diff --git a/.gn b/.gn
index 22e155c1..1da6987 100644
--- a/.gn
+++ b/.gn
@@ -71,7 +71,6 @@
   "//chrome/browser/updates/announcement_notification:*",  # 15 errors
   "//chrome/browser/updates/internal:*",  # 8 errors
   "//chrome/browser/updates:*",  # 21 errors
-  "//chrome/browser:*",  # 780 errors
   "//chrome/child:*",  # 3 errors
   "//chrome/install_static:*",  # 4 errors
   "//chrome/notification_helper:*",  # 4 errors
@@ -250,7 +249,6 @@
   "//third_party/blink/renderer/core/workers:*",  # 289 errors
   "//third_party/blink/renderer/core/xmlhttprequest:*",  # 49 errors
   "//third_party/blink/renderer/core:*",  # 823 errors
-  "//third_party/blink/renderer/modules/font_access:*",  # 3 errors
   "//third_party/blink/renderer/modules/peerconnection:*",  # 43 errors
 
   "//third_party/breakpad:*",  # 34 errors
diff --git a/DEPS b/DEPS
index 5db0d0cc..b8fb5181 100644
--- a/DEPS
+++ b/DEPS
@@ -195,7 +195,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'a195d101f96c3d0d2c3d67b1a84d1286dce52719',
+  'skia_revision': '2610e8261e9e8be23eeb8054f8aa4a148234d214',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -207,7 +207,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '377e748714bfcb827a2a61a3b8ccf8ea8fab2156',
+  'angle_revision': '4d3a0f602852ff8277a716fd99101fefbf6d544b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -215,7 +215,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '40d3f47d189c1ac36b14f3fe6d6ba9ce4c0a7d7e',
+  'pdfium_revision': '5b4eaf71f78bdb2e1c8b88a84eba68510dd871ac',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -242,7 +242,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling NaCl
   # and whatever else without interference from each other.
-  'nacl_revision': '3008f9e6de122325d8f9dbf02f7cdd51fa1ec306',
+  'nacl_revision': '69a0d6e8affc94187af10e0673592d1b238c6eb0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
@@ -258,7 +258,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '3f01e83f96b0c3cc3cd4f31bc4c097c55d13bdd1',
+  'catapult_revision': '511a82c95fc7a633cff6a3330ed82b13cdd77d41',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -266,7 +266,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': 'a1f84f4a730074d194fbebcf94251fe68b9395ec',
+  'devtools_frontend_revision': '97fd79e5180bff3ec46a93ae6f63f20b6d7b8248',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -545,7 +545,7 @@
   },
 
   'src/ios/third_party/material_components_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'aba747b4808a48603bae4798569aff2eb7d2404d',
+      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'eb829842242a3f8f657992381100407d205892fd',
       'condition': 'checkout_ios',
   },
 
@@ -896,7 +896,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '52fdd1ffcefb16435eee27023af95e5e844cfc16',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '8e500174f4bb7f19f1ef4630d7887146e9e14100',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1149,7 +1149,7 @@
   },
 
   'src/third_party/libvpx/source/libvpx':
-    Var('chromium_git') + '/webm/libvpx.git' + '@' +  '53747dfe65eaf670a7192f55117f3bf1e0280743',
+    Var('chromium_git') + '/webm/libvpx.git' + '@' +  '97356acb50e212fcfb7c91715718ec70953f780c',
 
   'src/third_party/libwebm/source':
     Var('chromium_git') + '/webm/libwebm.git' + '@' + '51ca718c3adf0ddedacd7df25fe45f67dc5a9ce1',
@@ -1249,7 +1249,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'b189aac831322c28c0d3d3f41cab7c0214dd8c9b',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'd48ef5f7ddc8d145e228a47f7297b6037a784d29',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1327,7 +1327,7 @@
       'packages': [
           {
               'package': 'fuchsia/third_party/aemu/linux-amd64',
-              'version': '8YjsZy1I3YIJIOUKErXW54SHjiEX62hd9SqYjmop19oC'
+              'version': 'IzByO_5k6SuUgXEKi9WBGlM_GOmnAPTcCsvgllPowHoC'
           },
       ],
       'condition': 'host_os == "linux" and checkout_fuchsia',
@@ -1471,7 +1471,7 @@
   },
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'ae073e44336fbc0f9e9f7af318447d5feebc660f',
+    Var('webrtc_git') + '/src.git' + '@' + 'b10d4a612b873d59c7ea79982c033dacfb68cd76',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1509,7 +1509,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/linux-amd64',
-          'version': 'f-DTUcX4U7OFc5zCWXjvrSxtdJvuhXh4sUcNTJ25tGgC',
+          'version': 'KS0vcfHGwNGOUpfZjf2qjxLk_Ab7qh3iQyA7Td9WfEwC',
         },
       ],
       'dep_type': 'cipd',
@@ -1519,7 +1519,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/windows-amd64',
-          'version': '0T7A2zKUcd9aOk8Bm8_upn7Ee3pt5MEMFPxJlsU5MSgC',
+          'version': 'kIrRtMsJjy2dsd5vfikJtfXXZk1zkN3lql3PtSU1kG4C',
         },
       ],
       'dep_type': 'cipd',
@@ -1529,7 +1529,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/mac-amd64',
-          'version': 'ZEjCOhpgQq2QyPhqYBzxLzorH4ZmulpCNyb_UYP34iYC',
+          'version': 'uCrto8KqeHOJLjyX8eolAvFrtFughNiEMrlow-3BHisC',
         },
       ],
       'dep_type': 'cipd',
@@ -1543,7 +1543,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@7e0dbae74fcd57f3c9ca145c2b0f979089cfc184',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@deacaf80c273290327930547aef17bfc20cb47e4',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/aw_print_manager.cc b/android_webview/browser/aw_print_manager.cc
index 10be4f90..dda4277 100644
--- a/android_webview/browser/aw_print_manager.cc
+++ b/android_webview/browser/aw_print_manager.cc
@@ -18,14 +18,15 @@
 #include "components/printing/common/print.mojom.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
+#include "printing/print_job_constants.h"
 
 namespace android_webview {
 
 namespace {
 
-int SaveDataToFd(int fd,
-                 int page_count,
-                 scoped_refptr<base::RefCountedSharedMemoryMapping> data) {
+uint32_t SaveDataToFd(int fd,
+                      uint32_t page_count,
+                      scoped_refptr<base::RefCountedSharedMemoryMapping> data) {
   bool result = fd > base::kInvalidFd &&
                 base::IsValueInRangeForNumericType<int>(data->size());
   if (result) {
@@ -128,6 +129,12 @@
     return;
   }
 
+  if (number_pages_ > printing::kMaxPageCount) {
+    web_contents()->Stop();
+    PdfWritingDone(0);
+    return;
+  }
+
   DCHECK(pdf_writing_done_callback_);
   base::PostTaskAndReplyWithResult(
       base::ThreadPool::CreateTaskRunner(
@@ -143,9 +150,10 @@
 void AwPrintManager::OnDidPrintDocumentWritingDone(
     const PdfWritingDoneCallback& callback,
     std::unique_ptr<DelayedFrameDispatchHelper> helper,
-    int page_count) {
+    uint32_t page_count) {
+  DCHECK_LE(page_count, printing::kMaxPageCount);
   if (callback)
-    callback.Run(page_count);
+    callback.Run(base::checked_cast<int>(page_count));
   helper->SendCompleted();
 }
 
diff --git a/android_webview/browser/aw_print_manager.h b/android_webview/browser/aw_print_manager.h
index 1da74ec2..499bc52 100644
--- a/android_webview/browser/aw_print_manager.h
+++ b/android_webview/browser/aw_print_manager.h
@@ -57,7 +57,7 @@
   static void OnDidPrintDocumentWritingDone(
       const PdfWritingDoneCallback& callback,
       std::unique_ptr<DelayedFrameDispatchHelper> helper,
-      int page_count);
+      uint32_t page_count);
 
   const std::unique_ptr<printing::PrintSettings> settings_;
 
diff --git a/android_webview/renderer/aw_content_settings_client.cc b/android_webview/renderer/aw_content_settings_client.cc
index 125b3a31..77b8f2ce 100644
--- a/android_webview/renderer/aw_content_settings_client.cc
+++ b/android_webview/renderer/aw_content_settings_client.cc
@@ -58,7 +58,7 @@
 }
 
 bool AwContentSettingsClient::ShouldAutoupgradeMixedContent() {
-  return render_frame()->GetWebkitPreferences().allow_mixed_content_upgrades;
+  return render_frame()->GetBlinkPreferences().allow_mixed_content_upgrades;
 }
 
 void AwContentSettingsClient::OnDestruct() {
diff --git a/ash/capture_mode/capture_mode_session.cc b/ash/capture_mode/capture_mode_session.cc
index 8e5dd48..a679592 100644
--- a/ash/capture_mode/capture_mode_session.cc
+++ b/ash/capture_mode/capture_mode_session.cc
@@ -4,16 +4,16 @@
 
 #include "ash/capture_mode/capture_mode_session.h"
 
-#include <memory>
-
 #include "ash/capture_mode/capture_mode_bar_view.h"
 #include "ash/capture_mode/capture_mode_controller.h"
 #include "ash/display/mouse_cursor_event_filter.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/style/ash_color_provider.h"
 #include "ash/wm/mru_window_tracker.h"
 #include "base/memory/ptr_util.h"
+#include "cc/paint/paint_flags.h"
 #include "ui/aura/window.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/layer_type.h"
@@ -21,8 +21,13 @@
 #include "ui/events/types/event_type.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/color_palette.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/paint_vector_icon.h"
 #include "ui/gfx/scoped_canvas.h"
+#include "ui/views/controls/button/label_button.h"
+#include "ui/views/controls/label.h"
 
 namespace ash {
 
@@ -30,6 +35,17 @@
 
 constexpr int kBorderStrokePx = 2;
 
+// The visual radius of the drag affordance circles which are shown while
+// resizing a drag region.
+constexpr int kAffordanceCircleRadiusDp = 5;
+
+// The hit radius of the drag affordance circles touch events.
+constexpr int kAffordanceCircleTouchHitRadiusDp = 16;
+
+constexpr int kSizeLabelYDistanceFromRegionDp = 8;
+
+constexpr SkColor kRegionBorderColor = SK_ColorWHITE;
+
 // Blue300 at 30%.
 constexpr SkColor kCaptureRegionColor = SkColorSetA(gfx::kGoogleBlue300, 77);
 
@@ -49,6 +65,66 @@
   return root->GetChildById(kShellWindowId_OverlayContainer);
 }
 
+// Retrieves the point on the |rect| associated with |position|.
+gfx::Point GetLocationForPosition(const gfx::Rect& rect,
+                                  FineTunePosition position) {
+  switch (position) {
+    case FineTunePosition::kTopLeft:
+      return rect.origin();
+    case FineTunePosition::kTopCenter:
+      return rect.top_center();
+    case FineTunePosition::kTopRight:
+      return rect.top_right();
+    case FineTunePosition::kRightCenter:
+      return rect.right_center();
+    case FineTunePosition::kBottomRight:
+      return rect.bottom_right();
+    case FineTunePosition::kBottomCenter:
+      return rect.bottom_center();
+    case FineTunePosition::kBottomLeft:
+      return rect.bottom_left();
+    case FineTunePosition::kLeftCenter:
+      return rect.left_center();
+    default:
+      break;
+  }
+
+  NOTREACHED();
+  return gfx::Point();
+}
+
+// Returns the smallest rect that contains all of |points|.
+gfx::Rect GetRectEnclosingPoints(const std::vector<gfx::Point>& points) {
+  DCHECK_GE(points.size(), 2u);
+
+  int x = INT_MAX;
+  int y = INT_MAX;
+  int right = INT_MIN;
+  int bottom = INT_MIN;
+  for (const gfx::Point& point : points) {
+    x = std::min(point.x(), x);
+    y = std::min(point.y(), y);
+    right = std::max(point.x(), right);
+    bottom = std::max(point.y(), bottom);
+  }
+  return gfx::Rect(x, y, right - x, bottom - y);
+}
+
+// Returns the widget init params needed to create a widget associated with a
+// capture session.
+views::Widget::InitParams CreateWidgetParams(aura::Window* parent,
+                                             const gfx::Rect& bounds,
+                                             const std::string& name) {
+  views::Widget::InitParams params(
+      views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
+  params.parent = parent;
+  params.bounds = bounds;
+  params.name = name;
+  return params;
+}
+
 }  // namespace
 
 CaptureModeSession::CaptureModeSession(CaptureModeController* controller,
@@ -67,15 +143,8 @@
   parent->layer()->Add(layer());
   layer()->SetBounds(parent->bounds());
 
-  views::Widget::InitParams params(
-      views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
-  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-  params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
-  params.parent = parent;
-  params.bounds = CaptureModeBarView::GetBounds(root);
-  params.name = "CaptureModeBarWidget";
-
-  capture_mode_bar_widget_.Init(std::move(params));
+  capture_mode_bar_widget_.Init(CreateWidgetParams(
+      parent, CaptureModeBarView::GetBounds(root), "CaptureModeBarWidget"));
   capture_mode_bar_widget_.SetContentsView(
       base::WrapUnique(capture_mode_bar_view_));
   capture_mode_bar_widget_.Show();
@@ -100,6 +169,7 @@
 void CaptureModeSession::OnCaptureSourceChanged(CaptureModeSource new_source) {
   capture_mode_bar_view_->OnCaptureSourceChanged(new_source);
   SetMouseWarpEnabled(new_source != CaptureModeSource::kRegion);
+  UpdateCaptureRegionWidgets();
   layer()->SchedulePaint(layer()->bounds());
 }
 
@@ -136,11 +206,22 @@
 }
 
 void CaptureModeSession::OnMouseEvent(ui::MouseEvent* event) {
-  // TODO(afakhry): Fill in here.
+  OnLocatedEvent(event, /*is_touch=*/false);
 }
 
 void CaptureModeSession::OnTouchEvent(ui::TouchEvent* event) {
-  // TODO(afakhry): Fill in here.
+  OnLocatedEvent(event, /*is_touch=*/true);
+}
+
+void CaptureModeSession::ButtonPressed(views::Button* sender,
+                                       const ui::Event& event) {
+  if (!capture_button_widget_)
+    return;
+
+  DCHECK_EQ(static_cast<views::LabelButton*>(
+                capture_button_widget_->GetContentsView()),
+            sender);
+  controller_->PerformCapture();  // |this| is destroyed here.
 }
 
 gfx::Rect CaptureModeSession::GetSelectedWindowBounds() const {
@@ -150,15 +231,12 @@
 
 void CaptureModeSession::RefreshStackingOrder(aura::Window* parent_container) {
   DCHECK(parent_container);
-  auto* widget_layer = capture_mode_bar_widget_.GetNativeWindow()->layer();
+  auto* capture_mode_bar_layer = capture_mode_bar_widget_.GetLayer();
   auto* overlay_layer = layer();
   auto* parent_container_layer = parent_container->layer();
 
-  DCHECK_EQ(parent_container_layer, overlay_layer->parent());
-  DCHECK_EQ(parent_container_layer, widget_layer->parent());
-
   parent_container_layer->StackAtTop(overlay_layer);
-  parent_container_layer->StackAtTop(widget_layer);
+  parent_container_layer->StackAtTop(capture_mode_bar_layer);
 }
 
 void CaptureModeSession::PaintCaptureRegion(gfx::Canvas* canvas) {
@@ -187,22 +265,320 @@
   const float dsf = canvas->UndoDeviceScaleFactor();
   region = gfx::ScaleToEnclosingRect(region, dsf);
 
-  canvas->FillRect(region, SK_ColorBLACK, SkBlendMode::kClear);
-  canvas->FillRect(region, kCaptureRegionColor);
+  if (!adjustable_region) {
+    canvas->FillRect(region, SK_ColorTRANSPARENT, SkBlendMode::kClear);
+    canvas->FillRect(region, kCaptureRegionColor);
+    return;
+  }
 
-  if (!adjustable_region)
+  region.Inset(-kBorderStrokePx, -kBorderStrokePx);
+  canvas->FillRect(region, SK_ColorTRANSPARENT, SkBlendMode::kClear);
+  canvas->DrawRect(gfx::RectF(region), kRegionBorderColor);
+
+  if (is_select_phase_)
     return;
 
-  // TODO(afakhry): For adjustable regions, we may change the colors. Also,
-  // paint the drag points at the corners.
-  region.Inset(-kBorderStrokePx, -kBorderStrokePx);
+  // Do not show affordance circles when repositioning the whole region.
+  if (fine_tune_position_ == FineTunePosition::kCenter)
+    return;
+
+  // Draw the drag affordance circles.
+  // TODO(sammiequon): Draw a drop shadow for the affordance circles and the
+  // border.
   cc::PaintFlags flags;
-  flags.setAntiAlias(true);
-  flags.setStyle(cc::PaintFlags::kStroke_Style);
-  // TODO(afakhry): Update to match the specs.
-  flags.setColor(gfx::kGoogleBlue200);
-  flags.setStrokeWidth(SkIntToScalar(kBorderStrokePx));
-  canvas->DrawRect(region, flags);
+  flags.setColor(kRegionBorderColor);
+  flags.setStyle(cc::PaintFlags::kFill_Style);
+  canvas->DrawCircle(region.origin(), kAffordanceCircleRadiusDp, flags);
+  canvas->DrawCircle(region.top_center(), kAffordanceCircleRadiusDp, flags);
+  canvas->DrawCircle(region.top_right(), kAffordanceCircleRadiusDp, flags);
+  canvas->DrawCircle(region.left_center(), kAffordanceCircleRadiusDp, flags);
+  canvas->DrawCircle(region.right_center(), kAffordanceCircleRadiusDp, flags);
+  canvas->DrawCircle(region.bottom_left(), kAffordanceCircleRadiusDp, flags);
+  canvas->DrawCircle(region.bottom_center(), kAffordanceCircleRadiusDp, flags);
+  canvas->DrawCircle(region.bottom_right(), kAffordanceCircleRadiusDp, flags);
+}
+
+void CaptureModeSession::OnLocatedEvent(ui::LocatedEvent* event,
+                                        bool is_touch) {
+  // No need to handle events if the current source is not region.
+  if (controller_->source() != CaptureModeSource::kRegion)
+    return;
+
+  gfx::Point location = event->location();
+  aura::Window* source = static_cast<aura::Window*>(event->target());
+  aura::Window::ConvertPointToTarget(source, current_root_, &location);
+
+  // Let the capture button handle any events within its bounds.
+  if (capture_button_widget_ &&
+      capture_button_widget_->GetNativeWindow()->bounds().Contains(location)) {
+    return;
+  }
+
+  // Allow events that are located on the capture mode bar to pass through so we
+  // can click the buttons.
+  if (!CaptureModeBarView::GetBounds(current_root_).Contains(location)) {
+    event->SetHandled();
+    event->StopPropagation();
+  }
+
+  switch (event->type()) {
+    case ui::ET_MOUSE_PRESSED:
+    case ui::ET_TOUCH_PRESSED:
+      OnLocatedEventPressed(location, is_touch);
+      break;
+    case ui::ET_MOUSE_DRAGGED:
+    case ui::ET_TOUCH_MOVED:
+      OnLocatedEventDragged(location);
+      break;
+    case ui::ET_MOUSE_RELEASED:
+    case ui::ET_TOUCH_RELEASED:
+      OnLocatedEventReleased(location);
+      break;
+    default:
+      break;
+  }
+}
+
+void CaptureModeSession::OnLocatedEventPressed(
+    const gfx::Point& location_in_root,
+    bool is_touch) {
+  initial_location_in_root_ = location_in_root;
+  previous_location_in_root_ = location_in_root;
+
+  if (is_select_phase_)
+    return;
+
+  // Calculate the position and anchor points of the current pressed event.
+  fine_tune_position_ = FineTunePosition::kNone;
+  // In the case of overlapping affordances, prioritize the bottomm right
+  // corner, then the rest of the corners, then the edges.
+  static const std::vector<FineTunePosition> drag_positions = {
+      FineTunePosition::kBottomRight,  FineTunePosition::kBottomLeft,
+      FineTunePosition::kTopLeft,      FineTunePosition::kTopRight,
+      FineTunePosition::kBottomCenter, FineTunePosition::kLeftCenter,
+      FineTunePosition::kTopCenter,    FineTunePosition::kRightCenter};
+
+  const int hit_radius =
+      is_touch ? kAffordanceCircleTouchHitRadiusDp : kAffordanceCircleRadiusDp;
+  const int hit_radius_squared = hit_radius * hit_radius;
+  for (FineTunePosition position : drag_positions) {
+    const gfx::Point position_location =
+        GetLocationForPosition(controller_->user_capture_region(), position);
+    // If |location_in_root| is within |hit_radius| of |position_location| for
+    // both x and y, then |position| is the current pressed down affordance.
+    if ((position_location - location_in_root).LengthSquared() <=
+        hit_radius_squared) {
+      fine_tune_position_ = position;
+      break;
+    }
+  }
+
+  if (fine_tune_position_ == FineTunePosition::kNone) {
+    // If the point is outside the capture region and not on the capture bar,
+    // restart to the select phase.
+    if (controller_->user_capture_region().Contains(location_in_root)) {
+      fine_tune_position_ = FineTunePosition::kCenter;
+    } else if (!CaptureModeBarView::GetBounds(current_root_)
+                    .Contains(location_in_root)) {
+      is_select_phase_ = true;
+      UpdateCaptureRegion(gfx::Rect());
+    }
+    return;
+  }
+
+  anchor_points_ = GetAnchorPointsForPosition(fine_tune_position_);
+}
+
+void CaptureModeSession::OnLocatedEventDragged(
+    const gfx::Point& location_in_root) {
+  const gfx::Point previous_location_in_root = previous_location_in_root_;
+  previous_location_in_root_ = location_in_root;
+
+  // For the select phase, the select region is the rectangle formed by the
+  // press location and the current locatiion.
+  if (is_select_phase_) {
+    UpdateCaptureRegion(
+        GetRectEnclosingPoints({initial_location_in_root_, location_in_root}));
+    return;
+  }
+
+  if (fine_tune_position_ == FineTunePosition::kNone)
+    return;
+
+  // For a reposition, offset the old select region by the difference between
+  // the current location and the previous location, but do not let the select
+  // region go offscreen.
+  if (fine_tune_position_ == FineTunePosition::kCenter) {
+    gfx::Rect new_capture_region = controller_->user_capture_region();
+    new_capture_region.Offset(location_in_root - previous_location_in_root);
+    new_capture_region.AdjustToFit(current_root_->bounds());
+    UpdateCaptureRegion(new_capture_region);
+    return;
+  }
+
+  // The new region is defined by the rectangle which encloses the anchor
+  // point(s) and |location_in_root|.
+  std::vector<gfx::Point> points = anchor_points_;
+  DCHECK(!points.empty());
+  points.push_back(location_in_root);
+  UpdateCaptureRegion(GetRectEnclosingPoints(points));
+}
+
+void CaptureModeSession::OnLocatedEventReleased(
+    const gfx::Point& location_in_root) {
+  fine_tune_position_ = FineTunePosition::kNone;
+  anchor_points_.clear();
+
+  // Do a repaint to show the affordance circles. See UpdateCaptureRegion to see
+  // how damage is calculated.
+  gfx::Rect damage_region = controller_->user_capture_region();
+  damage_region.Inset(
+      gfx::Insets(-kAffordanceCircleRadiusDp - kBorderStrokePx));
+  layer()->SchedulePaint(damage_region);
+
+  if (!is_select_phase_)
+    return;
+
+  // After first release event, we advance to the next phase.
+  is_select_phase_ = false;
+  UpdateCaptureRegionWidgets();
+}
+
+void CaptureModeSession::UpdateCaptureRegion(
+    const gfx::Rect& new_capture_region) {
+  const gfx::Rect old_capture_region = controller_->user_capture_region();
+  if (old_capture_region == new_capture_region)
+    return;
+
+  // Calculate the region that has been damaged and repaint the layer. Add some
+  // extra padding to make sure the border and affordance circles are also
+  // repainted.
+  gfx::Rect damage_region = old_capture_region;
+  damage_region.Union(new_capture_region);
+  damage_region.Inset(
+      gfx::Insets(-kAffordanceCircleRadiusDp - kBorderStrokePx));
+  layer()->SchedulePaint(damage_region);
+
+  controller_->set_user_capture_region(new_capture_region);
+  UpdateCaptureRegionWidgets();
+}
+
+void CaptureModeSession::UpdateCaptureRegionWidgets() {
+  // TODO(sammiequon): The dimensons label is always shown and the capture
+  // button label is always shown in the fine tune stage. Update this to match
+  // the specs.
+  const bool show = controller_->source() == CaptureModeSource::kRegion;
+  if (!show) {
+    dimensions_label_widget_.reset();
+    capture_button_widget_.reset();
+    return;
+  }
+
+  // TODO(sammiequon): Add styling to the two widget content views. Also, the
+  // widgets should be repositioned if the region is too small or too close to
+  // the edge.
+  const gfx::Rect capture_region = controller_->user_capture_region();
+  if (!dimensions_label_widget_) {
+    auto* parent = GetParentContainer(current_root_);
+    dimensions_label_widget_ = std::make_unique<views::Widget>();
+    dimensions_label_widget_->Init(
+        CreateWidgetParams(parent, gfx::Rect(), "CaptureModeSizeLabel"));
+    dimensions_label_widget_->SetContentsView(std::make_unique<views::Label>());
+    dimensions_label_widget_->Show();
+    parent->StackChildBelow(dimensions_label_widget_->GetNativeWindow(),
+                            capture_mode_bar_widget_.GetNativeWindow());
+  }
+
+  // Update the location of the size label. It is in the center of the region
+  // horizontally and slightly below the region vertically.
+  views::Label* size_label =
+      static_cast<views::Label*>(dimensions_label_widget_->GetContentsView());
+  size_label->SetText(base::UTF8ToUTF16(base::StringPrintf(
+      "%d x %d", capture_region.width(), capture_region.height())));
+  gfx::Rect dimensions_label_widget_bounds(size_label->GetPreferredSize());
+  dimensions_label_widget_bounds.set_x(capture_region.CenterPoint().x() -
+                                       dimensions_label_widget_bounds.width() /
+                                           2);
+  dimensions_label_widget_bounds.set_y(capture_region.bottom() +
+                                       kSizeLabelYDistanceFromRegionDp);
+  dimensions_label_widget_->SetBounds(dimensions_label_widget_bounds);
+
+  if (!capture_button_widget_ && !is_select_phase_) {
+    auto* parent = GetParentContainer(current_root_);
+    capture_button_widget_ = std::make_unique<views::Widget>();
+    capture_button_widget_->Init(
+        CreateWidgetParams(parent, gfx::Rect(), "CaptureModeButton"));
+    // TODO(sammiequon): Add the localized label.
+    auto label_button =
+        std::make_unique<views::LabelButton>(this, base::string16());
+    label_button->SetImage(
+        views::Button::STATE_NORMAL,
+        gfx::CreateVectorIcon(controller_->type() == CaptureModeType::kImage
+                                  ? kCaptureModeImageIcon
+                                  : kCaptureModeVideoIcon,
+                              SK_ColorBLACK));
+    capture_button_widget_->SetContentsView(std::move(label_button));
+    capture_button_widget_->Show();
+    parent->StackChildBelow(capture_button_widget_->GetNativeWindow(),
+                            capture_mode_bar_widget_.GetNativeWindow());
+  }
+
+  if (!capture_button_widget_)
+    return;
+
+  // Update the location of the capture button.
+  views::LabelButton* capture_button = static_cast<views::LabelButton*>(
+      capture_button_widget_->GetContentsView());
+  gfx::Rect capture_button_widget_bounds = capture_region;
+  capture_button_widget_bounds.ClampToCenteredSize(
+      capture_button->GetPreferredSize());
+  capture_button_widget_->SetBounds(capture_button_widget_bounds);
+}
+
+std::vector<gfx::Point> CaptureModeSession::GetAnchorPointsForPosition(
+    FineTunePosition position) {
+  std::vector<gfx::Point> anchor_points;
+  // For a vertex, the anchor point is the opposite vertex on the rectangle
+  // (ex. bottom left vertex -> top right vertex anchor point). For an edge, the
+  // anchor points are the two vertices of the opposite edge (ex. bottom edge ->
+  // top left and top right anchor points).
+  const gfx::Rect rect = controller_->user_capture_region();
+  switch (position) {
+    case FineTunePosition::kNone:
+    case FineTunePosition::kCenter:
+      break;
+    case FineTunePosition::kTopLeft:
+      anchor_points.push_back(rect.bottom_right());
+      break;
+    case FineTunePosition::kTopCenter:
+      anchor_points.push_back(rect.bottom_left());
+      anchor_points.push_back(rect.bottom_right());
+      break;
+    case FineTunePosition::kTopRight:
+      anchor_points.push_back(rect.bottom_left());
+      break;
+    case FineTunePosition::kLeftCenter:
+      anchor_points.push_back(rect.top_right());
+      anchor_points.push_back(rect.bottom_right());
+      break;
+    case FineTunePosition::kRightCenter:
+      anchor_points.push_back(rect.origin());
+      anchor_points.push_back(rect.bottom_left());
+      break;
+    case FineTunePosition::kBottomLeft:
+      anchor_points.push_back(rect.top_right());
+      break;
+    case FineTunePosition::kBottomCenter:
+      anchor_points.push_back(rect.origin());
+      anchor_points.push_back(rect.top_right());
+      break;
+    case FineTunePosition::kBottomRight:
+      anchor_points.push_back(rect.origin());
+      break;
+  }
+  DCHECK(!anchor_points.empty());
+  DCHECK_LE(anchor_points.size(), 2u);
+  return anchor_points;
 }
 
 }  // namespace ash
diff --git a/ash/capture_mode/capture_mode_session.h b/ash/capture_mode/capture_mode_session.h
index c015de8..e31f8b2 100644
--- a/ash/capture_mode/capture_mode_session.h
+++ b/ash/capture_mode/capture_mode_session.h
@@ -5,11 +5,15 @@
 #ifndef ASH_CAPTURE_MODE_CAPTURE_MODE_SESSION_H_
 #define ASH_CAPTURE_MODE_CAPTURE_MODE_SESSION_H_
 
+#include <memory>
+
 #include "ash/ash_export.h"
 #include "ash/capture_mode/capture_mode_types.h"
 #include "ui/compositor/layer_delegate.h"
 #include "ui/compositor/layer_owner.h"
+#include "ui/events/event.h"
 #include "ui/events/event_handler.h"
+#include "ui/views/controls/button/button.h"
 #include "ui/views/widget/widget.h"
 
 namespace gfx {
@@ -30,7 +34,8 @@
 // the one that will be.
 class ASH_EXPORT CaptureModeSession : public ui::LayerOwner,
                                       public ui::LayerDelegate,
-                                      public ui::EventHandler {
+                                      public ui::EventHandler,
+                                      public views::ButtonListener {
  public:
   // Creates the bar widget on the given |root| window.
   CaptureModeSession(CaptureModeController* controller, aura::Window* root);
@@ -61,6 +66,9 @@
   void OnMouseEvent(ui::MouseEvent* event) override;
   void OnTouchEvent(ui::TouchEvent* event) override;
 
+  // views::ButtonListener:
+  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
+
  private:
   // Gets the bounds of current window selected for |kWindow| capture source.
   gfx::Rect GetSelectedWindowBounds() const;
@@ -73,6 +81,34 @@
   // Paints the current capture region depending on the current capture source.
   void PaintCaptureRegion(gfx::Canvas* canvas);
 
+  // Helper to unify mouse/touch events. Forwards events to the three below
+  // functions and they are located on |capture_button_widget_|. Blocks events
+  // from reaching other handlers, unless the event is located on
+  // |capture_mode_bar_widget_|. |is_touch| signifies this is a touch event, and
+  // we will use larger hit targets for the drag affordances.
+  void OnLocatedEvent(ui::LocatedEvent* event, bool is_touch);
+
+  // Handles updating the select region UI.
+  void OnLocatedEventPressed(const gfx::Point& location_in_root, bool is_touch);
+  void OnLocatedEventDragged(const gfx::Point& location_in_root);
+  void OnLocatedEventReleased(const gfx::Point& location_in_root);
+
+  // Updates the capture region and the capture region widgets.
+  void UpdateCaptureRegion(const gfx::Rect& new_capture_region);
+
+  // Updates the widgets that are used to display text/icons while selecting a
+  // capture region. They are not visible during fullscreen or window capture,
+  // and some are only visible during certain phases of region capture. This
+  // will create or destroy the widgets as needed.
+  void UpdateCaptureRegionWidgets();
+
+  // Retrieves the anchor points on the current selected region associated with
+  // |position|. The anchor points are described as the points that do not
+  // change when resizing the capture region while dragging one of the drag
+  // affordances. There is one anchor point if |position| is a vertex, and two
+  // anchor points if |position| is an edge.
+  std::vector<gfx::Point> GetAnchorPointsForPosition(FineTunePosition position);
+
   CaptureModeController* const controller_;
 
   // The current root window on which the capture session is active, which may
@@ -84,6 +120,25 @@
   // The content view of the above widget and owned by its views hierarchy.
   CaptureModeBarView* capture_mode_bar_view_;
 
+  // Widgets which display text and icons during a region capture session.
+  std::unique_ptr<views::Widget> dimensions_label_widget_;
+  std::unique_ptr<views::Widget> capture_button_widget_;
+
+  // Stores the data needed to select a region during a region capture session.
+  // There are two phases for a region capture session. The select phase, where
+  // the user can quickly select a region and the fine tune phase, where the
+  // user can reposition and resize the region with a lot of accuracy.
+  bool is_select_phase_ = true;
+  // The location of the last press and drag events.
+  gfx::Point initial_location_in_root_;
+  gfx::Point previous_location_in_root_;
+  // The position of the last press event during the fine tune phase drag.
+  FineTunePosition fine_tune_position_;
+  // The points that do not change during a fine tune resize. This is empty
+  // when |fine_tune_position_| is kNone or kCenter, or if there is no drag
+  // underway.
+  std::vector<gfx::Point> anchor_points_;
+
   // Caches the old status of mouse warping before the session started to be
   // restored at the end.
   bool old_mouse_warp_status_;
diff --git a/ash/capture_mode/capture_mode_types.h b/ash/capture_mode/capture_mode_types.h
index 4248c64..db81acb 100644
--- a/ash/capture_mode/capture_mode_types.h
+++ b/ash/capture_mode/capture_mode_types.h
@@ -20,6 +20,28 @@
   kWindow,
 };
 
+// The position of the press event during the fine tune phase of a region
+// capture session. This will determine what subsequent drag events do to the
+// select region.
+enum class FineTunePosition {
+  // The initial press was outside region. Subsequent drags will do nothing.
+  kNone,
+  // The initial press was inside the select region. Subsequent drags will
+  // move the entire region.
+  kCenter,
+  // The initial press was on one of the drag affordance circles. Subsequent
+  // drags will resize the region. These are sorted clockwise starting at the
+  // top left.
+  kTopLeft,
+  kTopCenter,
+  kTopRight,
+  kRightCenter,
+  kBottomRight,
+  kBottomCenter,
+  kBottomLeft,
+  kLeftCenter,
+};
+
 }  // namespace ash
 
 #endif  // ASH_CAPTURE_MODE_CAPTURE_MODE_TYPES_H_
diff --git a/ash/system/holding_space/holding_space_item_context_menu.cc b/ash/system/holding_space/holding_space_item_context_menu.cc
index bd33ea9..204bdbf 100644
--- a/ash/system/holding_space/holding_space_item_context_menu.cc
+++ b/ash/system/holding_space/holding_space_item_context_menu.cc
@@ -4,12 +4,14 @@
 
 #include "ash/system/holding_space/holding_space_item_context_menu.h"
 
+#include "ash/public/cpp/holding_space/holding_space_client.h"
 #include "ash/public/cpp/holding_space/holding_space_constants.h"
 #include "ash/public/cpp/holding_space/holding_space_controller.h"
 #include "ash/public/cpp/holding_space/holding_space_model.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/holding_space/holding_space_item_view.h"
+#include "base/bind.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/views/controls/menu/menu_runner.h"
@@ -45,16 +47,18 @@
                                                  int event_flags) {
   switch (command_id) {
     case HoldingSpaceCommandId::kCopyToClipboard:
-      // TODO(crbug.com/1127240): Hookup API for copy to clipboard
+      HoldingSpaceController::Get()->client()->CopyToClipboard(
+          *item_, base::DoNothing());
       break;
     case HoldingSpaceCommandId::kPinItem:
-      // TODO(crbug.com/1127240): Hookup API for toggling pin
+      HoldingSpaceController::Get()->client()->PinItem(*item_);
       break;
     case HoldingSpaceCommandId::kShowInFolder:
-      // TODO(crbug.com/1127240): Hookup API for show in folder
+      HoldingSpaceController::Get()->client()->OpenItemInFolder(
+          *item_, base::DoNothing());
       break;
     case HoldingSpaceCommandId::kUnpinItem:
-      // TODO(crbug.com/1127240): Hookup API for toggling pin
+      HoldingSpaceController::Get()->client()->UnpinItem(*item_);
       break;
   }
 }
diff --git a/ash/wm/desks/desks_controller.cc b/ash/wm/desks/desks_controller.cc
index f37a8c90..0f5efc3d 100644
--- a/ash/wm/desks/desks_controller.cc
+++ b/ash/wm/desks/desks_controller.cc
@@ -163,13 +163,13 @@
 }
 
 const Desk* DesksController::GetTargetActiveDesk() const {
-  if (!animations_.empty())
-    return desks_[animations_.back()->ending_desk_index()].get();
+  if (animation_)
+    return desks_[animation_->ending_desk_index()].get();
   return active_desk();
 }
 
 void DesksController::Shutdown() {
-  animations_.clear();
+  animation_.reset();
 }
 
 void DesksController::AddObserver(Observer* observer) {
@@ -181,7 +181,7 @@
 }
 
 bool DesksController::AreDesksBeingModified() const {
-  return are_desks_being_modified_ || !animations_.empty();
+  return are_desks_being_modified_ || !!animation_;
 }
 
 bool DesksController::CanCreateDesks() const {
@@ -256,9 +256,9 @@
         current_desk_index + ((current_desk_index > 0) ? -1 : 1);
     DCHECK_GE(target_desk_index, 0);
     DCHECK_LT(target_desk_index, static_cast<int>(desks_.size()));
-    animations_.emplace_back(std::make_unique<DeskRemovalAnimation>(
-        this, current_desk_index, target_desk_index, source));
-    animations_.back()->Launch();
+    animation_ = std::make_unique<DeskRemovalAnimation>(
+        this, current_desk_index, target_desk_index, source);
+    animation_->Launch();
     return;
   }
 
@@ -267,7 +267,7 @@
 
 void DesksController::ActivateDesk(const Desk* desk, DesksSwitchSource source) {
   DCHECK(HasDesk(desk));
-  DCHECK(animations_.empty());
+  DCHECK(!animation_);
 
   OverviewController* overview_controller = Shell::Get()->overview_controller();
   const bool in_overview = overview_controller->InOverviewSession();
@@ -300,9 +300,9 @@
   }
 
   const int starting_desk_index = GetDeskIndex(active_desk());
-  animations_.emplace_back(std::make_unique<DeskActivationAnimation>(
-      this, starting_desk_index, target_desk_index, source));
-  animations_.back()->Launch();
+  animation_ = std::make_unique<DeskActivationAnimation>(
+      this, starting_desk_index, target_desk_index, source);
+  animation_->Launch();
 }
 
 bool DesksController::ActivateAdjacentDesk(bool going_left,
@@ -316,15 +316,9 @@
     return false;
 
   // Try replacing an ongoing desk animation of the same source.
-  if (is_enhanced_desk_animations_) {
-    for (const auto& animation : animations_) {
-      if (animation->Replace(going_left, source))
-        return true;
-    }
-    // If there is no current animation of the same source but there is an
-    // animation running, skip this animation.
-    if (!animations_.empty())
-      return false;
+  if (is_enhanced_desk_animations_ && animation_ &&
+      animation_->Replace(going_left, source)) {
+    return true;
   }
 
   const Desk* desk_to_activate = going_left ? GetPreviousDesk() : GetNextDesk();
@@ -349,18 +343,14 @@
 
 void DesksController::UpdateAnimationForGesture(float scroll_delta_x) {
   DCHECK(is_enhanced_desk_animations_);
-  for (const auto& animation : animations_) {
-    if (animation->Update(scroll_delta_x))
-      return;
-  }
+  if (animation_)
+    animation_->Update(scroll_delta_x);
 }
 
 void DesksController::EndAnimationForGesture() {
   DCHECK(is_enhanced_desk_animations_);
-  for (const auto& animation : animations_) {
-    if (animation->End())
-      return;
-  }
+  if (animation_)
+    animation_->End();
 }
 
 bool DesksController::MoveWindowFromActiveDeskTo(
@@ -503,7 +493,8 @@
 }
 
 void DesksController::OnAnimationFinished(DeskAnimationBase* animation) {
-  base::EraseIf(animations_, base::MatchesUniquePtr(animation));
+  DCHECK_EQ(animation_.get(), animation);
+  animation_.reset();
 }
 
 bool DesksController::HasDesk(const Desk* desk) const {
diff --git a/ash/wm/desks/desks_controller.h b/ash/wm/desks/desks_controller.h
index a95da23..ce437490f 100644
--- a/ash/wm/desks/desks_controller.h
+++ b/ash/wm/desks/desks_controller.h
@@ -230,9 +230,8 @@
   // mode as a result of desks modifications.
   bool are_desks_being_modified_ = false;
 
-  // List of on-going desks animations.
-  // TODO(sammiequon): Investigate if this needs to still be a list.
-  std::vector<std::unique_ptr<DeskAnimationBase>> animations_;
+  // Not null if there is an on-going desks animation.
+  std::unique_ptr<DeskAnimationBase> animation_;
 
   // A free list of desk container IDs to be used for newly-created desks. New
   // desks pops from this queue and removed desks's associated container IDs are
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 25bdb95..cc629fe 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -3638,6 +3638,8 @@
       "android/java/src/org/chromium/base/supplier/ObservableSupplier.java",
       "android/java/src/org/chromium/base/supplier/ObservableSupplierImpl.java",
       "android/java/src/org/chromium/base/supplier/OneShotCallback.java",
+      "android/java/src/org/chromium/base/supplier/OneshotSupplier.java",
+      "android/java/src/org/chromium/base/supplier/OneshotSupplierImpl.java",
       "android/java/src/org/chromium/base/supplier/Supplier.java",
       "android/java/src/org/chromium/base/task/AsyncTask.java",
       "android/java/src/org/chromium/base/task/BackgroundOnlyAsyncTask.java",
@@ -3882,6 +3884,7 @@
       "android/junit/src/org/chromium/base/process_launcher/ChildProcessConnectionTest.java",
       "android/junit/src/org/chromium/base/supplier/ObservableSupplierImplTest.java",
       "android/junit/src/org/chromium/base/supplier/OneShotCallbackTest.java",
+      "android/junit/src/org/chromium/base/supplier/OneshotSupplierImplTest.java",
       "android/junit/src/org/chromium/base/task/AsyncTaskThreadTest.java",
       "android/junit/src/org/chromium/base/task/TaskTraitsTest.java",
       "android/junit/src/org/chromium/base/util/GarbageCollectionTestUtilsUnitTest.java",
diff --git a/base/allocator/partition_allocator/partition_bucket.cc b/base/allocator/partition_allocator/partition_bucket.cc
index 903e0c0..c2ebd3c 100644
--- a/base/allocator/partition_allocator/partition_bucket.cc
+++ b/base/allocator/partition_allocator/partition_bucket.cc
@@ -577,7 +577,30 @@
     if (size > kMaxDirectMapped) {
       if (return_null)
         return nullptr;
+      // The lock is here to protect PA from:
+      // 1. Concurrent calls
+      // 2. Reentrant calls
+      //
+      // This is fine here however, as:
+      // 1. Concurrency: |PartitionRoot::OutOfMemory()| never returns, so the
+      //    lock will not be re-acquired, which would lead to acting on
+      //    inconsistent data that could have been modified in-between releasing
+      //    and acquiring it.
+      // 2. Reentrancy: This is why we release the lock. On some platforms,
+      //    terminating the process may free() memory, or even possibly try to
+      //    allocate some. Calling free() is fine, but will deadlock since
+      //    |PartitionRoot::lock_| is not recursive.
+      //
+      // Supporting reentrant calls properly is hard, and not a requirement for
+      // PA. However up to that point, we've only *read* data, not *written* to
+      // any state. Reentrant calls are then fine, especially as we don't
+      // continue on this path. The only downside is possibly endless recursion
+      // if the OOM handler allocates and fails to use UncheckedMalloc() or
+      // equivalent, but that's violating the contract of
+      // base::OnNoMemoryInternal().
+      ScopedUnlockGuard<thread_safe> unlock{root->lock_};
       PartitionExcessiveAllocationSize(size);
+      IMMEDIATE_CRASH();  // Not required, kept as documentation.
     }
     new_page = PartitionDirectMap(root, flags, size);
     if (new_page)
@@ -636,7 +659,10 @@
               PartitionPage<thread_safe>::get_sentinel_page());
     if (return_null)
       return nullptr;
+    // See comment above.
+    ScopedUnlockGuard<thread_safe> unlock{root->lock_};
     root->OutOfMemory(size);
+    IMMEDIATE_CRASH();  // Not required, kept as documentation.
   }
 
   PA_DCHECK(new_page_bucket != get_sentinel_bucket());
diff --git a/base/allocator/partition_allocator/partition_lock.h b/base/allocator/partition_allocator/partition_lock.h
index 9167697..b2f8484 100644
--- a/base/allocator/partition_allocator/partition_lock.h
+++ b/base/allocator/partition_allocator/partition_lock.h
@@ -39,6 +39,20 @@
   MaybeSpinLock<thread_safe>& lock_;
 };
 
+template <bool thread_safe>
+class SCOPED_LOCKABLE ScopedUnlockGuard {
+ public:
+  explicit ScopedUnlockGuard(MaybeSpinLock<thread_safe>& lock)
+      UNLOCK_FUNCTION(lock)
+      : lock_(lock) {
+    lock_.Unlock();
+  }
+  ~ScopedUnlockGuard() EXCLUSIVE_LOCK_FUNCTION() { lock_.Lock(); }
+
+ private:
+  MaybeSpinLock<thread_safe>& lock_;
+};
+
 #if !DCHECK_IS_ON()
 // Spinlock. Do not use, to be removed. crbug.com/1061437.
 class BASE_EXPORT SpinLock {
diff --git a/base/android/java/src/org/chromium/base/supplier/OneshotSupplier.java b/base/android/java/src/org/chromium/base/supplier/OneshotSupplier.java
new file mode 100644
index 0000000..6136cdf
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/supplier/OneshotSupplier.java
@@ -0,0 +1,47 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.supplier;
+
+import org.chromium.base.Callback;
+
+/**
+ * OneshotSupplier wraps an asynchronously provided, non-null object {@code T}, notifying
+ * observers a single time when the dependency becomes available. Note that null is the un-set
+ * value; a fulfilled supplier will never have a null underlying value.
+ *
+ * <p>This allows classes dependent on {@code T} to be provided with a
+ * OneshotSupplier during construction and register a {@code Callback<T>} to be notified when the
+ * needed dependency is available, but without the need to un-register that Callback upon
+ * destruction. Contrast to {@link ObservableSupplier}, which requires un-registration to prevent
+ * post-destruction callback invocation because the object can change an arbitrary number of times.
+ *
+ *
+ * <p>This class must only be accessed from a single thread. Unless a particular thread designation
+ * is given by the owner of the OneshotSupplier, clients should assume it must only be accessed on
+ * the UI thread.
+ *
+ * <p>If you want to create a supplier, see an implementation in {@link OneshotSupplierImpl}.
+ *
+ * <p>For classes using a OneshotSupplier to receive a dependency:
+ * <ul>
+ *    <li>To be notified when the object is available, call {@link #onAvailable(Callback)}.
+ *    <li>If the object is already available, the Callback will be posted immediately on the handler
+ *    for the thread the supplier was created on.
+ *    <li>The Callback will be called at most
+ *    once. It's still recommended to use {@link org.chromium.base.CallbackController} for safety.
+ * </ul>
+ *
+ * @param <T> The type of the wrapped object.
+ */
+public interface OneshotSupplier<T> extends Supplier<T> {
+    /**
+     * Add a callback that's called when the object owned by this supplier is available.
+     * If the object is already available, the callback will be called at the end of the
+     * current message loop.
+     *
+     * @param callback The callback to be called.
+     */
+    void onAvailable(Callback<T> callback);
+}
diff --git a/base/android/java/src/org/chromium/base/supplier/OneshotSupplierImpl.java b/base/android/java/src/org/chromium/base/supplier/OneshotSupplierImpl.java
new file mode 100644
index 0000000..ed233d1
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/supplier/OneshotSupplierImpl.java
@@ -0,0 +1,57 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.supplier;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import org.chromium.base.Callback;
+import org.chromium.base.Promise;
+import org.chromium.base.ThreadUtils;
+
+/**
+ * Concrete implementation of {@link OneshotSupplier} to be used by classes owning a
+ * OneshotSupplier and providing it as a dependency to others.
+ *
+ * <p>Instances of this class must only be accessed from the thread they were created on.
+ *
+ * To use:
+ * <ol>
+ *    <li>Create a new {@code OneshotSupplierImpl<T>} to pass as a dependency.
+ *    <li>Call {@link #set(Object)} when the object becomes available. {@link #set(Object)} may only
+ * be called once.
+ * </ol>
+ *
+ * @param <T> The type of the wrapped object.
+ */
+public class OneshotSupplierImpl<T> implements OneshotSupplier<T> {
+    private final Promise<T> mPromise = new Promise<>();
+    private final ThreadUtils.ThreadChecker mThreadChecker = new ThreadUtils.ThreadChecker();
+
+    @Override
+    public void onAvailable(Callback<T> callback) {
+        mThreadChecker.assertOnValidThread();
+        mPromise.then(callback);
+    }
+
+    @Override
+    public @Nullable T get() {
+        mThreadChecker.assertOnValidThread();
+        return mPromise.isFulfilled() ? mPromise.getResult() : null;
+    }
+
+    /**
+     * Set the object supplied by this supplier. This will notify registered callbacks that the
+     * dependency is available. If set() has already been called, this method will assert.
+     *
+     * @param object The object to supply.
+     */
+    public void set(@NonNull T object) {
+        mThreadChecker.assertOnValidThread();
+        assert !mPromise.isFulfilled();
+        assert object != null;
+        mPromise.fulfill(object);
+    }
+}
diff --git a/base/android/junit/src/org/chromium/base/supplier/OneshotSupplierImplTest.java b/base/android/junit/src/org/chromium/base/supplier/OneshotSupplierImplTest.java
new file mode 100644
index 0000000..748ce01
--- /dev/null
+++ b/base/android/junit/src/org/chromium/base/supplier/OneshotSupplierImplTest.java
@@ -0,0 +1,77 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.supplier;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowProcess;
+
+import org.chromium.base.Callback;
+import org.chromium.base.test.BaseRobolectricTestRunner;
+
+/**
+ * Unit tests for {@link OneshotSupplierImpl}.
+ */
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(shadows = {ShadowProcess.class})
+public class OneshotSupplierImplTest {
+    private OneshotSupplierImpl<String> mSupplier = new OneshotSupplierImpl<>();
+
+    @Spy
+    private Callback<String> mCallback1;
+    @Spy
+    private Callback<String> mCallback2;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testSet() {
+        mSupplier.onAvailable(mCallback1);
+        mSupplier.onAvailable(mCallback2);
+        mSupplier.set("answer");
+
+        verify(mCallback1).onResult("answer");
+        verify(mCallback2).onResult("answer");
+    }
+
+    @Test
+    public void testSetBeforeAddObserver() {
+        mSupplier.set("answer");
+
+        mSupplier.onAvailable(mCallback1);
+        mSupplier.onAvailable(mCallback2);
+
+        verify(mCallback1).onResult("answer");
+        verify(mCallback2).onResult("answer");
+    }
+
+    @Test
+    public void testInterleaved() {
+        mSupplier.onAvailable(mCallback1);
+        mSupplier.set("answer");
+        mSupplier.onAvailable(mCallback2);
+
+        verify(mCallback1).onResult("answer");
+        verify(mCallback2).onResult("answer");
+    }
+
+    @Test
+    public void testGet() {
+        assertNull(mSupplier.get());
+        mSupplier.set("answer");
+        assertEquals("answer", mSupplier.get());
+    }
+}
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index ef97e531..87bdf6c 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-0.20200915.2.1
+0.20200916.1.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index ef97e531..87bdf6c 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-0.20200915.2.1
+0.20200916.1.1
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index 781ad45..b41fb25a 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -6219,6 +6219,22 @@
   CheckCanUseLCDText(LCDTextDisallowedReason::kNone, "no filter");
 }
 
+TEST_P(LCDTextTest, FilterAnimation) {
+  FilterOperations blur_filter;
+  blur_filter.Append(FilterOperation::CreateBlurFilter(4.0f));
+  SetFilter(layer_, blur_filter);
+  CheckCanUseLCDText(LCDTextDisallowedReason::kPixelOrColorEffect, "filter");
+
+  GetEffectNode(layer_)->has_potential_filter_animation = true;
+  SetFilter(layer_, FilterOperations());
+  CheckCanUseLCDText(LCDTextDisallowedReason::kPixelOrColorEffect,
+                     "filter animation");
+
+  GetEffectNode(layer_)->has_potential_filter_animation = false;
+  SetFilter(layer_, FilterOperations());
+  CheckCanUseLCDText(LCDTextDisallowedReason::kNone, "no filter");
+}
+
 TEST_P(LCDTextTest, BackdropFilter) {
   FilterOperations backdrop_filter;
   backdrop_filter.Append(FilterOperation::CreateBlurFilter(4.0f));
@@ -6235,6 +6251,28 @@
                      layer_);
 }
 
+TEST_P(LCDTextTest, BackdropFilterAnimation) {
+  FilterOperations backdrop_filter;
+  backdrop_filter.Append(FilterOperation::CreateBlurFilter(4.0f));
+  SetBackdropFilter(descendant_, backdrop_filter);
+  UpdateDrawProperties(host_impl()->active_tree());
+  CheckCanUseLCDText(LCDTextDisallowedReason::kPixelOrColorEffect,
+                     "backdrop-filter", layer_);
+  CheckCanUseLCDText(LCDTextDisallowedReason::kNone, "backdrop-filter",
+                     descendant_);
+
+  GetEffectNode(descendant_)->has_potential_backdrop_filter_animation = true;
+  SetBackdropFilter(descendant_, FilterOperations());
+  UpdateDrawProperties(host_impl()->active_tree());
+  CheckCanUseLCDText(LCDTextDisallowedReason::kPixelOrColorEffect,
+                     "backdrop-filter animation", layer_);
+
+  GetEffectNode(descendant_)->has_potential_backdrop_filter_animation = false;
+  UpdateDrawProperties(host_impl()->active_tree());
+  CheckCanUseLCDText(LCDTextDisallowedReason::kNone, "no backdrop-filter",
+                     layer_);
+}
+
 TEST_P(LCDTextTest, ContentsOpaqueForText) {
   layer_->SetContentsOpaque(false);
   layer_->SetBackgroundColor(SK_ColorGREEN);
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc
index a2e21b1..1e007fd 100644
--- a/cc/trees/draw_property_utils.cc
+++ b/cc/trees/draw_property_utils.cc
@@ -777,7 +777,8 @@
     } else {
       node->target_id = effect_tree->parent(node)->target_id;
     }
-    if (!node->backdrop_filters.IsEmpty())
+    if (!node->backdrop_filters.IsEmpty() ||
+        node->has_potential_backdrop_filter_animation)
       last_backdrop_filter = node->id;
     node->affected_by_backdrop_filter = false;
   }
@@ -795,7 +796,8 @@
       current_target_id = kInvalidNodeId;
     // While down to kContentsRootNodeId, move |current_target_id| forward if
     // |node| has backdrop filter.
-    if (!node->backdrop_filters.IsEmpty() &&
+    if ((!node->backdrop_filters.IsEmpty() ||
+         node->has_potential_backdrop_filter_animation) &&
         current_target_id == kInvalidNodeId)
       current_target_id = node->target_id;
   }
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc
index a7d58fe..a4a770d1 100644
--- a/cc/trees/property_tree.cc
+++ b/cc/trees/property_tree.cc
@@ -743,7 +743,8 @@
 }
 
 void EffectTree::UpdateHasFilters(EffectNode* node, EffectNode* parent_node) {
-  node->node_or_ancestor_has_filters = !node->filters.IsEmpty();
+  node->node_or_ancestor_has_filters =
+      !node->filters.IsEmpty() || node->has_potential_filter_animation;
   if (parent_node) {
     node->node_or_ancestor_has_filters |=
         parent_node->node_or_ancestor_has_filters;
diff --git a/chrome/VERSION b/chrome/VERSION
index ec3c961..cce142a 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=87
 MINOR=0
-BUILD=4265
+BUILD=4266
 PATCH=0
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupPopupUiMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupPopupUiMediator.java
new file mode 100644
index 0000000..0c0201a
--- /dev/null
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupPopupUiMediator.java
@@ -0,0 +1,266 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.tasks.tab_management;
+
+import android.view.View;
+
+import androidx.annotation.VisibleForTesting;
+
+import org.chromium.base.CallbackController;
+import org.chromium.base.supplier.OneshotSupplier;
+import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
+import org.chromium.chrome.browser.compositor.layouts.EmptyOverviewModeObserver;
+import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tab.TabCreationState;
+import org.chromium.chrome.browser.tab.TabLaunchType;
+import org.chromium.chrome.browser.tabmodel.TabModelObserver;
+import org.chromium.chrome.browser.tabmodel.TabModelSelector;
+import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter;
+import org.chromium.chrome.tab_ui.R;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetObserver;
+import org.chromium.components.browser_ui.bottomsheet.EmptyBottomSheetObserver;
+import org.chromium.ui.KeyboardVisibilityDelegate;
+import org.chromium.ui.modelutil.PropertyModel;
+
+import java.util.List;
+
+/**
+ * A mediator for the TabGroupPopUi. Responsible for managing the
+ * internal state of the component.
+ */
+public class TabGroupPopupUiMediator {
+    /**
+     * An interface to update the size of the TabGroupPopupUi.
+     */
+    public interface TabGroupPopUiUpdater {
+        /**
+         * Update the TabGroupPopUi.
+         */
+        void updateTabGroupPopUi();
+    }
+
+    private final PropertyModel mModel;
+    private final TabModelObserver mTabModelObserver;
+    private final TabModelSelector mTabModelSelector;
+    private final BrowserControlsStateProvider mBrowserControlsStateProvider;
+    private final BrowserControlsStateProvider.Observer mBrowserControlsObserver;
+    private final KeyboardVisibilityDelegate.KeyboardVisibilityListener mKeyboardVisibilityListener;
+    private final TabGroupPopUiUpdater mUiUpdater;
+    private final TabGroupUiMediator.TabGroupUiController mTabGroupUiController;
+    private final BottomSheetController mBottomSheetController;
+    private final BottomSheetObserver mBottomSheetObserver;
+
+    private final OverviewModeBehavior.OverviewModeObserver mOverviewModeObserver;
+    private CallbackController mCallbackController = new CallbackController();
+    private OverviewModeBehavior mOverviewModeBehavior;
+
+    private boolean mIsOverviewModeVisible;
+
+    TabGroupPopupUiMediator(PropertyModel model, TabModelSelector tabModelSelector,
+            OneshotSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier,
+            BrowserControlsStateProvider browserControlsStateProvider, TabGroupPopUiUpdater updater,
+            TabGroupUiMediator.TabGroupUiController controller,
+            BottomSheetController bottomSheetController) {
+        mModel = model;
+        mTabModelSelector = tabModelSelector;
+        mBrowserControlsStateProvider = browserControlsStateProvider;
+        mUiUpdater = updater;
+        mTabGroupUiController = controller;
+        mBottomSheetController = bottomSheetController;
+
+        mBrowserControlsObserver = new BrowserControlsStateProvider.Observer() {
+            @Override
+            public void onControlsOffsetChanged(int topOffset, int topControlsMinHeightOffset,
+                    int bottomOffset, int bottomControlsMinHeightOffset, boolean needsAnimate) {
+                // Modify the alpha the strip container view base on bottomOffset. The range of
+                // bottomOffset is within 0 to mIconSize.
+                mModel.set(TabGroupPopupUiProperties.CONTENT_VIEW_ALPHA,
+                        1 - mBrowserControlsStateProvider.getBrowserControlHiddenRatio());
+            }
+        };
+        mBrowserControlsStateProvider.addObserver(mBrowserControlsObserver);
+
+        mTabModelObserver = new TabModelObserver() {
+            @Override
+            public void didSelectTab(Tab tab, int type, int lastId) {
+                List<Tab> tabList = mTabModelSelector.getTabModelFilterProvider()
+                                            .getCurrentTabModelFilter()
+                                            .getRelatedTabList(lastId);
+                if (tabList.contains(tab)) return;
+                if (isCurrentTabInGroup()) {
+                    if (isTabStripShowing()) {
+                        mUiUpdater.updateTabGroupPopUi();
+                    } else {
+                        maybeShowTabStrip();
+                    }
+                } else {
+                    hideTabStrip();
+                }
+            }
+
+            @Override
+            public void willCloseTab(Tab tab, boolean animate) {
+                if (!isCurrentTabInGroup()) {
+                    hideTabStrip();
+                }
+                if (isTabStripShowing()) {
+                    mUiUpdater.updateTabGroupPopUi();
+                }
+            }
+
+            @Override
+            public void didAddTab(Tab tab, int type, @TabCreationState int creationState) {
+                if (isTabStripShowing()) {
+                    mUiUpdater.updateTabGroupPopUi();
+                    return;
+                }
+                if (type != TabLaunchType.FROM_RESTORE) {
+                    maybeShowTabStrip();
+                }
+            }
+
+            @Override
+            public void tabClosureUndone(Tab tab) {
+                if (isTabStripShowing()) {
+                    mUiUpdater.updateTabGroupPopUi();
+                    return;
+                }
+                maybeShowTabStrip();
+            }
+
+            @Override
+            public void restoreCompleted() {
+                maybeShowTabStrip();
+            }
+        };
+        mTabModelSelector.getTabModelFilterProvider().addTabModelFilterObserver(mTabModelObserver);
+
+        mOverviewModeObserver = new EmptyOverviewModeObserver() {
+            @Override
+            public void onOverviewModeStartedShowing(boolean showToolbar) {
+                mIsOverviewModeVisible = true;
+                hideTabStrip();
+            }
+
+            @Override
+            public void onOverviewModeFinishedHiding() {
+                mIsOverviewModeVisible = false;
+                maybeShowTabStrip();
+            }
+        };
+
+        overviewModeBehaviorSupplier.onAvailable(
+                mCallbackController.makeCancelable((overviewModeBehavior) -> {
+                    mOverviewModeBehavior = overviewModeBehavior;
+                    mOverviewModeBehavior.addOverviewModeObserver(mOverviewModeObserver);
+                }));
+
+        mKeyboardVisibilityListener = new KeyboardVisibilityDelegate.KeyboardVisibilityListener() {
+            private boolean mWasShowingStrip;
+            @Override
+            public void keyboardVisibilityChanged(boolean isShowing) {
+                if (isShowing) {
+                    mWasShowingStrip = isTabStripShowing();
+                    hideTabStrip();
+                } else {
+                    if (mWasShowingStrip) {
+                        maybeShowTabStrip();
+                    }
+                }
+            }
+        };
+        KeyboardVisibilityDelegate.getInstance().addKeyboardVisibilityListener(
+                mKeyboardVisibilityListener);
+
+        mBottomSheetObserver = new EmptyBottomSheetObserver() {
+            private Boolean mWasShowingStrip;
+            @Override
+            public void onSheetStateChanged(int newState) {
+                if (newState == BottomSheetController.SheetState.HIDDEN) {
+                    if (mWasShowingStrip != null && mWasShowingStrip) {
+                        maybeShowTabStrip();
+                    }
+                    mWasShowingStrip = null;
+                } else {
+                    if (mWasShowingStrip == null) {
+                        mWasShowingStrip = isTabStripShowing();
+                    }
+                    hideTabStrip();
+                }
+            }
+        };
+        mBottomSheetController.addObserver(mBottomSheetObserver);
+
+        // TODO(yuezhanggg): Reset the strip with empty tab list as well.
+        mTabGroupUiController.setupLeftButtonOnClickListener(view -> hideTabStrip());
+    }
+
+    void onAnchorViewChanged(View anchorView, int anchorViewId) {
+        boolean isShowing = isTabStripShowing();
+        if (isShowing) {
+            mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, false);
+        }
+        // When showing bottom toolbar, the arrow on dismiss button should point down; when showing
+        // adaptive toolbar, the arrow on dismiss button should point up.
+        mTabGroupUiController.setupLeftButtonDrawable(anchorViewId == R.id.toolbar
+                        ? R.drawable.ic_expand_less_black_24dp
+                        : R.drawable.ic_expand_more_black_24dp);
+        mModel.set(TabGroupPopupUiProperties.ANCHOR_VIEW, anchorView);
+        if (isShowing) {
+            mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, true);
+        }
+    }
+
+    void maybeShowTabStrip() {
+        if (mIsOverviewModeVisible || !isCurrentTabInGroup()) return;
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, true);
+    }
+
+    private void hideTabStrip() {
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, false);
+    }
+
+    private boolean isCurrentTabInGroup() {
+        assert mTabModelSelector.getTabModelFilterProvider().getCurrentTabModelFilter()
+                        instanceof TabGroupModelFilter;
+        TabGroupModelFilter filter =
+                (TabGroupModelFilter) mTabModelSelector.getTabModelFilterProvider()
+                        .getCurrentTabModelFilter();
+        Tab currentTab = mTabModelSelector.getCurrentTab();
+        if (currentTab == null) return false;
+        List<Tab> tabgroup = filter.getRelatedTabList(currentTab.getId());
+        return tabgroup.size() > 1;
+    }
+
+    private boolean isTabStripShowing() {
+        return mModel.get(TabGroupPopupUiProperties.IS_VISIBLE);
+    }
+
+    /**
+     * Destroy any members that needs clean up.
+     */
+    public void destroy() {
+        KeyboardVisibilityDelegate.getInstance().removeKeyboardVisibilityListener(
+                mKeyboardVisibilityListener);
+        if (mOverviewModeBehavior != null) {
+            mOverviewModeBehavior.removeOverviewModeObserver(mOverviewModeObserver);
+        }
+        if (mCallbackController != null) {
+            mCallbackController.destroy();
+            mCallbackController = null;
+        }
+        mTabModelSelector.getTabModelFilterProvider().removeTabModelFilterObserver(
+                mTabModelObserver);
+        mBrowserControlsStateProvider.removeObserver(mBrowserControlsObserver);
+        mBottomSheetController.removeObserver(mBottomSheetObserver);
+    }
+
+    @VisibleForTesting
+    boolean getIsOverviewModeVisibleForTesting() {
+        return mIsOverviewModeVisible;
+    }
+}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediator.java
index cab57d6..afb4c681 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediator.java
@@ -14,10 +14,10 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
-import org.chromium.base.Callback;
+import org.chromium.base.CallbackController;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
-import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.chrome.browser.ThemeColorProvider;
 import org.chromium.chrome.browser.compositor.layouts.EmptyOverviewModeObserver;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
@@ -113,8 +113,7 @@
     private final SnackbarManager.SnackbarManageable mSnackbarManageable;
     private final Snackbar mUndoClosureSnackBar;
 
-    private ObservableSupplier<OverviewModeBehavior> mOverviewModeBehaviorSupplier;
-    private final Callback<OverviewModeBehavior> mOverviewModeBehaviorSupplierObserver;
+    private CallbackController mCallbackController = new CallbackController();
     private final OverviewModeBehavior.OverviewModeObserver mOverviewModeObserver;
     private OverviewModeBehavior mOverviewModeBehavior;
 
@@ -129,7 +128,7 @@
             BottomControlsCoordinator.BottomControlsVisibilityController visibilityController,
             ResetHandler resetHandler, PropertyModel model, TabModelSelector tabModelSelector,
             TabCreatorManager tabCreatorManager,
-            ObservableSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier,
+            OneshotSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier,
             ThemeColorProvider themeColorProvider,
             @Nullable TabGridDialogMediator.DialogController dialogController,
             ActivityLifecycleDispatcher activityLifecycleDispatcher,
@@ -139,7 +138,6 @@
         mModel = model;
         mTabModelSelector = tabModelSelector;
         mTabCreatorManager = tabCreatorManager;
-        mOverviewModeBehaviorSupplier = overviewModeBehaviorSupplier;
         mVisibilityController = visibilityController;
         mThemeColorProvider = themeColorProvider;
         mTabGridDialogController = dialogController;
@@ -342,19 +340,11 @@
         mTabModelSelector.getTabModelFilterProvider().addTabModelFilterObserver(mTabModelObserver);
         mTabModelSelector.addObserver(mTabModelSelectorObserver);
 
-        mOverviewModeBehaviorSupplierObserver = new Callback<OverviewModeBehavior>() {
-            @Override
-            public void onResult(OverviewModeBehavior overviewModeBehavior) {
-                assert overviewModeBehavior != null;
-                mOverviewModeBehavior = overviewModeBehavior;
-                mOverviewModeBehavior.addOverviewModeObserver(mOverviewModeObserver);
-
-                // TODO(crbug.com/1084528): Replace with OneShotSupplier when it is available.
-                mOverviewModeBehaviorSupplier.removeObserver(this);
-                mOverviewModeBehaviorSupplier = null;
-            }
-        };
-        mOverviewModeBehaviorSupplier.addObserver(mOverviewModeBehaviorSupplierObserver);
+        overviewModeBehaviorSupplier.onAvailable(
+                mCallbackController.makeCancelable((overviewModeBehavior) -> {
+                    mOverviewModeBehavior = overviewModeBehavior;
+                    mOverviewModeBehavior.addOverviewModeObserver(mOverviewModeObserver);
+                }));
 
         mThemeColorProvider.addThemeColorObserver(mThemeColorObserver);
         mThemeColorProvider.addTintObserver(mTintObserver);
@@ -530,8 +520,9 @@
         if (mOverviewModeBehavior != null) {
             mOverviewModeBehavior.removeOverviewModeObserver(mOverviewModeObserver);
         }
-        if (mOverviewModeBehaviorSupplier != null) {
-            mOverviewModeBehaviorSupplier.removeObserver(mOverviewModeBehaviorSupplierObserver);
+        if (mCallbackController != null) {
+            mCallbackController.destroy();
+            mCallbackController = null;
         }
         mThemeColorProvider.removeThemeColorObserver(mThemeColorObserver);
         mThemeColorProvider.removeTintObserver(mTintObserver);
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupPopupUiMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupPopupUiMediatorUnitTest.java
new file mode 100644
index 0000000..209566c
--- /dev/null
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupPopupUiMediatorUnitTest.java
@@ -0,0 +1,601 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.tasks.tab_management;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.widget.FrameLayout;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import org.chromium.base.supplier.OneshotSupplierImpl;
+import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
+import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tab.TabCreationState;
+import org.chromium.chrome.browser.tab.TabImpl;
+import org.chromium.chrome.browser.tab.TabLaunchType;
+import org.chromium.chrome.browser.tab.state.CriticalPersistedTabData;
+import org.chromium.chrome.browser.tabmodel.TabModelFilterProvider;
+import org.chromium.chrome.browser.tabmodel.TabModelObserver;
+import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl;
+import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter;
+import org.chromium.chrome.browser.toolbar.top.ToolbarPhone;
+import org.chromium.chrome.tab_ui.R;
+import org.chromium.chrome.test.util.browser.Features;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetObserver;
+import org.chromium.testing.local.LocalRobolectricTestRunner;
+import org.chromium.ui.KeyboardVisibilityDelegate;
+import org.chromium.ui.modelutil.PropertyModel;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Tests for {@link TabGroupPopupUiMediator}.
+ */
+@SuppressWarnings({"ResultOfMethodCallIgnored", "ArraysAsListWithZeroOrOneArgument"})
+@RunWith(LocalRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class TabGroupPopupUiMediatorUnitTest {
+    @Rule
+    public TestRule mProcessor = new Features.JUnitProcessor();
+
+    private static final String TAB1_TITLE = "Tab1";
+    private static final String TAB2_TITLE = "Tab2";
+    private static final String TAB3_TITLE = "Tab3";
+    private static final String TAB4_TITLE = "Tab4";
+    private static final int TAB1_ID = 456;
+    private static final int TAB2_ID = 789;
+    private static final int TAB3_ID = 123;
+    private static final int TAB4_ID = 357;
+
+    @Mock
+    TabModelSelectorImpl mTabModelSelector;
+    @Mock
+    OverviewModeBehavior mOverviewModeBehavior;
+    @Mock
+    BrowserControlsStateProvider mBrowserControlsStateProvider;
+    @Mock
+    TabGroupPopupUiMediator.TabGroupPopUiUpdater mUpdater;
+    @Mock
+    TabGroupUiMediator.TabGroupUiController mTabGroupUiController;
+    @Mock
+    TabModelFilterProvider mTabModelFilterProvider;
+    @Mock
+    TabGroupModelFilter mTabGroupModelFilter;
+    @Mock
+    KeyboardVisibilityDelegate mKeyboardVisibilityDelegate;
+    @Mock
+    ToolbarPhone mTopAnchorView;
+    @Mock
+    FrameLayout mBottomAnchorView;
+    @Mock
+    BottomSheetController mBottomSheetController;
+    @Captor
+    ArgumentCaptor<TabModelObserver> mTabModelObserverCaptor;
+    @Captor
+    private ArgumentCaptor<BrowserControlsStateProvider.Observer>
+            mBrowserControlsStateProviderObserverCaptor;
+    @Captor
+    ArgumentCaptor<OverviewModeBehavior.OverviewModeObserver> mOverviewModeObserverCaptor;
+    @Captor
+    ArgumentCaptor<KeyboardVisibilityDelegate.KeyboardVisibilityListener>
+            mKeyboardVisibilityListenerCaptor;
+    @Captor
+    ArgumentCaptor<BottomSheetObserver> mBottomSheetObserver;
+
+    private TabImpl mTab1;
+    private TabImpl mTab2;
+    private TabImpl mTab3;
+    private PropertyModel mModel;
+    private TabGroupPopupUiMediator mMediator;
+    private OneshotSupplierImpl<OverviewModeBehavior> mOverviewModeBehaviorSupplier =
+            new OneshotSupplierImpl<>();
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mTab1 = prepareTab(TAB1_ID, TAB1_TITLE);
+        mTab2 = prepareTab(TAB2_ID, TAB2_TITLE);
+        mTab3 = prepareTab(TAB3_ID, TAB3_TITLE);
+
+        doReturn(mTab1).when(mTabModelSelector).getCurrentTab();
+        doReturn(mTabModelFilterProvider).when(mTabModelSelector).getTabModelFilterProvider();
+        doReturn(mTabGroupModelFilter).when(mTabModelFilterProvider).getCurrentTabModelFilter();
+        doNothing()
+                .when(mTabModelFilterProvider)
+                .addTabModelFilterObserver(mTabModelObserverCaptor.capture());
+        doNothing()
+                .when(mBrowserControlsStateProvider)
+                .addObserver(mBrowserControlsStateProviderObserverCaptor.capture());
+        doNothing()
+                .when(mOverviewModeBehavior)
+                .addOverviewModeObserver(mOverviewModeObserverCaptor.capture());
+        doNothing()
+                .when(mKeyboardVisibilityDelegate)
+                .addKeyboardVisibilityListener(mKeyboardVisibilityListenerCaptor.capture());
+        doNothing().when(mBottomSheetController).addObserver(mBottomSheetObserver.capture());
+
+        mOverviewModeBehaviorSupplier.set(mOverviewModeBehavior);
+        KeyboardVisibilityDelegate.setInstance(mKeyboardVisibilityDelegate);
+        mModel = new PropertyModel(TabGroupPopupUiProperties.ALL_KEYS);
+        mMediator = new TabGroupPopupUiMediator(mModel, mTabModelSelector,
+                mOverviewModeBehaviorSupplier, mBrowserControlsStateProvider, mUpdater,
+                mTabGroupUiController, mBottomSheetController);
+    }
+
+    @Test
+    public void testOnControlOffsetChanged() {
+        mModel.set(TabGroupPopupUiProperties.CONTENT_VIEW_ALPHA, 0f);
+
+        // Mock that the hidden ratio of browser control is 0.8765.
+        float hiddenRatio = 0.8765f;
+        doReturn(hiddenRatio).when(mBrowserControlsStateProvider).getBrowserControlHiddenRatio();
+        mBrowserControlsStateProviderObserverCaptor.getValue().onControlsOffsetChanged(
+                0, 0, 0, 0, false);
+
+        assertThat(
+                mModel.get(TabGroupPopupUiProperties.CONTENT_VIEW_ALPHA), equalTo(1 - hiddenRatio));
+
+        // Mock that the hidden ratio of browser control is 0.12345.
+        hiddenRatio = 0.1234f;
+        doReturn(hiddenRatio).when(mBrowserControlsStateProvider).getBrowserControlHiddenRatio();
+        mBrowserControlsStateProviderObserverCaptor.getValue().onControlsOffsetChanged(
+                0, 0, 0, 0, false);
+
+        assertThat(
+                mModel.get(TabGroupPopupUiProperties.CONTENT_VIEW_ALPHA), equalTo(1 - hiddenRatio));
+    }
+
+    @Test
+    public void tabSelection_Show() {
+        // Mock that the strip is hidden.
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, false);
+        // Mock that tab1 and tab2 are in the same group, and tab 3 is a single tab.
+        createTabGroup(new ArrayList<>(Arrays.asList(mTab1, mTab2)), TAB1_ID);
+        createTabGroup(new ArrayList<>(Arrays.asList(mTab3)), TAB3_ID);
+
+        doReturn(mTab2).when(mTabModelSelector).getCurrentTab();
+        mTabModelObserverCaptor.getValue().didSelectTab(
+                mTab2, TabLaunchType.FROM_CHROME_UI, TAB3_ID);
+
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(true));
+        verify(mUpdater, never()).updateTabGroupPopUi();
+    }
+
+    @Test
+    public void tabSelection_Hide() {
+        // Mock that the strip is showing.
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, true);
+        // Mock that tab1 and tab2 are in the same group, and tab 3 is a single tab.
+        createTabGroup(new ArrayList<>(Arrays.asList(mTab1, mTab2)), TAB1_ID);
+        createTabGroup(new ArrayList<>(Arrays.asList(mTab3)), TAB3_ID);
+
+        doReturn(mTab3).when(mTabModelSelector).getCurrentTab();
+        mTabModelObserverCaptor.getValue().didSelectTab(
+                mTab3, TabLaunchType.FROM_CHROME_UI, TAB1_ID);
+
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(false));
+        verify(mUpdater, never()).updateTabGroupPopUi();
+    }
+
+    @Test
+    public void tabSelection_Update() {
+        // Mock that the strip is showing.
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, true);
+        // Mock that tab1 and tab2 are in the same group, tab3 and new tab are in the same group.
+        createTabGroup(new ArrayList<>(Arrays.asList(mTab1, mTab2)), TAB1_ID);
+        createTabGroup(
+                new ArrayList<>(Arrays.asList(mTab3, prepareTab(TAB4_ID, TAB4_TITLE))), TAB3_ID);
+
+        doReturn(mTab1).when(mTabModelSelector).getCurrentTab();
+        mTabModelObserverCaptor.getValue().didSelectTab(
+                mTab1, TabLaunchType.FROM_CHROME_UI, TAB3_ID);
+
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(true));
+        verify(mUpdater).updateTabGroupPopUi();
+    }
+
+    @Test
+    public void tabSelection_SameGroup() {
+        // Mock that the strip is showing.
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, true);
+        // Mock that tab1 and tab2 are in the same group.
+        createTabGroup(new ArrayList<>(Arrays.asList(mTab1, mTab2)), TAB1_ID);
+
+        doReturn(mTab1).when(mTabModelSelector).getCurrentTab();
+        mTabModelObserverCaptor.getValue().didSelectTab(
+                mTab1, TabLaunchType.FROM_CHROME_UI, TAB2_ID);
+
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(true));
+        verify(mUpdater, never()).updateTabGroupPopUi();
+    }
+
+    @Test
+    public void tabClosure_Hide() {
+        // Mock that the strip is showing.
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, true);
+        // Mock that tab1 and tab2 are in the same group, and tab1 is closing.
+        List<Tab> tabGroup = new ArrayList<>(Arrays.asList(mTab2));
+        doReturn(tabGroup).when(mTabGroupModelFilter).getRelatedTabList(TAB1_ID);
+        doReturn(tabGroup).when(mTabGroupModelFilter).getRelatedTabList(TAB2_ID);
+
+        mTabModelObserverCaptor.getValue().willCloseTab(mTab1, false);
+
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(false));
+        verify(mUpdater, never()).updateTabGroupPopUi();
+    }
+
+    @Test
+    public void tabClosure_Update() {
+        // Mock that the strip is showing.
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, true);
+        // Mock that tab1, tab2 and tab3 are in the same group, and tab1 is closing.
+        List<Tab> tabGroup = new ArrayList<>(Arrays.asList(mTab2, mTab3));
+        doReturn(tabGroup).when(mTabGroupModelFilter).getRelatedTabList(TAB1_ID);
+        doReturn(tabGroup).when(mTabGroupModelFilter).getRelatedTabList(TAB2_ID);
+        doReturn(tabGroup).when(mTabGroupModelFilter).getRelatedTabList(TAB3_ID);
+
+        mTabModelObserverCaptor.getValue().willCloseTab(mTab1, false);
+
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(true));
+        verify(mUpdater).updateTabGroupPopUi();
+    }
+
+    @Test
+    public void tabAddition_Show() {
+        // Mock that the strip is hidden.
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, false);
+        // Mock that tab1 and tab2 are in the same group, and tab2 has just been created.
+        List<Tab> tabGroup = new ArrayList<>(Arrays.asList(mTab1, mTab2));
+        createTabGroup(tabGroup, TAB1_ID);
+
+        mTabModelObserverCaptor.getValue().didAddTab(
+                mTab2, TabLaunchType.FROM_CHROME_UI, TabCreationState.LIVE_IN_FOREGROUND);
+
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(true));
+        verify(mUpdater, never()).updateTabGroupPopUi();
+    }
+
+    @Test
+    public void tabAddition_Update() {
+        // Mock that the strip is showing.
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, true);
+        // Mock that tab1, tab2 and tab3 are in the same group, and tab3 has just been created.
+        List<Tab> tabGroup = new ArrayList<>(Arrays.asList(mTab1, mTab2, mTab3));
+        createTabGroup(tabGroup, TAB1_ID);
+
+        mTabModelObserverCaptor.getValue().didAddTab(
+                mTab3, TabLaunchType.FROM_CHROME_UI, TabCreationState.LIVE_IN_FOREGROUND);
+
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(true));
+        verify(mUpdater).updateTabGroupPopUi();
+    }
+
+    @Test
+    public void tabAddition_NotShow_Restore() {
+        // Mock that the strip is hidden.
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, false);
+        // Mock that tab1 and tab2 are in the same group, and they are being restored.
+        List<Tab> tabGroup = new ArrayList<>(Arrays.asList(mTab1, mTab2));
+        createTabGroup(tabGroup, TAB1_ID);
+
+        mTabModelObserverCaptor.getValue().didAddTab(
+                mTab2, TabLaunchType.FROM_RESTORE, TabCreationState.FROZEN_ON_RESTORE);
+
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(false));
+        verify(mUpdater, never()).updateTabGroupPopUi();
+    }
+
+    @Test
+    public void tabClosureUndone_Show() {
+        // Mock that the strip is hiding.
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, false);
+        // Mock that tab1 and tab2 are in the same group, and we have just undone the closure of
+        // tab2.
+        List<Tab> tabGroup = new ArrayList<>(Arrays.asList(mTab1, mTab2));
+        createTabGroup(tabGroup, TAB1_ID);
+
+        mTabModelObserverCaptor.getValue().tabClosureUndone(mTab2);
+
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(true));
+        verify(mUpdater, never()).updateTabGroupPopUi();
+    }
+
+    @Test
+    public void tabClosureUndone_Update() {
+        // Mock that the strip is showing.
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, true);
+        // Mock that tab1, tab2 and tab3 are in the same group, and we have just undone the closure
+        // of tab3.
+        List<Tab> tabGroup = new ArrayList<>(Arrays.asList(mTab1, mTab2, mTab3));
+        createTabGroup(tabGroup, TAB1_ID);
+
+        mTabModelObserverCaptor.getValue().tabClosureUndone(mTab3);
+
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(true));
+        verify(mUpdater).updateTabGroupPopUi();
+    }
+
+    @Test
+    public void tabClosureUndone_NotShow() {
+        // Mock that the strip is hiding.
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, false);
+        // Mock that tab1 is a single tab.
+        List<Tab> tabGroup = new ArrayList<>(Arrays.asList(mTab1));
+        createTabGroup(tabGroup, TAB1_ID);
+
+        mTabModelObserverCaptor.getValue().tabClosureUndone(mTab1);
+
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(false));
+        verify(mUpdater, never()).updateTabGroupPopUi();
+    }
+
+    @Test
+    public void tabRestoreCompletion_NotShow() {
+        // Mock that the strip is hiding.
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, false);
+        // Mock that tab1 is the current tab and it is a single tab.
+        List<Tab> tabGroup = new ArrayList<>(Arrays.asList(mTab1));
+        createTabGroup(tabGroup, TAB1_ID);
+        doReturn(mTab1).when(mTabModelSelector).getCurrentTab();
+
+        mTabModelObserverCaptor.getValue().restoreCompleted();
+
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(false));
+    }
+
+    @Test
+    public void tabRestoreCompletion_Show() {
+        // Mock that the strip is hiding.
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, false);
+        // Mock that tab1 is the current tab and it is in a group of {tab1, tab2}.
+        List<Tab> tabGroup = new ArrayList<>(Arrays.asList(mTab1, mTab2));
+        createTabGroup(tabGroup, TAB1_ID);
+        doReturn(mTab1).when(mTabModelSelector).getCurrentTab();
+
+        mTabModelObserverCaptor.getValue().restoreCompleted();
+
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(true));
+    }
+
+    @Test
+    public void testOverviewModeHiding() {
+        // Mock that the strip is hiding.
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, false);
+        // Mock that tab1 and tab2 are in the same group, and tab1 is the current tab.
+        List<Tab> tabGroup = new ArrayList<>(Arrays.asList(mTab1, mTab2));
+        createTabGroup(tabGroup, TAB1_ID);
+        doReturn(mTab1).when(mTabModelSelector).getCurrentTab();
+
+        mOverviewModeObserverCaptor.getValue().onOverviewModeFinishedHiding();
+
+        assertThat(mMediator.getIsOverviewModeVisibleForTesting(), equalTo(false));
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(true));
+    }
+
+    @Test
+    public void testOverviewModeShowing() {
+        // Mock that the strip is showing.
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, true);
+        // Mock that tab1 and tab2 are in the same group, and tab1 is the current tab.
+        List<Tab> tabGroup = new ArrayList<>(Arrays.asList(mTab1, mTab2));
+        createTabGroup(tabGroup, TAB1_ID);
+        doReturn(mTab1).when(mTabModelSelector).getCurrentTab();
+
+        mOverviewModeObserverCaptor.getValue().onOverviewModeStartedShowing(true);
+
+        assertThat(mMediator.getIsOverviewModeVisibleForTesting(), equalTo(true));
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(false));
+    }
+
+    @Test
+    public void testNeverShowStripWhenOverviewVisible() {
+        // Mock that the strip is hiding and overview is visible.
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, false);
+        mOverviewModeObserverCaptor.getValue().onOverviewModeStartedShowing(true);
+        assertThat(mMediator.getIsOverviewModeVisibleForTesting(), equalTo(true));
+
+        // Calling maybeShowTabStrip should never show strip in this case.
+        mMediator.maybeShowTabStrip();
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(false));
+    }
+
+    @Test
+    public void testNeverShowStripWhenSingleTab() {
+        // Mock that the strip is hiding and overview is visible.
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, false);
+        // Mock that tab1 is the current tab and it is a single tab.
+        List<Tab> tabGroup = new ArrayList<>(Arrays.asList(mTab1));
+        createTabGroup(tabGroup, TAB1_ID);
+        doReturn(mTab1).when(mTabModelSelector).getCurrentTab();
+
+        // Calling maybeShowTabStrip should never show strip in this case.
+        mMediator.maybeShowTabStrip();
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(false));
+    }
+
+    @Test
+    public void testShowKeyboard_HideStrip() {
+        // Mock that the strip is showing.
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, true);
+
+        mKeyboardVisibilityListenerCaptor.getValue().keyboardVisibilityChanged(true);
+
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(false));
+    }
+
+    @Test
+    public void testHideKeyboard_ShowStrip() {
+        // Mock that the strip is showing before showing the keyboard. tab1 and tab2 are in the same
+        // group, and tab1 is the current tab.
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, true);
+        List<Tab> tabGroup = new ArrayList<>(Arrays.asList(mTab1, mTab2));
+        createTabGroup(tabGroup, TAB1_ID);
+        doReturn(mTab1).when(mTabModelSelector).getCurrentTab();
+
+        // Hide the keyboard after showing it.
+        mKeyboardVisibilityListenerCaptor.getValue().keyboardVisibilityChanged(true);
+        mKeyboardVisibilityListenerCaptor.getValue().keyboardVisibilityChanged(false);
+
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(true));
+    }
+
+    @Test
+    public void testHideKeyboard_NotReshowStrip() {
+        // Mock that the strip is hidden before showing the keyboard. tab1 and tab2 are in the same
+        // group, and tab1 is the current tab.
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, false);
+        List<Tab> tabGroup = new ArrayList<>(Arrays.asList(mTab1, mTab2));
+        createTabGroup(tabGroup, TAB1_ID);
+        doReturn(mTab1).when(mTabModelSelector).getCurrentTab();
+
+        // Hide the keyboard after showing it.
+        mKeyboardVisibilityListenerCaptor.getValue().keyboardVisibilityChanged(true);
+        mKeyboardVisibilityListenerCaptor.getValue().keyboardVisibilityChanged(false);
+
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(false));
+    }
+
+    @Test
+    public void testShowBottomSheet_HideStrip() {
+        // Mock that the strip is showing.
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, true);
+
+        // Show bottom sheet.
+        mBottomSheetObserver.getValue().onSheetStateChanged(BottomSheetController.SheetState.PEEK);
+
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(false));
+    }
+
+    @Test
+    public void testHideBottomSheet_ShowStrip() {
+        // Mock that the strip is showing before showing the bottom sheet. tab1 and tab2 are in the
+        // same group, and tab1 is the current tab.
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, true);
+        List<Tab> tabGroup = new ArrayList<>(Arrays.asList(mTab1, mTab2));
+        createTabGroup(tabGroup, TAB1_ID);
+        doReturn(mTab1).when(mTabModelSelector).getCurrentTab();
+
+        // Hide the bottom sheet after showing it.
+        mBottomSheetObserver.getValue().onSheetStateChanged(BottomSheetController.SheetState.PEEK);
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(false));
+        mBottomSheetObserver.getValue().onSheetStateChanged(
+                BottomSheetController.SheetState.HIDDEN);
+
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(true));
+    }
+
+    @Test
+    public void testHideBottomSheet_NotReshowStrip() {
+        // Mock that the strip is hidden before showing the bottom sheet. tab1 and tab2 are in the
+        // same group, and tab1 is the current tab.
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, false);
+        List<Tab> tabGroup = new ArrayList<>(Arrays.asList(mTab1, mTab2));
+        createTabGroup(tabGroup, TAB1_ID);
+        doReturn(mTab1).when(mTabModelSelector).getCurrentTab();
+
+        // Hide the bottom sheet after showing it.
+        mBottomSheetObserver.getValue().onSheetStateChanged(BottomSheetController.SheetState.PEEK);
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(false));
+        mBottomSheetObserver.getValue().onSheetStateChanged(
+                BottomSheetController.SheetState.HIDDEN);
+
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(false));
+    }
+
+    @Test
+    public void testAnchorViewChange_TopToolbar() {
+        mMediator.onAnchorViewChanged(mTopAnchorView, R.id.toolbar);
+
+        assertThat(mModel.get(TabGroupPopupUiProperties.ANCHOR_VIEW), equalTo(mTopAnchorView));
+        verify(mTabGroupUiController)
+                .setupLeftButtonDrawable(eq(R.drawable.ic_expand_less_black_24dp));
+    }
+
+    @Test
+    public void testAnchorViewChange_BottomToolbar() {
+        mMediator.onAnchorViewChanged(mBottomAnchorView, R.id.bottom_controls);
+
+        assertThat(mModel.get(TabGroupPopupUiProperties.ANCHOR_VIEW), equalTo(mBottomAnchorView));
+        verify(mTabGroupUiController)
+                .setupLeftButtonDrawable(eq(R.drawable.ic_expand_more_black_24dp));
+    }
+
+    @Test
+    public void testAnchorViewChange_WithStripShowing() {
+        // Mock that strip is showing when anchor view changes.
+        mModel.set(TabGroupPopupUiProperties.IS_VISIBLE, true);
+
+        mMediator.onAnchorViewChanged(mBottomAnchorView, R.id.bottom_controls);
+
+        assertTrue(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE));
+        assertThat(mModel.get(TabGroupPopupUiProperties.ANCHOR_VIEW), equalTo(mBottomAnchorView));
+        verify(mTabGroupUiController)
+                .setupLeftButtonDrawable(eq(R.drawable.ic_expand_more_black_24dp));
+    }
+
+    @Test
+    public void testNoCurrentTab_NotShow() {
+        // Mock overview mode is hiding, and current tab is null.
+        doReturn(null).when(mTabModelSelector).getCurrentTab();
+        mOverviewModeObserverCaptor.getValue().onOverviewModeFinishedHiding();
+        assertThat(mMediator.getIsOverviewModeVisibleForTesting(), equalTo(false));
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(false));
+
+        mMediator.maybeShowTabStrip();
+
+        assertThat(mModel.get(TabGroupPopupUiProperties.IS_VISIBLE), equalTo(false));
+    }
+
+    @Test
+    public void testDestroy() {
+        mMediator.destroy();
+        verify(mKeyboardVisibilityDelegate)
+                .removeKeyboardVisibilityListener(mKeyboardVisibilityListenerCaptor.capture());
+        verify(mOverviewModeBehavior)
+                .removeOverviewModeObserver(mOverviewModeObserverCaptor.capture());
+        verify(mTabModelFilterProvider)
+                .removeTabModelFilterObserver(mTabModelObserverCaptor.capture());
+        verify(mBrowserControlsStateProvider)
+                .removeObserver(mBrowserControlsStateProviderObserverCaptor.capture());
+    }
+
+    // TODO(yuezhanggg): Pull methods below to a utility class.
+    private TabImpl prepareTab(int id, String title) {
+        TabImpl tab = TabUiUnitTestUtils.prepareTab(id, title, "");
+        doReturn(true).when(tab).isIncognito();
+        return tab;
+    }
+
+    private void createTabGroup(List<Tab> tabs, int rootId) {
+        for (Tab tab : tabs) {
+            when(mTabGroupModelFilter.getRelatedTabList(tab.getId())).thenReturn(tabs);
+            CriticalPersistedTabData criticalPersistedTabData = CriticalPersistedTabData.from(tab);
+            doReturn(rootId).when(criticalPersistedTabData).getRootId();
+        }
+    }
+}
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediatorUnitTest.java
index f9fd908..6b4ba5de 100644
--- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediatorUnitTest.java
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediatorUnitTest.java
@@ -40,7 +40,7 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
 
-import org.chromium.base.supplier.ObservableSupplierImpl;
+import org.chromium.base.supplier.OneshotSupplierImpl;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.browser.ThemeColorProvider;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
@@ -158,8 +158,8 @@
     private TabGroupUiMediator mTabGroupUiMediator;
     private InOrder mResetHandlerInOrder;
     private InOrder mVisibilityControllerInOrder;
-    private ObservableSupplierImpl<OverviewModeBehavior> mOverviewModeBehaviorSupplier =
-            new ObservableSupplierImpl<>();
+    private OneshotSupplierImpl<OverviewModeBehavior> mOverviewModeBehaviorSupplier =
+            new OneshotSupplierImpl<>();
 
     private TabImpl prepareTab(int tabId, int rootId) {
         TabImpl tab = TabUiUnitTestUtils.prepareTab(tabId, rootId);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 5af719f..33b5a90 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -42,9 +42,10 @@
 import org.chromium.base.library_loader.LibraryLoader;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
-import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.supplier.OneShotCallback;
+import org.chromium.base.supplier.OneshotSupplier;
+import org.chromium.base.supplier.OneshotSupplierImpl;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.base.task.PostTask;
 import org.chromium.chrome.R;
@@ -285,8 +286,8 @@
 
     private NextTabPolicySupplier mNextTabPolicySupplier;
 
-    private final ObservableSupplierImpl<OverviewModeBehavior> mOverviewModeBehaviorSupplier =
-            new ObservableSupplierImpl<>();
+    private final OneshotSupplierImpl<OverviewModeBehavior> mOverviewModeBehaviorSupplier =
+            new OneshotSupplierImpl<>();
     private OverviewModeController mOverviewModeController;
 
     private ObservableSupplierImpl<EphemeralTabCoordinator> mEphemeralTabCoordinatorSupplier =
@@ -848,7 +849,7 @@
         if (!mPendingInitialTabCreation
                 && !(TabUiFeatureUtilities.supportInstantStart(isTablet())
                         && shouldShowTabSwitcherOnStart())) {
-            setInitialOverviewState();
+            setInitialOverviewStateAsync();
         }
 
         if (TabUiFeatureUtilities.isConditionalTabStripEnabled()
@@ -902,7 +903,7 @@
     }
 
     @Override
-    public @Nullable ObservableSupplier<OverviewModeBehavior> getOverviewModeBehaviorSupplier() {
+    public @Nullable OneshotSupplier<OverviewModeBehavior> getOverviewModeBehaviorSupplier() {
         return mOverviewModeBehaviorSupplier;
     }
 
@@ -925,7 +926,14 @@
         }
     }
 
-    private void setInitialOverviewState() {
+    // Posts a call to setInitialOverviewStateSync that will trigger after observers of
+    // mOverviewModeBehaviorSupplier have a chance to process the supplied OverviewModeBehavior and
+    // add themselves as observers.
+    private void setInitialOverviewStateAsync() {
+        mOverviewModeBehaviorSupplier.onAvailable((unused) -> setInitalOverviewStateSync());
+    }
+
+    private void setInitalOverviewStateSync() {
         boolean isOverviewVisible = mOverviewModeController.overviewVisible();
 
         if (shouldShowTabSwitcherOnStart() && !isOverviewVisible) {
@@ -1137,7 +1145,7 @@
         if (hasStartWithNativeBeenCalled()
                 && !(TabUiFeatureUtilities.supportInstantStart(isTablet())
                         && shouldShowTabSwitcherOnStart())) {
-            setInitialOverviewState();
+            setInitialOverviewStateAsync();
         }
     }
 
@@ -1521,7 +1529,7 @@
             if (shouldShowTabSwitcherOnStart()) {
                 mLayoutManager.setTabModelSelector(mTabModelSelectorImpl);
                 mIsAccessibilityTabSwitcherEnabled = DeviceClassManager.enableAccessibilityLayout();
-                setInitialOverviewState();
+                setInitialOverviewStateAsync();
             }
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
index a72154e..f53ac6ea 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
@@ -50,6 +50,7 @@
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplierImpl;
+import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.AppHooks;
@@ -1376,7 +1377,8 @@
      * @return {@link ObservableSupplier} for the {@link OverviewModeBehavior} for this activity
      *         if it supports an overview mode, null otherwise.
      */
-    public @Nullable ObservableSupplier<OverviewModeBehavior> getOverviewModeBehaviorSupplier() {
+
+    public @Nullable OneshotSupplier<OverviewModeBehavior> getOverviewModeBehaviorSupplier() {
         return null;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java
index 73d85c3..90b20bb6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java
@@ -25,10 +25,12 @@
 import androidx.core.graphics.drawable.DrawableCompat;
 
 import org.chromium.base.Callback;
+import org.chromium.base.CallbackController;
 import org.chromium.base.CommandLine;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.ShortcutHelper;
@@ -83,9 +85,8 @@
     protected final TabModelSelector mTabModelSelector;
     protected final ToolbarManager mToolbarManager;
     protected final View mDecorView;
-    private final @Nullable ObservableSupplier<OverviewModeBehavior> mOverviewModeBehaviorSupplier;
+    private CallbackController mCallbackController = new CallbackController();
     private final ObservableSupplier<BookmarkBridge> mBookmarkBridgeSupplier;
-    private @Nullable Callback<OverviewModeBehavior> mOverviewModeSupplierCallback;
     private Callback<BookmarkBridge> mBookmarkBridgeSupplierCallback;
     private boolean mUpdateMenuItemVisible;
     private ShareUtils mShareUtils;
@@ -129,7 +130,7 @@
     public AppMenuPropertiesDelegateImpl(Context context, ActivityTabProvider activityTabProvider,
             MultiWindowModeStateDispatcher multiWindowModeStateDispatcher,
             TabModelSelector tabModelSelector, ToolbarManager toolbarManager, View decorView,
-            @Nullable ObservableSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier,
+            @Nullable OneshotSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier,
             ObservableSupplier<BookmarkBridge> bookmarkBridgeSupplier) {
         mContext = context;
         mIsTablet = DeviceFormFactor.isNonMultiDisplayContextOnTablet(mContext);
@@ -139,12 +140,9 @@
         mToolbarManager = toolbarManager;
         mDecorView = decorView;
 
-        mOverviewModeBehaviorSupplier = overviewModeBehaviorSupplier;
-        if (mOverviewModeBehaviorSupplier != null) {
-            mOverviewModeSupplierCallback = overviewModeBehavior -> {
-                mOverviewModeBehavior = overviewModeBehavior;
-            };
-            mOverviewModeBehaviorSupplier.addObserver(mOverviewModeSupplierCallback);
+        if (overviewModeBehaviorSupplier != null) {
+            overviewModeBehaviorSupplier.onAvailable(mCallbackController.makeCancelable(
+                    overviewModeBehavior -> { mOverviewModeBehavior = overviewModeBehavior; }));
         }
 
         mBookmarkBridgeSupplier = bookmarkBridgeSupplier;
@@ -155,10 +153,11 @@
 
     @Override
     public void destroy() {
-        if (mOverviewModeBehaviorSupplier != null) {
-            mOverviewModeBehaviorSupplier.removeObserver(mOverviewModeSupplierCallback);
-        }
         mBookmarkBridgeSupplier.removeObserver(mBookmarkBridgeSupplierCallback);
+        if (mCallbackController != null) {
+            mCallbackController.destroy();
+            mCallbackController = null;
+        }
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/ChromeNextTabPolicySupplier.java b/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/ChromeNextTabPolicySupplier.java
index 3ea752d..c5e1433 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/ChromeNextTabPolicySupplier.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/ChromeNextTabPolicySupplier.java
@@ -7,8 +7,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 
-import org.chromium.base.supplier.ObservableSupplier;
-import org.chromium.base.supplier.OneShotCallback;
+import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
 import org.chromium.chrome.browser.tabmodel.NextTabPolicy;
 import org.chromium.chrome.browser.tabmodel.NextTabPolicy.NextTabPolicySupplier;
@@ -20,10 +19,8 @@
     private OverviewModeBehavior mOverviewModeBehavior;
 
     public ChromeNextTabPolicySupplier(
-            ObservableSupplier<OverviewModeBehavior> overviewModeControllerObservableSupplier) {
-        // TODO(crbug.com/1084528): Replace this with OneShotSupplier when it is available.
-        new OneShotCallback<>(
-                overviewModeControllerObservableSupplier, this::setOverviewModeBehavior);
+            OneshotSupplier<OverviewModeBehavior> overviewModeControllerObservableSupplier) {
+        overviewModeControllerObservableSupplier.onAvailable(this::setOverviewModeBehavior);
     }
 
     private void setOverviewModeBehavior(@NonNull OverviewModeBehavior overviewModeBehavior) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
index f39cfb6..29e0db0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
@@ -22,7 +22,8 @@
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.metrics.RecordHistogram;
-import org.chromium.base.supplier.ObservableSupplierImpl;
+import org.chromium.base.supplier.OneshotSupplier;
+import org.chromium.base.supplier.OneshotSupplierImpl;
 import org.chromium.base.task.PostTask;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeApplication;
@@ -83,8 +84,8 @@
     protected @Nullable WebappActivityCoordinator mWebappActivityCoordinator;
     protected @Nullable TrustedWebActivityCoordinator mTwaCoordinator;
     protected Verifier mVerifier;
-    private ObservableSupplierImpl<OverviewModeBehavior> mOverviewModeBehaviorSupplier =
-            new ObservableSupplierImpl<>();
+    private OneshotSupplier<OverviewModeBehavior> mOverviewModeBehaviorSupplier =
+            new OneshotSupplierImpl<>();
 
     // This is to give the right package name while using the client's resources during an
     // overridePendingTransition call.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java
index 667d3e44..a2b7c8bb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java
@@ -6,6 +6,7 @@
 
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.OneShotCallback;
+import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.app.ChromeActivity;
@@ -37,7 +38,7 @@
             Supplier<CustomTabActivityNavigationController> customTabNavigationController,
             ActivityTabProvider tabProvider, ObservableSupplier<Profile> profileSupplier,
             ObservableSupplier<BookmarkBridge> bookmarkBridgeSupplier,
-            ObservableSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier,
+            OneshotSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier,
             Supplier<ContextualSearchManager> contextualSearchManagerSupplier) {
         super(activity, null, shareDelegateSupplier, tabProvider, profileSupplier,
                 bookmarkBridgeSupplier, overviewModeBehaviorSupplier,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestFactory.java
index def0a8f..6118eb0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestFactory.java
@@ -4,14 +4,11 @@
 
 package org.chromium.chrome.browser.payments;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.tabmodel.TabModel;
-import org.chromium.chrome.browser.tabmodel.TabModelUtils;
 import org.chromium.components.payments.ComponentPaymentRequestImpl;
 import org.chromium.components.payments.ErrorStrings;
 import org.chromium.components.payments.OriginSecurityChecker;
@@ -20,6 +17,7 @@
 import org.chromium.components.user_prefs.UserPrefs;
 import org.chromium.content_public.browser.FeaturePolicyFeature;
 import org.chromium.content_public.browser.RenderFrameHost;
+import org.chromium.content_public.browser.Visibility;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.WebContentsStatics;
 import org.chromium.mojo.system.MojoException;
@@ -40,7 +38,7 @@
  */
 public class PaymentRequestFactory implements InterfaceFactory<PaymentRequest> {
     // Tests can inject behaviour on future PaymentRequests via these objects.
-    public static PaymentRequestImpl.Delegate sDelegateForTest;
+    public static ComponentPaymentRequestImpl.Delegate sDelegateForTest;
 
     private final RenderFrameHost mRenderFrameHost;
 
@@ -108,8 +106,9 @@
      * Production implementation of the PaymentRequestImpl's Delegate. Gives true answers
      * about the system.
      */
-    public static class PaymentRequestDelegateImpl implements PaymentRequestImpl.Delegate {
-        private final TwaPackageManagerDelegate mPackageManager = new TwaPackageManagerDelegate();
+    public static class PaymentRequestDelegateImpl implements ComponentPaymentRequestImpl.Delegate {
+        private final TwaPackageManagerDelegate mPackageManagerDelegate =
+                new TwaPackageManagerDelegate();
         private final RenderFrameHost mRenderFrameHost;
 
         /* package */ PaymentRequestDelegateImpl(RenderFrameHost renderFrameHost) {
@@ -117,39 +116,42 @@
         }
 
         @Override
-        public boolean isOffTheRecord(WebContents webContents) {
-            // To be conservative, a request which we don't know its profile is considered
-            // off-the-record, and thus user data would not be recorded in this case.
-            ChromeActivity activity = ChromeActivity.fromWebContents(webContents);
-            if (activity == null) return true;
-            TabModel tabModel = activity.getCurrentTabModel();
-            assert tabModel != null;
-            Profile profile = tabModel.getProfile();
+        public boolean isOffTheRecord() {
+            // TODO(crbug.com/1128658): Try getting around the Profile dependency, as in C++ where
+            // we can do web_contents->GetBrowserContext()->IsOffTheRecord().
+            WebContents liveWebContents = getLiveWebContents();
+            if (liveWebContents == null) return true;
+            Profile profile = Profile.fromWebContents(liveWebContents);
             if (profile == null) return true;
             return profile.isOffTheRecord();
         }
 
         @Override
         public String getInvalidSslCertificateErrorMessage() {
-            WebContents webContents = getWebContents();
-            if (webContents == null || webContents.isDestroyed()) return null;
-            if (!OriginSecurityChecker.isSchemeCryptographic(webContents.getLastCommittedUrl())) {
+            WebContents liveWebContents = getLiveWebContents();
+            if (liveWebContents == null) return null;
+            if (!OriginSecurityChecker.isSchemeCryptographic(
+                        liveWebContents.getLastCommittedUrl())) {
                 return null;
             }
-            return SslValidityChecker.getInvalidSslCertificateErrorMessage(webContents);
+            return SslValidityChecker.getInvalidSslCertificateErrorMessage(liveWebContents);
         }
 
         @Override
-        public boolean isWebContentsActive(@NonNull ChromeActivity activity) {
-            return TabModelUtils.getCurrentWebContents(activity.getCurrentTabModel())
-                    == getWebContents();
+        public boolean isWebContentsActive() {
+            // TODO(crbug.com/1128658): Try making the WebContents inactive for instrumentation
+            // tests rather than mocking it with this method.
+            WebContents liveWebContents = getLiveWebContents();
+            return liveWebContents != null && liveWebContents.getVisibility() == Visibility.VISIBLE;
         }
 
         @Override
         public boolean prefsCanMakePayment() {
-            WebContents webContents = getWebContents();
-            return webContents != null && !webContents.isDestroyed()
-                    && UserPrefs.get(Profile.fromWebContents(webContents))
+            // TODO(crbug.com/1128658): Try replacing Profile with BrowserContextHandle, which
+            // represents a Chrome Profile or WebLayer ProfileImpl, and which UserPrefs operates on.
+            WebContents liveWebContents = getLiveWebContents();
+            return liveWebContents != null
+                    && UserPrefs.get(Profile.fromWebContents(liveWebContents))
                                .getBoolean(Pref.CAN_MAKE_PAYMENT_ENABLED);
         }
 
@@ -160,13 +162,17 @@
 
         @Override
         @Nullable
-        public String getTwaPackageName(@Nullable ChromeActivity activity) {
-            return activity != null ? mPackageManager.getTwaPackageName(activity) : null;
+        public String getTwaPackageName() {
+            WebContents liveWebContents = getLiveWebContents();
+            if (liveWebContents == null) return null;
+            ChromeActivity activity = ChromeActivity.fromWebContents(liveWebContents);
+            return activity != null ? mPackageManagerDelegate.getTwaPackageName(activity) : null;
         }
 
         @Nullable
-        private WebContents getWebContents() {
-            return WebContentsStatics.fromRenderFrameHost(mRenderFrameHost);
+        private WebContents getLiveWebContents() {
+            WebContents webContents = WebContentsStatics.fromRenderFrameHost(mRenderFrameHost);
+            return webContents != null && !webContents.isDestroyed() ? webContents : null;
         }
     }
 
@@ -192,7 +198,7 @@
             return new InvalidPaymentRequest();
         }
 
-        PaymentRequestImpl.Delegate delegate;
+        ComponentPaymentRequestImpl.Delegate delegate;
         if (sDelegateForTest != null) {
             delegate = sDelegateForTest;
         } else {
@@ -203,8 +209,8 @@
         if (webContents == null || webContents.isDestroyed()) return new InvalidPaymentRequest();
 
         return ComponentPaymentRequestImpl.createPaymentRequest(mRenderFrameHost,
-                /*isOffTheRecord=*/delegate.isOffTheRecord(webContents),
-                /*skipUiForBasicCard=*/delegate.skipUiForBasicCard(),
+                /*isOffTheRecord=*/delegate.isOffTheRecord(),
+                /*skipUiForBasicCard=*/delegate.skipUiForBasicCard(), delegate,
                 (componentPaymentRequest)
                         -> new PaymentRequestImpl(componentPaymentRequest, delegate));
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
index b259d18..6752028 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -8,7 +8,6 @@
 import android.os.Handler;
 import android.text.TextUtils;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 import androidx.collection.ArrayMap;
@@ -36,6 +35,7 @@
 import org.chromium.components.payments.CanMakePaymentQuery;
 import org.chromium.components.payments.CheckoutFunnelStep;
 import org.chromium.components.payments.ComponentPaymentRequestImpl;
+import org.chromium.components.payments.ComponentPaymentRequestImpl.Delegate;
 import org.chromium.components.payments.ErrorMessageUtil;
 import org.chromium.components.payments.ErrorStrings;
 import org.chromium.components.payments.Event;
@@ -98,43 +98,6 @@
                    PaymentResponseHelper.PaymentResponseRequesterDelegate,
                    PaymentDetailsConverter.MethodChecker, PaymentUIsManager.Delegate,
                    PaymentUIsObserver {
-    /**
-     * A delegate to ask questions about the system, that allows tests to inject behaviour without
-     * having to modify the entire system. This partially mirrors a similar C++
-     * (Content)PaymentRequestDelegate for the C++ implementation, allowing the test harness to
-     * override behaviour in both in a similar fashion.
-     */
-    public interface Delegate {
-        /**
-         * Returns whether the WebContents is currently showing an off-the-record tab. Return true
-         * if the tab profile is not accessible from the WebContents.
-         */
-        boolean isOffTheRecord(WebContents webContents);
-        /**
-         * Returns a non-null string if there is an invalid SSL certificate on the currently
-         * loaded page.
-         */
-        String getInvalidSslCertificateErrorMessage();
-        /**
-         * Returns true if the web contents that initiated the payment request is active.
-         */
-        boolean isWebContentsActive(@NonNull ChromeActivity activity);
-        /**
-         * Returns whether the preferences allow CAN_MAKE_PAYMENT.
-         */
-        boolean prefsCanMakePayment();
-        /**
-         * Returns true if the UI can be skipped for "basic-card" scenarios. This will only ever
-         * be true in tests.
-         */
-        boolean skipUiForBasicCard();
-        /**
-         * If running inside of a Trusted Web Activity, returns the package name for Trusted Web
-         * Activity. Otherwise returns an empty string or null.
-         */
-        @Nullable
-        String getTwaPackageName(@Nullable ChromeActivity activity);
-    }
 
     private static final String TAG = "PaymentRequest";
     private static boolean sIsLocalCanMakePaymentQueryQuotaEnforcedForTest;
@@ -164,11 +127,13 @@
 
     private final PaymentUIsManager mPaymentUIsManager;
 
-    private PaymentOptions mPaymentOptions;
-    private boolean mRequestShipping;
-    private boolean mRequestPayerName;
-    private boolean mRequestPayerPhone;
-    private boolean mRequestPayerEmail;
+    @Nullable
+    private final PaymentOptions mPaymentOptions;
+    private final boolean mRequestShipping;
+    private final boolean mRequestPayerName;
+    private final boolean mRequestPayerPhone;
+    private final boolean mRequestPayerEmail;
+    private final int mShippingType;
 
     private boolean mIsCanMakePaymentResponsePending;
     private boolean mIsHasEnrolledInstrumentResponsePending;
@@ -178,7 +143,6 @@
     private boolean mHasClosed;
 
     private PaymentRequestSpec mSpec;
-    private int mShippingType;
     private boolean mIsFinishedQueryingPaymentApps;
     private List<PaymentApp> mPendingApps = new ArrayList<>();
     private PaymentApp mInvokedPaymentApp;
@@ -263,6 +227,15 @@
         mWebContents = componentPaymentRequestImpl.getWebContents();
         mMerchantName = mWebContents.getTitle();
         mJourneyLogger = componentPaymentRequestImpl.getJourneyLogger();
+
+        mPaymentOptions = componentPaymentRequestImpl.getPaymentOptions();
+        assert mPaymentOptions != null;
+        mRequestShipping = mPaymentOptions.requestShipping;
+        mRequestPayerName = mPaymentOptions.requestPayerName;
+        mRequestPayerPhone = mPaymentOptions.requestPayerPhone;
+        mRequestPayerEmail = mPaymentOptions.requestPayerEmail;
+        mShippingType = mPaymentOptions.shippingType;
+
         mComponentPaymentRequestImpl = componentPaymentRequestImpl;
         mPaymentUIsManager = new PaymentUIsManager(/*delegate=*/this,
                 /*params=*/this, mWebContents, mIsOffTheRecord, mJourneyLogger, mTopLevelOrigin,
@@ -273,38 +246,10 @@
     // Implement BrowserPaymentRequest:
     @Override
     public boolean initAndValidate(PaymentMethodData[] rawMethodData, PaymentDetails details,
-            @Nullable PaymentOptions options, boolean googlePayBridgeEligible) {
+            boolean googlePayBridgeEligible) {
         assert mComponentPaymentRequestImpl != null;
-        mJourneyLogger.recordCheckoutStep(CheckoutFunnelStep.INITIATED);
-
-        mPaymentOptions = options;
-        mRequestShipping = options != null && options.requestShipping;
-        mRequestPayerName = options != null && options.requestPayerName;
-        mRequestPayerPhone = options != null && options.requestPayerPhone;
-        mRequestPayerEmail = options != null && options.requestPayerEmail;
-        mShippingType = PaymentOptionsUtils.getShippingType(options);
-
-        if (!UrlUtil.isOriginAllowedToUseWebPaymentApis(mWebContents.getLastCommittedUrl())) {
-            Log.d(TAG, ErrorStrings.PROHIBITED_ORIGIN);
-            Log.d(TAG, ErrorStrings.PROHIBITED_ORIGIN_OR_INVALID_SSL_EXPLANATION);
-            mJourneyLogger.setAborted(AbortReason.INVALID_DATA_FROM_RENDERER);
-            disconnectFromClientWithDebugMessage(ErrorStrings.PROHIBITED_ORIGIN,
-                    PaymentErrorReason.NOT_SUPPORTED_FOR_INVALID_ORIGIN_OR_SSL);
-            return false;
-        }
-
-        mJourneyLogger.setRequestedInformation(
-                mRequestShipping, mRequestPayerEmail, mRequestPayerPhone, mRequestPayerName);
-
-        String rejectShowErrorMessage = mDelegate.getInvalidSslCertificateErrorMessage();
-        if (!TextUtils.isEmpty(rejectShowErrorMessage)) {
-            Log.d(TAG, rejectShowErrorMessage);
-            Log.d(TAG, ErrorStrings.PROHIBITED_ORIGIN_OR_INVALID_SSL_EXPLANATION);
-            mJourneyLogger.setAborted(AbortReason.INVALID_DATA_FROM_RENDERER);
-            disconnectFromClientWithDebugMessage(rejectShowErrorMessage,
-                    PaymentErrorReason.NOT_SUPPORTED_FOR_INVALID_ORIGIN_OR_SSL);
-            return false;
-        }
+        assert rawMethodData != null;
+        assert details != null;
 
         boolean googlePayBridgeActivated = googlePayBridgeEligible
                 && SkipToGPayHelper.canActivateExperiment(mWebContents, rawMethodData);
@@ -320,7 +265,7 @@
 
         if (googlePayBridgeActivated) {
             PaymentMethodData data = methodData.get(MethodStrings.GOOGLE_PAY);
-            mSkipToGPayHelper = new SkipToGPayHelper(options, data.gpayBridgeData);
+            mSkipToGPayHelper = new SkipToGPayHelper(mPaymentOptions, data.gpayBridgeData);
         }
 
         mQueryForQuota = new HashMap<>(methodData);
@@ -396,7 +341,7 @@
     /** @return Whether the UI was built. */
     private boolean buildUI(ChromeActivity activity) {
         String error = mPaymentUIsManager.buildPaymentRequestUI(activity,
-                /*isWebContentsActive=*/mDelegate.isWebContentsActive(activity),
+                /*isWebContentsActive=*/mDelegate.isWebContentsActive(),
                 /*waitForUpdatedDetails=*/mWaitForUpdatedDetails);
         if (error != null) {
             mJourneyLogger.setNotShown(NotShownReason.OTHER);
@@ -1129,15 +1074,15 @@
         disconnectFromClientWithDebugMessage(ErrorStrings.USER_CANCELLED);
     }
 
+    private void disconnectFromClientWithDebugMessage(String debugMessage) {
+        disconnectFromClientWithDebugMessage(debugMessage, PaymentErrorReason.USER_CANCEL);
+    }
+
     // Implement BrowserPaymentRequest:
     // This method is not supposed to be used outside this class and
     // ComponentPaymentRequestImpl.
     @Override
-    public void disconnectFromClientWithDebugMessage(String debugMessage) {
-        disconnectFromClientWithDebugMessage(debugMessage, PaymentErrorReason.USER_CANCEL);
-    }
-
-    private void disconnectFromClientWithDebugMessage(String debugMessage, int reason) {
+    public void disconnectFromClientWithDebugMessage(String debugMessage, int reason) {
         Log.d(TAG, debugMessage);
         if (mComponentPaymentRequestImpl != null) {
             mComponentPaymentRequestImpl.onError(reason, debugMessage);
@@ -1441,7 +1386,7 @@
     @Override
     @Nullable
     public String getTwaPackageName() {
-        return mDelegate.getTwaPackageName(ChromeActivity.fromWebContents(mWebContents));
+        return mDelegate.getTwaPackageName();
     }
 
     // PaymentAppFactoryDelegate implementation.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentUIsManager.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentUIsManager.java
index 303d230f..451639e9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentUIsManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentUIsManager.java
@@ -575,7 +575,7 @@
                             false /* includeNameInLabel */));
         }
 
-        if (PaymentOptionsUtils.requestShipping(mParams.getPaymentOptions())) {
+        if (mParams.getPaymentOptions().requestShipping) {
             boolean haveCompleteShippingAddress = false;
             for (int i = 0; i < mAutofillProfiles.size(); i++) {
                 if (AutofillAddress.checkAddressCompletionStatus(
@@ -591,9 +591,8 @@
         PaymentOptions options = mParams.getPaymentOptions();
         if (PaymentOptionsUtils.requestAnyContactInformation(mParams.getPaymentOptions())) {
             // Do not persist changes on disk in OffTheRecord mode.
-            mContactEditor = new ContactEditor(PaymentOptionsUtils.requestPayerName(options),
-                    PaymentOptionsUtils.requestPayerPhone(options),
-                    PaymentOptionsUtils.requestPayerEmail(options),
+            mContactEditor = new ContactEditor(options.requestPayerName, options.requestPayerPhone,
+                    options.requestPayerEmail,
                     /*saveToDisk=*/!mIsOffTheRecord);
             boolean haveCompleteContactInfo = false;
             for (int i = 0; i < getAutofillProfiles().size(); i++) {
@@ -885,7 +884,7 @@
 
     /** Implements {@link PaymentRequestUI.Client.shouldShowShippingSection}. */
     public boolean shouldShowShippingSection() {
-        if (!PaymentOptionsUtils.requestShipping(mParams.getPaymentOptions())) return false;
+        if (!mParams.getPaymentOptions().requestShipping) return false;
 
         if (mPaymentMethodsSection == null) return true;
 
@@ -898,16 +897,15 @@
         PaymentApp selectedApp = (mPaymentMethodsSection == null)
                 ? null
                 : (PaymentApp) mPaymentMethodsSection.getSelectedItem();
-        org.chromium.payments.mojom.PaymentOptions options = mParams.getPaymentOptions();
-        if (PaymentOptionsUtils.requestPayerName(options)
-                && (selectedApp == null || !selectedApp.handlesPayerName())) {
+        PaymentOptions options = mParams.getPaymentOptions();
+        if (options.requestPayerName && (selectedApp == null || !selectedApp.handlesPayerName())) {
             return true;
         }
-        if (PaymentOptionsUtils.requestPayerPhone(options)
+        if (options.requestPayerPhone
                 && (selectedApp == null || !selectedApp.handlesPayerPhone())) {
             return true;
         }
-        if (PaymentOptionsUtils.requestPayerEmail(options)
+        if (options.requestPayerEmail
                 && (selectedApp == null || !selectedApp.handlesPayerEmail())) {
             return true;
         }
@@ -1139,8 +1137,7 @@
                 mMerchantSupportsAutofillCards, !PaymentPreferencesUtil.isPaymentCompleteOnce(),
                 mMerchantName, mTopLevelOriginFormattedForDisplay,
                 SecurityStateModel.getSecurityLevelForWebContents(mWebContents),
-                new ShippingStrings(
-                        PaymentOptionsUtils.getShippingType(mParams.getPaymentOptions())),
+                new ShippingStrings(mParams.getPaymentOptions().shippingType),
                 mPaymentUisShowStateReconciler, Profile.fromWebContents(mWebContents));
         activity.getLifecycleDispatcher().register(
                 mPaymentRequestUI); // registered as a PauseResumeWithNativeObserver
@@ -1160,7 +1157,7 @@
                 });
 
         // Add the callback to change the label of shipping addresses depending on the focus.
-        if (PaymentOptionsUtils.requestShipping(mParams.getPaymentOptions())) {
+        if (mParams.getPaymentOptions().requestShipping) {
             setShippingAddressSectionFocusChangedObserverForPaymentRequestUI();
         }
 
@@ -1402,13 +1399,10 @@
         int sectionSize = mPaymentMethodsSection.getSize();
         for (int i = 0; i < sectionSize; i++) {
             PaymentApp app = (PaymentApp) mPaymentMethodsSection.getItem(i);
-            if ((!PaymentOptionsUtils.requestShipping(mParams.getPaymentOptions())
-                        || app.handlesShippingAddress())
-                    && (!PaymentOptionsUtils.requestPayerName(mParams.getPaymentOptions())
-                            || app.handlesPayerName())
-                    && (!PaymentOptionsUtils.requestPayerPhone(mParams.getPaymentOptions())
-                            || app.handlesPayerPhone())
-                    && (!PaymentOptionsUtils.requestPayerEmail(mParams.getPaymentOptions())
+            if ((!mParams.getPaymentOptions().requestShipping || app.handlesShippingAddress())
+                    && (!mParams.getPaymentOptions().requestPayerName || app.handlesPayerName())
+                    && (!mParams.getPaymentOptions().requestPayerPhone || app.handlesPayerPhone())
+                    && (!mParams.getPaymentOptions().requestPayerEmail
                             || app.handlesPayerEmail())) {
                 // There is more than one available app that can provide all merchant requested
                 // information information.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegate.java
index 082fcb0..b75c9ab 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegate.java
@@ -8,6 +8,7 @@
 import android.view.View;
 
 import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.app.appmenu.AppMenuIconRowFooter;
@@ -37,7 +38,7 @@
             MultiWindowModeStateDispatcher multiWindowModeStateDispatcher,
             TabModelSelector tabModelSelector, ToolbarManager toolbarManager, View decorView,
             AppMenuDelegate appMenuDelegate,
-            ObservableSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier,
+            OneshotSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier,
             ObservableSupplier<BookmarkBridge> bookmarkBridgeSupplier) {
         super(context, activityTabProvider, multiWindowModeStateDispatcher, tabModelSelector,
                 toolbarManager, decorView, overviewModeBehaviorSupplier, bookmarkBridgeSupplier);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedNavigationBarColorController.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedNavigationBarColorController.java
index 7917a36..0e1b3848 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedNavigationBarColorController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedNavigationBarColorController.java
@@ -16,9 +16,10 @@
 import androidx.annotation.Nullable;
 
 import org.chromium.base.ApiCompatibilityUtils;
-import org.chromium.base.Callback;
+import org.chromium.base.CallbackController;
 import org.chromium.base.MathUtils;
 import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.compositor.layouts.EmptyOverviewModeObserver;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
@@ -48,10 +49,9 @@
     // May be null if we return from the constructor early. Otherwise will be set.
     private final @Nullable TabModelSelector mTabModelSelector;
     private final @Nullable TabModelSelectorObserver mTabModelSelectorObserver;
-    private @Nullable ObservableSupplier<OverviewModeBehavior> mOverviewModeBehaviorSupplier;
-    private @Nullable Callback<OverviewModeBehavior> mOverviewModeSupplierCallback;
     private @Nullable OverviewModeBehavior mOverviewModeBehavior;
     private @Nullable OverviewModeObserver mOverviewModeObserver;
+    private CallbackController mCallbackController = new CallbackController();
 
     private boolean mUseLightNavigation;
     private boolean mOverviewModeHiding;
@@ -66,7 +66,7 @@
      *         {@link OverviewModeBehavior} associated with the containing activity.
      */
     TabbedNavigationBarColorController(Window window, TabModelSelector tabModelSelector,
-            ObservableSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier) {
+            OneshotSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier) {
         assert Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1;
 
         mWindow = window;
@@ -93,9 +93,8 @@
         };
         mTabModelSelector.addObserver(mTabModelSelectorObserver);
 
-        mOverviewModeBehaviorSupplier = overviewModeBehaviorSupplier;
-        mOverviewModeSupplierCallback = this::setOverviewModeBehavior;
-        mOverviewModeBehaviorSupplier.addObserver(mOverviewModeSupplierCallback);
+        overviewModeBehaviorSupplier.onAvailable(
+                mCallbackController.makeCancelable(this::setOverviewModeBehavior));
 
         // TODO(https://crbug.com/806054): Observe tab loads to restrict black bottom nav to
         // incognito NTP.
@@ -110,12 +109,13 @@
      */
     public void destroy() {
         if (mTabModelSelector != null) mTabModelSelector.removeObserver(mTabModelSelectorObserver);
-        if (mOverviewModeBehaviorSupplier != null) {
-            mOverviewModeBehaviorSupplier.removeObserver(mOverviewModeSupplierCallback);
-        }
         if (mOverviewModeBehavior != null) {
             mOverviewModeBehavior.removeOverviewModeObserver(mOverviewModeObserver);
         }
+        if (mCallbackController != null) {
+            mCallbackController.destroy();
+            mCallbackController = null;
+        }
         VrModuleProvider.unregisterVrModeObserver(this);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
index 60c7f801..e484362 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
@@ -14,6 +14,7 @@
 import org.chromium.base.TraceEvent;
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplierImpl;
+import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ActivityTabProvider;
@@ -101,7 +102,7 @@
             ObservableSupplierImpl<EphemeralTabCoordinator> ephemeralTabCoordinatorSupplier,
             ObservableSupplier<Profile> profileSupplier,
             ObservableSupplier<BookmarkBridge> bookmarkBridgeSupplier,
-            ObservableSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier,
+            OneshotSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier,
             Supplier<ContextualSearchManager> contextualSearchManagerSupplier) {
         super(activity, onOmniboxFocusChangedListener, shareDelegateSupplier, tabProvider,
                 profileSupplier, bookmarkBridgeSupplier, overviewModeBehaviorSupplier,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedSystemUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedSystemUiCoordinator.java
index 4c0674fd..69ae2ca 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedSystemUiCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedSystemUiCoordinator.java
@@ -10,6 +10,7 @@
 import androidx.annotation.Nullable;
 
 import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 
@@ -32,7 +33,7 @@
      *         {@link OverviewModeBehavior} associated with the containing activity.
      */
     public TabbedSystemUiCoordinator(Window window, TabModelSelector tabModelSelector,
-            @Nullable ObservableSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier) {
+            @Nullable OneshotSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier) {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
             assert overviewModeBehaviorSupplier != null;
             mNavigationBarColorController = new TabbedNavigationBarColorController(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index c31f64c0..6c71f07 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -21,8 +21,10 @@
 import androidx.appcompat.app.ActionBar;
 
 import org.chromium.base.Callback;
+import org.chromium.base.CallbackController;
 import org.chromium.base.TraceEvent;
 import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ActivityTabProvider;
@@ -142,8 +144,8 @@
     private OverviewModeObserver mOverviewModeObserver;
 
     private OverviewModeBehavior mOverviewModeBehavior;
-    private Callback<OverviewModeBehavior> mOverviewModeBehaviorSupplierObserver;
-    private ObservableSupplier<OverviewModeBehavior> mOverviewModeBehaviorSupplier;
+    private OneshotSupplier<OverviewModeBehavior> mOverviewModeBehaviorSupplier;
+    private CallbackController mCallbackController = new CallbackController();
 
     private SceneChangeObserver mSceneChangeObserver;
     private final ActionBarDelegate mActionBarDelegate;
@@ -219,7 +221,7 @@
             FindToolbarManager findToolbarManager, ObservableSupplier<Profile> profileSupplier,
             ObservableSupplier<BookmarkBridge> bookmarkBridgeSupplier,
             @Nullable Supplier<Boolean> canAnimateNativeBrowserControls,
-            ObservableSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier,
+            OneshotSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier,
             ObservableSupplier<AppMenuCoordinator> appMenuCoordinatorSupplier,
             boolean shouldShowUpdateBadge) {
         TraceEvent.begin("ToolbarManager.ToolbarManager");
@@ -248,8 +250,8 @@
         mProfileSupplier.addObserver(mProfileSupplierObserver);
 
         mOverviewModeBehaviorSupplier = overviewModeBehaviorSupplier;
-        mOverviewModeBehaviorSupplierObserver = this::setOverviewModeBehavior;
-        mOverviewModeBehaviorSupplier.addObserver(mOverviewModeBehaviorSupplierObserver);
+        mOverviewModeBehaviorSupplier.onAvailable(
+                mCallbackController.makeCancelable(this::setOverviewModeBehavior));
 
         mComponentCallbacks = new ComponentCallbacks() {
             @Override
@@ -823,9 +825,7 @@
         }
 
         if (mOverviewModeBehaviorSupplier != null) {
-            mOverviewModeBehaviorSupplier.removeObserver(mOverviewModeBehaviorSupplierObserver);
             mOverviewModeBehaviorSupplier = null;
-            mOverviewModeBehaviorSupplierObserver = null;
         }
 
         if (mLayoutManager != null) {
@@ -890,6 +890,11 @@
             mMenuButtonCoordinator = null;
         }
 
+        if (mCallbackController != null) {
+            mCallbackController.destroy();
+            mCallbackController = null;
+        }
+
         mActivity.unregisterComponentCallbacks(mComponentCallbacks);
         mComponentCallbacks = null;
         ChromeAccessibilityUtil.get().removeObserver(this);
@@ -1233,13 +1238,8 @@
     }
 
     private void setOverviewModeBehavior(OverviewModeBehavior overviewModeBehavior) {
-        assert overviewModeBehavior != null;
-        assert mOverviewModeBehavior
-                == null
-            : "TODO(https://crbug.com/1084528): the overview mode manager should set at most once.";
         mOverviewModeBehavior = overviewModeBehavior;
         mOverviewModeBehavior.addOverviewModeObserver(mOverviewModeObserver);
-
         mAppThemeColorProvider.setOverviewModeBehavior(mOverviewModeBehavior);
         mLocationBarModel.setOverviewModeBehavior(mOverviewModeBehavior);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomControlsCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomControlsCoordinator.java
index 0613149..91aa315 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomControlsCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomControlsCoordinator.java
@@ -14,6 +14,7 @@
 
 import org.chromium.base.Callback;
 import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ActivityTabProvider;
@@ -85,7 +86,7 @@
             ObservableSupplier<AppMenuButtonHelper> menuButtonHelperSupplier,
             Supplier<Boolean> showStartSurfaceCallable, Runnable openHomepageAction,
             Callback<Integer> setUrlBarFocusAction,
-            ObservableSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier,
+            OneshotSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier,
             ScrimCoordinator scrimCoordinator) {
         final ScrollingBottomViewResourceFrameLayout root =
                 (ScrollingBottomViewResourceFrameLayout) stub.inflate();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarCoordinator.java
new file mode 100644
index 0000000..f4be501
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarCoordinator.java
@@ -0,0 +1,279 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.toolbar.bottom;
+
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnLongClickListener;
+import android.view.ViewGroup;
+import android.view.ViewStub;
+
+import org.chromium.base.Callback;
+import org.chromium.base.metrics.RecordUserAction;
+import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.base.supplier.ObservableSupplierImpl;
+import org.chromium.base.supplier.OneShotCallback;
+import org.chromium.base.supplier.OneshotSupplier;
+import org.chromium.base.supplier.Supplier;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ActivityTabProvider;
+import org.chromium.chrome.browser.ThemeColorProvider;
+import org.chromium.chrome.browser.compositor.layouts.EmptyOverviewModeObserver;
+import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
+import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior.OverviewModeObserver;
+import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
+import org.chromium.chrome.browser.omnibox.LocationBar;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.share.ShareDelegate;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tasks.ReturnToChromeExperimentsUtil;
+import org.chromium.chrome.browser.toolbar.IncognitoStateProvider;
+import org.chromium.chrome.browser.toolbar.TabCountProvider;
+import org.chromium.chrome.browser.ui.appmenu.AppMenuButtonHelper;
+import org.chromium.components.feature_engagement.EventConstants;
+import org.chromium.components.feature_engagement.Tracker;
+
+/**
+ * The root coordinator for the bottom toolbar. It has two sub-components: the browsing mode bottom
+ * toolbar and the tab switcher mode bottom toolbar.
+ */
+class BottomToolbarCoordinator {
+    /** The browsing mode bottom toolbar component */
+    private final BrowsingModeBottomToolbarCoordinator mBrowsingModeCoordinator;
+
+    /** The tab switcher mode bottom toolbar component */
+    private TabSwitcherBottomToolbarCoordinator mTabSwitcherModeCoordinator;
+
+    /** The tab switcher mode bottom toolbar stub that will be inflated when native is ready. */
+    private final ViewStub mTabSwitcherModeStub;
+
+    /** A provider that notifies components when the theme color changes.*/
+    private final ThemeColorProvider mThemeColorProvider;
+
+    /** The overview mode manager. */
+    private OverviewModeBehavior mOverviewModeBehavior;
+    private OverviewModeObserver mOverviewModeObserver;
+
+    /** The activity tab provider. */
+    private ActivityTabProvider mTabProvider;
+
+    private final ObservableSupplier<ShareDelegate> mShareDelegateSupplier;
+    private final Callback<ShareDelegate> mShareDelegateSupplierCallback;
+    private ObservableSupplierImpl<OnClickListener> mShareButtonListenerSupplier =
+            new ObservableSupplierImpl<>();
+    private final Supplier<Boolean> mShowStartSurfaceCallable;
+    private AppMenuButtonHelper mMenuButtonHelper;
+    private OneshotSupplier<OverviewModeBehavior> mOverviewModeBehaviorSupplier;
+
+    /**
+     * Build the coordinator that manages the bottom toolbar.
+     * @param stub The bottom toolbar {@link ViewStub} to inflate.
+     * @param tabProvider The {@link ActivityTabProvider} used for making the IPH.
+     * @param themeColorProvider The {@link ThemeColorProvider} for the bottom toolbar.
+     * @param shareDelegateSupplier The supplier for the {@link ShareDelegate} the bottom controls
+     *         should use to share content.
+     * @param showStartSurfaceCallable The action that opens the start surface, returning true if
+     * the start surface is shown.
+     * @param openHomepageAction The action that opens the homepage.
+     * @param setUrlBarFocusAction The function that sets Url bar focus. The first argument is
+     * @param overviewModeBehaviorSupplier Supplier for the overview mode manager.
+     * @param menuButtonHelperSupplier
+     */
+    BottomToolbarCoordinator(ViewStub stub, ActivityTabProvider tabProvider,
+            OnLongClickListener tabsSwitcherLongClickListner, ThemeColorProvider themeColorProvider,
+            ObservableSupplier<ShareDelegate> shareDelegateSupplier,
+            Supplier<Boolean> showStartSurfaceCallable, Runnable openHomepageAction,
+            Callback<Integer> setUrlBarFocusAction,
+            ObservableSupplier<AppMenuButtonHelper> menuButtonHelperSupplier,
+            OneshotSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier) {
+        View root = stub.inflate();
+
+        mOverviewModeBehaviorSupplier = overviewModeBehaviorSupplier;
+
+        mShowStartSurfaceCallable = showStartSurfaceCallable;
+        final OnClickListener homeButtonListener = v -> {
+            recordBottomToolbarUseForIPH();
+            openHomepageAction.run();
+        };
+
+        final OnClickListener searchAcceleratorListener = v -> {
+            recordBottomToolbarUseForIPH();
+            RecordUserAction.record("MobileToolbarOmniboxAcceleratorTap");
+
+            // Only switch to HomePage when overview is showing.
+            if (mOverviewModeBehavior != null && mOverviewModeBehavior.overviewVisible()) {
+                mShowStartSurfaceCallable.get();
+            }
+            setUrlBarFocusAction.onResult(LocationBar.OmniboxFocusReason.ACCELERATOR_TAP);
+        };
+
+        mBrowsingModeCoordinator = new BrowsingModeBottomToolbarCoordinator(root, tabProvider,
+                homeButtonListener, searchAcceleratorListener, mShareButtonListenerSupplier,
+                tabsSwitcherLongClickListner, mOverviewModeBehaviorSupplier);
+
+        mTabSwitcherModeStub = root.findViewById(R.id.bottom_toolbar_tab_switcher_mode_stub);
+
+        mThemeColorProvider = themeColorProvider;
+        mTabProvider = tabProvider;
+
+        mShareDelegateSupplier = shareDelegateSupplier;
+        mShareDelegateSupplierCallback = this::onShareDelegateAvailable;
+        mShareDelegateSupplier.addObserver(mShareDelegateSupplierCallback);
+
+        new OneShotCallback<>(menuButtonHelperSupplier, (menuButtonHelper) -> {
+            if (menuButtonHelper != null) {
+                mMenuButtonHelper = menuButtonHelper;
+                mMenuButtonHelper.setOnClickRunnable(() -> recordBottomToolbarUseForIPH());
+            }
+        });
+    }
+
+    /**
+     * Initialize the bottom toolbar with the components that had native initialization
+     * dependencies.
+     * <p>
+     * Calling this must occur after the native library have completely loaded.
+     * @param tabSwitcherListener An {@link OnClickListener} that is triggered when the
+     *                            tab switcher button is clicked.
+     * @param newTabClickListener An {@link OnClickListener} that is triggered when the
+     *                            new tab button is clicked.
+     * @param tabCountProvider Updates the tab count number in the tab switcher button and in the
+     *                         incognito toggle tab layout.
+     * @param incognitoStateProvider Notifies components when incognito mode is entered or exited.
+     * @param topToolbarRoot The root {@link ViewGroup} of the top toolbar.
+     * @param closeAllTabsAction The runnable that closes all tabs in the current tab model.
+     */
+    void initializeWithNative(OnClickListener tabSwitcherListener,
+            OnClickListener newTabClickListener, TabCountProvider tabCountProvider,
+            IncognitoStateProvider incognitoStateProvider, ViewGroup topToolbarRoot,
+            Runnable closeAllTabsAction) {
+        final OnClickListener closeTabsClickListener = v -> {
+            recordBottomToolbarUseForIPH();
+            final boolean isIncognito = incognitoStateProvider.isIncognitoSelected();
+            if (isIncognito) {
+                RecordUserAction.record("MobileToolbarCloseAllIncognitoTabsButtonTap");
+            } else {
+                RecordUserAction.record("MobileToolbarCloseAllRegularTabsButtonTap");
+            }
+
+            closeAllTabsAction.run();
+        };
+
+        newTabClickListener = wrapBottomToolbarClickListenerForIPH(newTabClickListener);
+        tabSwitcherListener = wrapBottomToolbarClickListenerForIPH(tabSwitcherListener);
+        mBrowsingModeCoordinator.initializeWithNative(newTabClickListener, tabSwitcherListener,
+                mMenuButtonHelper, tabCountProvider, mThemeColorProvider, incognitoStateProvider);
+        mTabSwitcherModeCoordinator = new TabSwitcherBottomToolbarCoordinator(mTabSwitcherModeStub,
+                topToolbarRoot, incognitoStateProvider, mThemeColorProvider, newTabClickListener,
+                closeTabsClickListener, mMenuButtonHelper, tabCountProvider);
+
+        // Do not change bottom bar if StartSurface Single Pane is enabled and HomePage is not
+        // customized.
+        if (!ReturnToChromeExperimentsUtil.shouldShowStartSurfaceAsTheHomePage()
+                && BottomToolbarVariationManager.shouldBottomToolbarBeVisibleInOverviewMode()) {
+            mOverviewModeObserver = new EmptyOverviewModeObserver() {
+                @Override
+                public void onOverviewModeStartedShowing(boolean showToolbar) {
+                    mBrowsingModeCoordinator.getSearchAccelerator().setEnabled(false);
+                    if (BottomToolbarVariationManager.isShareButtonOnBottom()) {
+                        mBrowsingModeCoordinator.getShareButton().setEnabled(false);
+                    }
+                    if (BottomToolbarVariationManager.isHomeButtonOnBottom()) {
+                        mBrowsingModeCoordinator.getHomeButton().setEnabled(false);
+                    }
+                }
+
+                @Override
+                public void onOverviewModeStartedHiding(
+                        boolean showToolbar, boolean delayAnimation) {
+                    mBrowsingModeCoordinator.getSearchAccelerator().setEnabled(true);
+                    if (BottomToolbarVariationManager.isShareButtonOnBottom()) {
+                        mBrowsingModeCoordinator.getShareButton().updateButtonEnabledState(
+                                mTabProvider.get());
+                    }
+                    if (BottomToolbarVariationManager.isHomeButtonOnBottom()) {
+                        mBrowsingModeCoordinator.getHomeButton().updateButtonEnabledState(
+                                mTabProvider.get());
+                    }
+                }
+            };
+            mOverviewModeBehaviorSupplier.onAvailable(this::setOverviewModeBehavior);
+        }
+    }
+
+    /**
+     * @param isVisible Whether the bottom toolbar is visible.
+     */
+    void setBottomToolbarVisible(boolean isVisible) {
+        if (mTabSwitcherModeCoordinator != null) {
+            mTabSwitcherModeCoordinator.showToolbarOnTop(!isVisible);
+        }
+        mBrowsingModeCoordinator.onVisibilityChanged(isVisible);
+    }
+
+    /**
+     * Clean up any state when the bottom toolbar is destroyed.
+     */
+    void destroy() {
+        mBrowsingModeCoordinator.destroy();
+        if (mTabSwitcherModeCoordinator != null) {
+            mTabSwitcherModeCoordinator.destroy();
+            mTabSwitcherModeCoordinator = null;
+        }
+        if (mOverviewModeBehavior != null) {
+            mOverviewModeBehavior.removeOverviewModeObserver(mOverviewModeObserver);
+            mOverviewModeBehavior = null;
+        }
+        if (mOverviewModeBehaviorSupplier != null) {
+            mOverviewModeBehaviorSupplier = null;
+        }
+        mThemeColorProvider.destroy();
+        mShareDelegateSupplier.removeObserver(mShareDelegateSupplierCallback);
+    }
+
+    private void onShareDelegateAvailable(ShareDelegate shareDelegate) {
+        final OnClickListener shareButtonListener = v -> {
+            if (BottomToolbarVariationManager.isShareButtonOnBottom()) {
+                recordBottomToolbarUseForIPH();
+                RecordUserAction.record("MobileBottomToolbarShareButton");
+            }
+
+            Tab tab = mTabProvider.get();
+            shareDelegate.share(tab, /*shareDirectly=*/false);
+        };
+
+        mShareButtonListenerSupplier.set(shareButtonListener);
+    }
+
+    private void setOverviewModeBehavior(OverviewModeBehavior overviewModeBehavior) {
+        assert overviewModeBehavior != null;
+        assert mOverviewModeBehavior
+                == null
+            : "TODO(https://crbug.com/1084528): the overview mode manager should set at most once.";
+        mOverviewModeBehavior = overviewModeBehavior;
+        mOverviewModeBehavior.addOverviewModeObserver(mOverviewModeObserver);
+    }
+
+    /** Record that the bottom toolbar was used for IPH reasons. */
+    private void recordBottomToolbarUseForIPH() {
+        Tab tab = mTabProvider.get();
+        if (tab == null) return;
+
+        Tracker tracker =
+                TrackerFactory.getTrackerForProfile(Profile.fromWebContents(tab.getWebContents()));
+        tracker.notifyEvent(EventConstants.CHROME_DUET_USED_BOTTOM_TOOLBAR);
+    }
+
+    /**
+     * Add bottom toolbar IPH tracking to an existing click listener.
+     * @param listener The listener to add bottom toolbar tracking to.
+     */
+    private OnClickListener wrapBottomToolbarClickListenerForIPH(OnClickListener listener) {
+        return (v) -> {
+            recordBottomToolbarUseForIPH();
+            listener.onClick(v);
+        };
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BrowsingModeBottomToolbarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BrowsingModeBottomToolbarCoordinator.java
new file mode 100644
index 0000000..3b5c982
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BrowsingModeBottomToolbarCoordinator.java
@@ -0,0 +1,251 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.toolbar.bottom;
+
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnLongClickListener;
+
+import org.chromium.base.Callback;
+import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.base.supplier.OneshotSupplier;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ActivityTabProvider;
+import org.chromium.chrome.browser.ThemeColorProvider;
+import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tab.TabUtils;
+import org.chromium.chrome.browser.tasks.ReturnToChromeExperimentsUtil;
+import org.chromium.chrome.browser.toolbar.HomeButton;
+import org.chromium.chrome.browser.toolbar.IncognitoStateProvider;
+import org.chromium.chrome.browser.toolbar.TabCountProvider;
+import org.chromium.chrome.browser.toolbar.TabSwitcherButtonCoordinator;
+import org.chromium.chrome.browser.toolbar.TabSwitcherButtonView;
+import org.chromium.chrome.browser.ui.appmenu.AppMenuButtonHelper;
+import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
+
+/**
+ * The coordinator for the browsing mode bottom toolbar. This class has two primary components,
+ * an Android view that handles user actions and a composited texture that draws when the controls
+ * are being scrolled off-screen. The Android version does not draw unless the controls offset is 0.
+ */
+public class BrowsingModeBottomToolbarCoordinator {
+    /** The mediator that handles events from outside the browsing mode bottom toolbar. */
+    private final BrowsingModeBottomToolbarMediator mMediator;
+
+    /** The home button that lives in the bottom toolbar. */
+    private final HomeButton mHomeButton;
+
+    /** The share button that lives in the bottom toolbar. */
+    private final ShareButton mShareButton;
+
+    /** The new tab button that lives in the bottom toolbar. */
+    private final BottomToolbarNewTabButton mNewTabButton;
+
+    /** The search accelerator that lives in the bottom toolbar. */
+    private final SearchAccelerator mSearchAccelerator;
+
+    /** The tab switcher button component that lives in the bottom toolbar. */
+    private final TabSwitcherButtonCoordinator mTabSwitcherButtonCoordinator;
+
+    /** The tab switcher button view that lives in the bottom toolbar. */
+    private final TabSwitcherButtonView mTabSwitcherButtonView;
+
+    /** The view group that includes all views shown on browsing mode */
+    private final BrowsingModeBottomToolbarLinearLayout mToolbarRoot;
+
+    /** The model for the browsing mode bottom toolbar that holds all of its state. */
+    private final BrowsingModeBottomToolbarModel mModel;
+
+    /** The callback to be exectured when the share button on click listener is available. */
+    private Callback<OnClickListener> mShareButtonListenerSupplierCallback;
+
+    /** The supplier for the share button on click listener. */
+    private ObservableSupplier<OnClickListener> mShareButtonListenerSupplier;
+
+    /** The activity tab provider that used for making the IPH. */
+    private final ActivityTabProvider mTabProvider;
+
+    /**
+     * Build the coordinator that manages the browsing mode bottom toolbar.
+     * @param root The root {@link View} for locating the views to inflate.
+     * @param tabProvider The {@link ActivityTabProvider} used for making the IPH.
+     * @param homeButtonListener The {@link OnClickListener} for the home button.
+     * @param searchAcceleratorListener The {@link OnClickListener} for the search accelerator.
+     * @param shareButtonListener The {@link OnClickListener} for the share button.
+     * @param overviewModeBehaviorSupplier Supplier for the overview mode manager.
+     */
+    BrowsingModeBottomToolbarCoordinator(View root, ActivityTabProvider tabProvider,
+            OnClickListener homeButtonListener, OnClickListener searchAcceleratorListener,
+            ObservableSupplier<OnClickListener> shareButtonListenerSupplier,
+            OnLongClickListener tabSwitcherLongClickListener,
+            OneshotSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier) {
+        mModel = new BrowsingModeBottomToolbarModel();
+        mToolbarRoot = root.findViewById(R.id.bottom_toolbar_browsing);
+        mTabProvider = tabProvider;
+
+        PropertyModelChangeProcessor.create(
+                mModel, mToolbarRoot, new BrowsingModeBottomToolbarViewBinder());
+
+        mMediator = new BrowsingModeBottomToolbarMediator(mModel);
+
+        mHomeButton = mToolbarRoot.findViewById(R.id.bottom_home_button);
+        mHomeButton.setOnClickListener(homeButtonListener);
+        mHomeButton.setActivityTabProvider(mTabProvider);
+
+        mNewTabButton = mToolbarRoot.findViewById(R.id.bottom_new_tab_button);
+
+        mShareButton = mToolbarRoot.findViewById(R.id.bottom_share_button);
+
+        mSearchAccelerator = mToolbarRoot.findViewById(R.id.search_accelerator);
+        mSearchAccelerator.setOnClickListener(searchAcceleratorListener);
+
+        // TODO(amaralp): Make this adhere to MVC framework.
+        mTabSwitcherButtonView = mToolbarRoot.findViewById(R.id.bottom_tab_switcher_button);
+        mTabSwitcherButtonCoordinator = new TabSwitcherButtonCoordinator(mTabSwitcherButtonView);
+
+        mTabSwitcherButtonView.setOnLongClickListener(tabSwitcherLongClickListener);
+        if (BottomToolbarVariationManager.isNewTabButtonOnBottom()) {
+            mNewTabButton.setVisibility(View.VISIBLE);
+        }
+        if (BottomToolbarVariationManager.isHomeButtonOnBottom()) {
+            mHomeButton.setVisibility(View.VISIBLE);
+        }
+
+        if (BottomToolbarVariationManager.isTabSwitcherOnBottom()) {
+            mTabSwitcherButtonView.setVisibility(View.VISIBLE);
+        }
+        if (BottomToolbarVariationManager.isShareButtonOnBottom()) {
+            mShareButton.setVisibility(View.VISIBLE);
+            mShareButtonListenerSupplierCallback = shareButtonListener -> {
+                mShareButton.setOnClickListener(shareButtonListener);
+            };
+            mShareButtonListenerSupplier = shareButtonListenerSupplier;
+            mShareButton.setActivityTabProvider(mTabProvider);
+            mShareButtonListenerSupplier.addObserver(mShareButtonListenerSupplierCallback);
+        }
+
+        overviewModeBehaviorSupplier.onAvailable(this::setOverviewModeBehavior);
+    }
+
+    /**
+     * @param isVisible Whether the bottom toolbar is visible.
+     */
+    void onVisibilityChanged(boolean isVisible) {
+        if (isVisible) return;
+        Tab tab = mTabProvider.get();
+        if (tab != null) mMediator.dismissIPH(TabUtils.getActivity(tab));
+    }
+
+    /**
+     * Initialize the bottom toolbar with the components that had native initialization
+     * dependencies.
+     * <p>
+     * Calling this must occur after the native library have completely loaded.
+     * @param tabSwitcherListener An {@link OnClickListener} that is triggered when the
+     *                            tab switcher button is clicked.
+     * @param menuButtonHelper An {@link AppMenuButtonHelper} that is triggered when the
+     *                         menu button is clicked.
+     * @param tabCountProvider Updates the tab count number in the tab switcher button.
+     * @param themeColorProvider Notifies components when theme color changes.
+     * @param incognitoStateProvider Notifies components when incognito state changes.
+     */
+    void initializeWithNative(OnClickListener newTabListener, OnClickListener tabSwitcherListener,
+            AppMenuButtonHelper menuButtonHelper, TabCountProvider tabCountProvider,
+            ThemeColorProvider themeColorProvider, IncognitoStateProvider incognitoStateProvider) {
+        mMediator.setThemeColorProvider(themeColorProvider);
+        if (BottomToolbarVariationManager.isNewTabButtonOnBottom()) {
+            mNewTabButton.setOnClickListener(newTabListener);
+            mNewTabButton.setThemeColorProvider(themeColorProvider);
+            mNewTabButton.setIncognitoStateProvider(incognitoStateProvider);
+        }
+        if (BottomToolbarVariationManager.isHomeButtonOnBottom()) {
+            mHomeButton.setThemeColorProvider(themeColorProvider);
+        }
+
+        if (BottomToolbarVariationManager.isShareButtonOnBottom()) {
+            mShareButton.setThemeColorProvider(themeColorProvider);
+        }
+
+        mSearchAccelerator.setThemeColorProvider(themeColorProvider);
+        mSearchAccelerator.setIncognitoStateProvider(incognitoStateProvider);
+
+        if (BottomToolbarVariationManager.isTabSwitcherOnBottom()) {
+            mTabSwitcherButtonCoordinator.setTabSwitcherListener(tabSwitcherListener);
+            mTabSwitcherButtonCoordinator.setThemeColorProvider(themeColorProvider);
+            mTabSwitcherButtonCoordinator.setTabCountProvider(tabCountProvider);
+        }
+    }
+
+    private void setOverviewModeBehavior(OverviewModeBehavior overviewModeBehavior) {
+        assert overviewModeBehavior != null;
+
+        // If StartSurface is HomePage, BrowsingModeBottomToolbar is shown in browsing mode and in
+        // overview mode. We need to pass the OverviewModeBehavior to the buttons so they are
+        // disabled based on the overview state.
+        if (ReturnToChromeExperimentsUtil.shouldShowStartSurfaceAsTheHomePage()) {
+            mShareButton.setOverviewModeBehavior(overviewModeBehavior);
+            mTabSwitcherButtonCoordinator.setOverviewModeBehavior(overviewModeBehavior);
+            mHomeButton.setOverviewModeBehavior(overviewModeBehavior);
+        }
+    }
+
+    /**
+     * @param enabled Whether to disable click events on the bottom toolbar. Setting true can also
+     *                prevent from all click events on toolbar and all children views on toolbar.
+     */
+    void setTouchEnabled(boolean enabled) {
+        mToolbarRoot.setTouchEnabled(enabled);
+    }
+
+    /**
+     * @param visible Whether to hide the tab switcher bottom toolbar
+     */
+    void setVisible(boolean visible) {
+        mModel.set(BrowsingModeBottomToolbarModel.IS_VISIBLE, visible);
+    }
+
+    /**
+     * @return The browsing mode bottom toolbar's share button.
+     */
+    ShareButton getShareButton() {
+        return mShareButton;
+    }
+
+    /**
+     * @return The browsing mode bottom toolbar's tab switcher button.
+     */
+    TabSwitcherButtonView getTabSwitcherButtonView() {
+        return mTabSwitcherButtonView;
+    }
+
+    /**
+     * @return The browsing mode bottom toolbar's search button.
+     */
+    SearchAccelerator getSearchAccelerator() {
+        return mSearchAccelerator;
+    }
+
+    /**
+     * @return The browsing mode bottom toolbar's home button.
+     */
+    HomeButton getHomeButton() {
+        return mHomeButton;
+    }
+
+    /**
+     * Clean up any state when the browsing mode bottom toolbar is destroyed.
+     */
+    public void destroy() {
+        if (mShareButtonListenerSupplier != null) {
+            mShareButtonListenerSupplier.removeObserver(mShareButtonListenerSupplierCallback);
+        }
+        mMediator.destroy();
+        mHomeButton.destroy();
+        mShareButton.destroy();
+        mSearchAccelerator.destroy();
+        mTabSwitcherButtonCoordinator.destroy();
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarCoordinator.java
index dd551dbeba..bc76e1da 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarCoordinator.java
@@ -11,9 +11,9 @@
 
 import androidx.annotation.VisibleForTesting;
 
-import org.chromium.base.Callback;
+import org.chromium.base.CallbackController;
 import org.chromium.base.library_loader.LibraryLoader;
-import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ThemeColorProvider;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
@@ -49,19 +49,17 @@
     private ThemeColorProvider mThemeColorProvider;
     private OnClickListener mTabSwitcherClickListener;
     private OnLongClickListener mTabSwitcherLongClickListener;
-    private Callback<OverviewModeBehavior> mOverviewModeBehaviorSupplierObserver;
-    private ObservableSupplier<OverviewModeBehavior> mOverviewModeBehaviorSupplier;
     private MenuButtonCoordinator mMenuButtonCoordinator;
+    private CallbackController mCallbackController = new CallbackController();
 
     StartSurfaceToolbarCoordinator(ViewStub startSurfaceToolbarStub,
             IdentityDiscController identityDiscController, UserEducationHelper userEducationHelper,
-            ObservableSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier,
+            OneshotSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier,
             ThemeColorProvider provider, MenuButtonCoordinator menuButtonCoordinator) {
         mStub = startSurfaceToolbarStub;
 
-        mOverviewModeBehaviorSupplier = overviewModeBehaviorSupplier;
-        mOverviewModeBehaviorSupplierObserver = this::setOverviewModeBehavior;
-        mOverviewModeBehaviorSupplier.addObserver(mOverviewModeBehaviorSupplierObserver);
+        overviewModeBehaviorSupplier.onAvailable(
+                mCallbackController.makeCancelable(this::setOverviewModeBehavior));
 
         mPropertyModel =
                 new PropertyModel.Builder(StartSurfaceToolbarProperties.ALL_KEYS)
@@ -100,11 +98,6 @@
      * Cleans up any code and removes observers as necessary.
      */
     void destroy() {
-        if (mOverviewModeBehaviorSupplier != null) {
-            mOverviewModeBehaviorSupplier.removeObserver(mOverviewModeBehaviorSupplierObserver);
-            mOverviewModeBehaviorSupplier = null;
-            mOverviewModeBehaviorSupplierObserver = null;
-        }
         mToolbarMediator.destroy();
         if (mIncognitoSwitchCoordinator != null) mIncognitoSwitchCoordinator.destroy();
         if (mTabSwitcherButtonCoordinator != null) mTabSwitcherButtonCoordinator.destroy();
@@ -112,6 +105,10 @@
             mMenuButtonCoordinator.destroy();
             mMenuButtonCoordinator = null;
         }
+        if (mCallbackController != null) {
+            mCallbackController.destroy();
+            mCallbackController = null;
+        }
         mTabSwitcherButtonCoordinator = null;
         mTabSwitcherButtonView = null;
         mTabCountProvider = null;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
index fe28253..75b38ce 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
@@ -15,9 +15,10 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
-import org.chromium.base.Callback;
+import org.chromium.base.CallbackController;
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.OneShotCallback;
+import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ThemeColorProvider;
 import org.chromium.chrome.browser.compositor.Invalidator;
@@ -78,10 +79,9 @@
     private final IdentityDiscController mIdentityDiscController;
     private OptionalBrowsingModeButtonController mOptionalButtonController;
 
-    private Callback<OverviewModeBehavior> mOverviewModeBehaviorSupplierObserver;
-    private ObservableSupplier<OverviewModeBehavior> mOverviewModeBehaviorSupplier;
     private MenuButtonCoordinator mMenuButtonCoordinator;
     private ObservableSupplier<AppMenuButtonHelper> mAppMenuButtonHelperSupplier;
+    private CallbackController mCallbackController = new CallbackController();
 
     private HomepageManager.HomepageStateListener mHomepageStateListener =
             new HomepageManager.HomepageStateListener() {
@@ -108,7 +108,7 @@
             ToolbarLayout toolbarLayout, IdentityDiscController identityDiscController,
             ToolbarDataProvider toolbarDataProvider, ToolbarTabController tabController,
             UserEducationHelper userEducationHelper, List<ButtonDataProvider> buttonDataProviders,
-            ObservableSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier,
+            OneshotSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier,
             ThemeColorProvider normalThemeColorProvider,
             ThemeColorProvider overviewThemeColorProvider,
             MenuButtonCoordinator browsingModeMenuButtonCoordinator,
@@ -120,15 +120,14 @@
         mOptionalButtonController = new OptionalBrowsingModeButtonController(buttonDataProviders,
                 userEducationHelper, mToolbarLayout, () -> toolbarDataProvider.getTab());
 
-        mOverviewModeBehaviorSupplier = overviewModeBehaviorSupplier;
-        mOverviewModeBehaviorSupplierObserver = this::setOverviewModeBehavior;
-        mOverviewModeBehaviorSupplier.addObserver(mOverviewModeBehaviorSupplierObserver);
+        overviewModeBehaviorSupplier.onAvailable(
+                mCallbackController.makeCancelable(this::setOverviewModeBehavior));
 
         if (mToolbarLayout instanceof ToolbarPhone) {
             if (StartSurfaceConfiguration.isStartSurfaceEnabled()) {
                 mStartSurfaceToolbarCoordinator = new StartSurfaceToolbarCoordinator(
                         controlContainer.getRootView().findViewById(R.id.tab_switcher_toolbar_stub),
-                        mIdentityDiscController, userEducationHelper, mOverviewModeBehaviorSupplier,
+                        mIdentityDiscController, userEducationHelper, overviewModeBehaviorSupplier,
                         overviewThemeColorProvider, startSurfaceMenuButtonCoordinator);
             } else {
                 mTabSwitcherModeCoordinatorPhone = new TabSwitcherModeTTCoordinatorPhone(
@@ -232,11 +231,6 @@
      */
     public void destroy() {
         HomepageManager.getInstance().removeListener(mHomepageStateListener);
-        if (mOverviewModeBehaviorSupplier != null) {
-            mOverviewModeBehaviorSupplier.removeObserver(mOverviewModeBehaviorSupplierObserver);
-            mOverviewModeBehaviorSupplier = null;
-            mOverviewModeBehaviorSupplierObserver = null;
-        }
         mToolbarLayout.destroy();
         if (mTabSwitcherModeCoordinatorPhone != null) {
             mTabSwitcherModeCoordinatorPhone.destroy();
@@ -244,6 +238,11 @@
             mStartSurfaceToolbarCoordinator.destroy();
         }
 
+        if (mCallbackController != null) {
+            mCallbackController.destroy();
+            mCallbackController = null;
+        }
+
         if (mOptionalButtonController != null) {
             mOptionalButtonController.destroy();
             mOptionalButtonController = null;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java
index fbecdc2..fbe4118 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java
@@ -21,6 +21,7 @@
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplierImpl;
+import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ActivityTabProvider;
@@ -114,8 +115,7 @@
     private OverlayPanelManager.OverlayPanelManagerObserver mOverlayPanelManagerObserver;
 
     private OverviewModeBehavior mOverviewModeBehavior;
-    private Callback<OverviewModeBehavior> mOverviewModeBehaviorSupplierObserver;
-    private ObservableSupplier<OverviewModeBehavior> mOverviewModeBehaviorSupplier;
+    private OneshotSupplier<OverviewModeBehavior> mOverviewModeBehaviorSupplier;
     private OverviewModeBehavior.OverviewModeObserver mOverviewModeObserver;
 
     /** A means of providing the theme color to different features. */
@@ -168,7 +168,7 @@
             ObservableSupplier<ShareDelegate> shareDelegateSupplier,
             ActivityTabProvider tabProvider, ObservableSupplier<Profile> profileSupplier,
             ObservableSupplier<BookmarkBridge> bookmarkBridgeSupplier,
-            ObservableSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier,
+            OneshotSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier,
             Supplier<ContextualSearchManager> contextualSearchManagerSupplier) {
         mCallbackController = new CallbackController();
         mActivity = activity;
@@ -195,8 +195,8 @@
         mOmniboxFocusStateSupplier.set(false);
 
         mOverviewModeBehaviorSupplier = overviewModeBehaviorSupplier;
-        mOverviewModeBehaviorSupplierObserver = this::setOverviewModeBehavior;
-        mOverviewModeBehaviorSupplier.addObserver(mOverviewModeBehaviorSupplierObserver);
+        mOverviewModeBehaviorSupplier.onAvailable(
+                mCallbackController.makeCancelable(this::setOverviewModeBehavior));
     }
 
     // TODO(pnoland, crbug.com/865801): remove this in favor of wiring it directly.
@@ -221,9 +221,7 @@
         }
 
         if (mOverviewModeBehaviorSupplier != null) {
-            mOverviewModeBehaviorSupplier.removeObserver(mOverviewModeBehaviorSupplierObserver);
             mOverviewModeBehaviorSupplier = null;
-            mOverviewModeBehaviorSupplierObserver = null;
         }
 
         if (mToolbarManager != null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java b/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java
index cb0f24d3..fccd03e7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java
@@ -14,8 +14,8 @@
 import androidx.annotation.Nullable;
 
 import org.chromium.base.ApiCompatibilityUtils;
-import org.chromium.base.Callback;
-import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.base.CallbackController;
+import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.app.ChromeActivity;
@@ -79,8 +79,7 @@
     private final @ColorInt int mIncognitoDefaultThemeColor;
 
     private @Nullable TabModelSelector mTabModelSelector;
-    private ObservableSupplier<OverviewModeBehavior> mOverviewModeBehaviorSupplier;
-    private Callback<OverviewModeBehavior> mOverviewModeBehaviorSupplierObserver;
+    private CallbackController mCallbackController = new CallbackController();
     private @Nullable OverviewModeBehavior.OverviewModeObserver mOverviewModeObserver;
     private @Nullable Tab mCurrentTab;
     private boolean mIsInOverviewMode;
@@ -176,34 +175,28 @@
             }
         };
 
-        mOverviewModeBehaviorSupplier = chromeActivity.getOverviewModeBehaviorSupplier();
+        OneshotSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier =
+                chromeActivity.getOverviewModeBehaviorSupplier();
+        if (overviewModeBehaviorSupplier != null) {
+            overviewModeBehaviorSupplier.onAvailable(
+                    mCallbackController.makeCancelable(overviewModeBehavior -> {
+                        assert overviewModeBehavior != null;
+                        mOverviewModeBehavior = overviewModeBehavior;
+                        mOverviewModeObserver = new EmptyOverviewModeObserver() {
+                            @Override
+                            public void onOverviewModeStartedShowing(boolean showToolbar) {
+                                mIsInOverviewMode = true;
+                                updateStatusBarColor();
+                            }
 
-        if (mOverviewModeBehaviorSupplier != null) {
-            mOverviewModeBehaviorSupplierObserver = new Callback<OverviewModeBehavior>() {
-                @Override
-                public void onResult(OverviewModeBehavior overviewModeBehavior) {
-                    assert overviewModeBehavior != null;
-                    mOverviewModeBehavior = overviewModeBehavior;
-                    mOverviewModeObserver = new EmptyOverviewModeObserver() {
-                        @Override
-                        public void onOverviewModeStartedShowing(boolean showToolbar) {
-                            mIsInOverviewMode = true;
-                            updateStatusBarColor();
-                        }
-
-                        @Override
-                        public void onOverviewModeFinishedHiding() {
-                            mIsInOverviewMode = false;
-                            updateStatusBarColor();
-                        }
-                    };
-                    mOverviewModeBehavior.addOverviewModeObserver(mOverviewModeObserver);
-                    // TODO(crbug.com/1084528): Replace with OneShotSupplier when it is available.
-                    mOverviewModeBehaviorSupplier.removeObserver(this);
-                    mOverviewModeBehaviorSupplier = null;
-                }
-            };
-            mOverviewModeBehaviorSupplier.addObserver(mOverviewModeBehaviorSupplierObserver);
+                            @Override
+                            public void onOverviewModeFinishedHiding() {
+                                mIsInOverviewMode = false;
+                                updateStatusBarColor();
+                            }
+                        };
+                        mOverviewModeBehavior.addOverviewModeObserver(mOverviewModeObserver);
+                    }));
         }
 
         chromeActivity.getLifecycleDispatcher().register(this);
@@ -213,15 +206,16 @@
     @Override
     public void destroy() {
         mStatusBarColorTabObserver.destroy();
-        if (mOverviewModeBehaviorSupplier != null) {
-            mOverviewModeBehaviorSupplier.removeObserver(mOverviewModeBehaviorSupplierObserver);
-        }
         if (mOverviewModeBehavior != null) {
             mOverviewModeBehavior.removeOverviewModeObserver(mOverviewModeObserver);
         }
         if (mTabModelSelector != null) {
             mTabModelSelector.removeObserver(mTabModelSelectorObserver);
         }
+        if (mCallbackController != null) {
+            mCallbackController.destroy();
+            mCallbackController = null;
+        }
     }
 
     // TopToolbarCoordinator.UrlExpansionObserver implementation.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ui/tablet/emptybackground/EmptyBackgroundViewWrapper.java b/chrome/android/java/src/org/chromium/chrome/browser/ui/tablet/emptybackground/EmptyBackgroundViewWrapper.java
index f58adb09..0ad1410 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ui/tablet/emptybackground/EmptyBackgroundViewWrapper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ui/tablet/emptybackground/EmptyBackgroundViewWrapper.java
@@ -11,8 +11,9 @@
 
 import androidx.annotation.Nullable;
 
-import org.chromium.base.Callback;
+import org.chromium.base.CallbackController;
 import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
 import org.chromium.chrome.browser.tab.Tab;
@@ -40,8 +41,7 @@
     private final TabModelSelectorObserver mTabModelSelectorObserver;
     private final SnackbarManager mSnackbarManager;
 
-    private final ObservableSupplier<OverviewModeBehavior> mOverviewModeBehaviorSupplier;
-    private final Callback<OverviewModeBehavior> mOverviewModeSupplierCallback;
+    CallbackController mCallbackController = new CallbackController();
     private @Nullable OverviewModeBehavior mOverviewModeBehavior;
 
     private EmptyBackgroundViewTablet mBackgroundView;
@@ -62,17 +62,15 @@
     public EmptyBackgroundViewWrapper(TabModelSelector selector, TabCreator tabCreator,
             Activity activity, @Nullable AppMenuHandler menuHandler,
             SnackbarManager snackbarManager,
-            ObservableSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier) {
+            OneshotSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier) {
         mActivity = activity;
         mMenuHandler = menuHandler;
         mTabModelSelector = selector;
         mTabCreator = tabCreator;
         mSnackbarManager = snackbarManager;
 
-        mOverviewModeBehaviorSupplier = overviewModeBehaviorSupplier;
-        mOverviewModeSupplierCallback =
-                overviewModeBehavior -> mOverviewModeBehavior = overviewModeBehavior;
-        mOverviewModeBehaviorSupplier.addObserver(mOverviewModeSupplierCallback);
+        overviewModeBehaviorSupplier.onAvailable(mCallbackController.makeCancelable(
+                overviewModeBehavior -> mOverviewModeBehavior = overviewModeBehavior));
 
         mTabModelObserver = new TabModelObserver() {
             @Override
@@ -118,7 +116,10 @@
      * Called when the containing activity is being destroyed.
      */
     public void destroy() {
-        mOverviewModeBehaviorSupplier.removeObserver(mOverviewModeSupplierCallback);
+        if (mCallbackController != null) {
+            mCallbackController.destroy();
+            mCallbackController = null;
+        }
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/undo_tab_close_snackbar/UndoBarController.java b/chrome/android/java/src/org/chromium/chrome/browser/undo_tab_close_snackbar/UndoBarController.java
index a51ebfd..847989c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/undo_tab_close_snackbar/UndoBarController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/undo_tab_close_snackbar/UndoBarController.java
@@ -8,9 +8,8 @@
 
 import androidx.annotation.Nullable;
 
-import org.chromium.base.Callback;
-import org.chromium.base.supplier.ObservableSupplier;
-import org.chromium.base.supplier.ObservableSupplierImpl;
+import org.chromium.base.CallbackController;
+import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
@@ -49,8 +48,7 @@
     private final TabModelObserver mTabModelObserver;
     private final SnackbarManager.SnackbarManageable mSnackbarManagable;
     private final Context mContext;
-    private ObservableSupplier<OverviewModeBehavior> mOverviewModeBehaviorSupplier;
-    private Callback<OverviewModeBehavior> mOverviewModeBehaviorSupplierObserver;
+    private CallbackController mCallbackController = new CallbackController();
     private OverviewModeBehavior mOverviewModeBehavior;
 
     /**
@@ -65,25 +63,13 @@
      */
     public UndoBarController(Context context, TabModelSelector selector,
             SnackbarManager.SnackbarManageable snackbarManageable,
-            ObservableSupplierImpl<OverviewModeBehavior> overviewModeBehaviorSupplier,
+            OneshotSupplier<OverviewModeBehavior> overviewModeBehaviorSupplier,
             @Nullable Supplier<Boolean> dialogVisibilitySupplier) {
         mSnackbarManagable = snackbarManageable;
         mTabModelSelector = selector;
         mContext = context;
-        mOverviewModeBehaviorSupplier = overviewModeBehaviorSupplier;
-        mOverviewModeBehaviorSupplierObserver = new Callback<OverviewModeBehavior>() {
-            @Override
-            public void onResult(OverviewModeBehavior overviewModeBehavior) {
-                assert overviewModeBehavior != null;
-
-                mOverviewModeBehavior = overviewModeBehavior;
-                // TODO(crbug.com/1084528): Replace with OneShotSupplier when it is available.
-                mOverviewModeBehaviorSupplier.removeObserver(this);
-                mOverviewModeBehaviorSupplier = null;
-            }
-        };
-
-        overviewModeBehaviorSupplier.addObserver(mOverviewModeBehaviorSupplierObserver);
+        overviewModeBehaviorSupplier.onAvailable(mCallbackController.makeCancelable(
+                overviewModeBehavior -> mOverviewModeBehavior = overviewModeBehavior));
 
         mTabModelObserver = new TabModelObserver() {
             /**
@@ -172,8 +158,9 @@
     public void destroy() {
         TabModel model = mTabModelSelector.getModel(false);
         if (model != null) model.removeObserver(mTabModelObserver);
-        if (mOverviewModeBehaviorSupplier != null) {
-            mOverviewModeBehaviorSupplier.removeObserver(mOverviewModeBehaviorSupplierObserver);
+        if (mCallbackController != null) {
+            mCallbackController.destroy();
+            mCallbackController = null;
         }
     }
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateUnitTest.java
index 8e7942c..634e97f 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateUnitTest.java
@@ -28,6 +28,7 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.supplier.ObservableSupplierImpl;
+import org.chromium.base.supplier.OneshotSupplierImpl;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ActivityTabProvider;
@@ -83,8 +84,8 @@
     @Mock
     private UpdateMenuItemHelper mUpdateMenuItemHelper;
 
-    private ObservableSupplierImpl<OverviewModeBehavior> mOverviewModeSupplier =
-            new ObservableSupplierImpl<>();
+    private OneshotSupplierImpl<OverviewModeBehavior> mOverviewModeSupplier =
+            new OneshotSupplierImpl<>();
     private ObservableSupplierImpl<BookmarkBridge> mBookmarkBridgeSupplier =
             new ObservableSupplierImpl<>();
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java
index 7d7edc1..3be1ed5 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java
@@ -27,6 +27,7 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.supplier.ObservableSupplierImpl;
+import org.chromium.base.supplier.OneshotSupplierImpl;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.JniMocker;
 import org.chromium.chrome.R;
@@ -92,8 +93,8 @@
     @Mock
     Profile mProfileMock;
 
-    private ObservableSupplierImpl<OverviewModeBehavior> mOverviewModeSupplier =
-            new ObservableSupplierImpl<>();
+    private OneshotSupplierImpl<OverviewModeBehavior> mOverviewModeSupplier =
+            new OneshotSupplierImpl<>();
     private ObservableSupplierImpl<BookmarkBridge> mBookmarkBridgeSupplier =
             new ObservableSupplierImpl<>();
 
diff --git a/chrome/app/chrome_command_ids.h b/chrome/app/chrome_command_ids.h
index da2209a..652201d 100644
--- a/chrome/app/chrome_command_ids.h
+++ b/chrome/app/chrome_command_ids.h
@@ -298,6 +298,7 @@
 #define IDC_CONTENT_CONTEXT_REDO 50145
 #define IDC_CONTENT_CONTEXT_SELECTALL 50146
 #define IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE 50147
+#define IDC_CONTENT_CONTEXT_COPYLINKTOTEXT 50148
 // Other items.
 #define IDC_CONTENT_CONTEXT_TRANSLATE 50150
 #define IDC_CONTENT_CONTEXT_INSPECTELEMENT 50151
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index fafa22a4..3eb046c3 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -4579,9 +4579,6 @@
   <message name="IDS_CROSTINI_TERMINAL_STATUS_INSTALL_IMAGE_LOADER" desc="Text shown in the crostini terminal when it is checking whether the virtual machine component is installed">
     Checking the virtual machine
   </message>
-  <message name="IDS_CROSTINI_TERMINAL_STATUS_START_CONCIERGE" desc="Text shown in the crostini terminal when it is starting the VM controller">
-    Starting the virtual machine controller
-  </message>
   <message name="IDS_CROSTINI_TERMINAL_STATUS_CREATE_DISK_IMAGE" desc="Text shown in the crostini terminal when it is checking whether the VM image is installed">
     Checking the virtual machine image
   </message>
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_TERMINAL_STATUS_START_CONCIERGE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_TERMINAL_STATUS_START_CONCIERGE.png.sha1
deleted file mode 100644
index c2dd105..0000000
--- a/chrome/app/chromeos_strings_grdp/IDS_CROSTINI_TERMINAL_STATUS_START_CONCIERGE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-d5dfef986211c69d831ac4515dd9defdc772cfc3
\ No newline at end of file
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 84f6b77..e897344 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -583,6 +583,10 @@
             Copy link te&amp;xt
           </message>
 
+          <message name="IDS_CONTENT_CONTEXT_COPYLINKTOTEXT" desc="The name of the Copy Link to Text command in the content area context menu">
+            Copy link to text
+          </message>
+
           <message name="IDS_CONTENT_CONTEXT_SAVEIMAGEAS" desc="The name of the Save Image As command in the content area context menu">
             Sa&amp;ve image as...
           </message>
@@ -801,6 +805,10 @@
             Copy Link Te&amp;xt
           </message>
 
+          <message name="IDS_CONTENT_CONTEXT_COPYLINKTOTEXT" desc="In Title Case: The name of the Copy Link to Text command in the content area context menu">
+            Copy Link to Text
+          </message>
+
           <message name="IDS_CONTENT_CONTEXT_SAVEIMAGEAS" desc="In Title Case: The name of the Save Image As command in the content area context menu">
             Sa&amp;ve Image As...
           </message>
diff --git a/chrome/app/generated_resources_grd/IDS_CONTENT_CONTEXT_COPYLINKTOTEXT.png.sha1 b/chrome/app/generated_resources_grd/IDS_CONTENT_CONTEXT_COPYLINKTOTEXT.png.sha1
new file mode 100644
index 0000000..571c8f1
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_CONTENT_CONTEXT_COPYLINKTOTEXT.png.sha1
@@ -0,0 +1 @@
+b7ed24ed91c5178f15b28dbb72da30e5fd53db0c
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 4f93a2c1..0d8dc11 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -370,7 +370,6 @@
     "data_use_measurement/chrome_data_use_measurement.h",
     "defaults.cc",
     "defaults.h",
-    "device_oauth2_token_store.h",
     "dom_distiller/dom_distiller_service_factory.cc",
     "dom_distiller/dom_distiller_service_factory.h",
     "dom_distiller/lazy_dom_distiller_service.cc",
@@ -847,7 +846,6 @@
     "navigation_predictor/navigation_predictor_renderer_warmup_client.h",
     "navigation_predictor/search_engine_preconnector.cc",
     "navigation_predictor/search_engine_preconnector.h",
-    "net/chrome_cookie_notification_details.h",
     "net/chrome_mojo_proxy_resolver_factory.cc",
     "net/chrome_mojo_proxy_resolver_factory.h",
     "net/chrome_network_delegate.cc",
@@ -949,7 +947,6 @@
     "ntp_tiles/chrome_popular_sites_factory.h",
     "offline_items_collection/offline_content_aggregator_factory.cc",
     "offline_items_collection/offline_content_aggregator_factory.h",
-    "omnibox/common/omnibox_features.h",
     "optimization_guide/blink/blink_optimization_guide_feature_flag_helper.cc",
     "optimization_guide/blink/blink_optimization_guide_feature_flag_helper.h",
     "optimization_guide/blink/blink_optimization_guide_inquirer.cc",
@@ -1046,6 +1043,8 @@
     "page_load_metrics/observers/tab_restore_page_load_metrics_observer.h",
     "page_load_metrics/observers/third_party_metrics_observer.cc",
     "page_load_metrics/observers/third_party_metrics_observer.h",
+    "page_load_metrics/observers/translate_page_load_metrics_observer.cc",
+    "page_load_metrics/observers/translate_page_load_metrics_observer.h",
     "page_load_metrics/observers/ukm_page_load_metrics_observer.cc",
     "page_load_metrics/observers/ukm_page_load_metrics_observer.h",
     "page_load_metrics/page_load_metrics_initialize.cc",
@@ -1824,13 +1823,6 @@
   libs = []
   ldflags = []
 
-  if (is_mac) {
-    sources += [
-      "geolocation/geolocation_system_permission_mac.h",
-      "geolocation/geolocation_system_permission_mac.mm",
-    ]
-  }
-
   allow_circular_includes_from = [
     "//chrome/browser/ui",
     "//chrome/browser/ui/webui/bluetooth_internals",
@@ -1846,7 +1838,9 @@
     "//components/account_id",
     "//components/autofill/core/browser",
     "//components/nacl/common:buildflags",
+    "//components/page_info",
     "//components/payments/core",
+    "//components/payments/core:error_strings",
     "//components/policy/proto",
     "//components/safe_browsing:buildflags",
     "//components/services/storage/public/mojom",
@@ -1862,6 +1856,7 @@
     ":active_use_util",
     ":availability_protos",
     ":buildflags",
+    ":dev_ui_browser_resources_grit",
     ":expired_flags_list",
     ":ntp_background_proto",
     ":permissions_proto",
@@ -1871,7 +1866,7 @@
     ":unexpire_flags",
     "//base:i18n",
     "//base/allocator:buildflags",
-    "//base/util/memory_pressure:memory_pressure",
+    "//base/util/memory_pressure",
     "//base/util/values:values_util",
     "//build:branding_buildflags",
     "//build:chromeos_buildflags",
@@ -1879,9 +1874,12 @@
     "//chrome:extra_resources",
     "//chrome:resources",
     "//chrome:strings",
+    "//chrome/app:command_ids",
     "//chrome/app/resources:platform_locale_settings",
     "//chrome/app/theme:theme_resources",
+    "//chrome/app/vector_icons",
     "//chrome/browser/devtools",
+    "//chrome/browser/engagement:mojo_bindings",
     "//chrome/browser/image_decoder",
     "//chrome/browser/media:media_engagement_preload_proto",
     "//chrome/browser/media:mojo_bindings",
@@ -1891,25 +1889,44 @@
     "//chrome/browser/media/router",
     "//chrome/browser/metrics:expired_histograms_array",
     "//chrome/browser/metrics/variations:chrome_ui_string_overrider_factory",
+    "//chrome/browser/nearby_sharing/common",
     "//chrome/browser/net:probe_message_proto",
     "//chrome/browser/notifications",
+    "//chrome/browser/notifications/scheduler:factory",
+    "//chrome/browser/notifications/scheduler/public",
+    "//chrome/browser/policy:path_parser",
     "//chrome/browser/privacy_budget",
     "//chrome/browser/profiling_host",
+    "//chrome/browser/promo_browser_command:mojo_bindings",
     "//chrome/browser/push_messaging:budget_proto",
     "//chrome/browser/reputation:proto",
     "//chrome/browser/resource_coordinator:mojo_bindings",
     "//chrome/browser/resource_coordinator:tab_manager_features",
     "//chrome/browser/safe_browsing",
+    "//chrome/browser/safe_browsing:advanced_protection",
+    "//chrome/browser/safe_browsing:url_lookup_service_factory",
     "//chrome/browser/sharing:buildflags",
     "//chrome/browser/sharing/proto",
     "//chrome/browser/storage_access_api:permissions",
     "//chrome/browser/thumbnail",
     "//chrome/browser/touch_to_fill",
     "//chrome/browser/ui",
+    "//chrome/browser/ui/webui/app_management:mojo_bindings",
     "//chrome/browser/ui/webui/bluetooth_internals",
+    "//chrome/browser/ui/webui/bluetooth_internals:mojo_bindings",
+    "//chrome/browser/ui/webui/downloads:mojo_bindings",
+    "//chrome/browser/ui/webui/internals/web_app:mojo_bindings",
+    "//chrome/browser/ui/webui/interventions_internals:mojo_bindings",
+    "//chrome/browser/ui/webui/new_tab_page:mojo_bindings",
+    "//chrome/browser/ui/webui/omnibox:mojo_bindings",
+    "//chrome/browser/ui/webui/read_later:mojo_bindings",
+    "//chrome/browser/ui/webui/reset_password:mojo_bindings",
+    "//chrome/browser/ui/webui/tab_search:mojo_bindings",
+    "//chrome/browser/ui/webui/usb_internals:mojo_bindings",
     "//chrome/browser/updates/announcement_notification",
     "//chrome/browser/video_tutorials",
     "//chrome/common:channel_info",
+    "//chrome/common:version_header",
     "//chrome/common/net",
     "//chrome/common/performance_manager/mojom",
     "//chrome/installer/util:with_no_strings",
@@ -1919,7 +1936,8 @@
     "//components/autofill/content/browser",
     "//components/autofill/core/browser",
     "//components/background_task_scheduler",
-    "//components/blocklist/opt_out_blocklist:opt_out_blocklist",
+    "//components/blocked_content",
+    "//components/blocklist/opt_out_blocklist",
     "//components/blocklist/opt_out_blocklist/sql:opt_out_blocklist_sql",
     "//components/bookmarks/browser",
     "//components/bookmarks/managed",
@@ -1939,9 +1957,12 @@
     "//components/consent_auditor",
     "//components/content_capture/browser",
     "//components/content_settings/browser",
+    "//components/content_settings/common:mojom",
     "//components/content_settings/core/browser",
     "//components/content_settings/core/common",
+    "//components/contextual_search:buildflags",
     "//components/contextual_search/content:browser",
+    "//components/contextual_search/content/common/mojom",
     "//components/contextual_search/core:browser",
     "//components/cookie_config",
     "//components/country_codes",
@@ -1953,6 +1974,7 @@
     "//components/dom_distiller/content/common/mojom",
     "//components/domain_reliability",
     "//components/download/content/factory",
+    "//components/download/content/public",
     "//components/download/database",
     "//components/download/public/background_service:public",
     "//components/embedder_support",
@@ -1960,12 +1982,18 @@
     "//components/enterprise",
     "//components/enterprise/common/proto:connectors_proto",
     "//components/error_page/common",
+    "//components/error_page/content/browser",
     "//components/favicon/content",
     "//components/favicon/core",
     "//components/favicon/core:history_implementation",
     "//components/favicon_base",
     "//components/feature_engagement",
     "//components/federated_learning",
+    "//components/feed:buildflags",
+    "//components/feed/content:feed_content",
+    "//components/feed/core/common:feed_core_common",
+    "//components/feed/core/shared_prefs:feed_shared_prefs",
+    "//components/feed/core/v2:feed_core_v2",
     "//components/filename_generation",
     "//components/find_in_page",
     "//components/flags_ui",
@@ -1981,11 +2009,15 @@
     "//components/javascript_dialogs",
     "//components/keyed_service/content",
     "//components/language/content/browser",
+    "//components/language/content/browser/ulp_language_code_locator",
     "//components/language/core/browser",
     "//components/language/core/common",
+    "//components/language_usage_metrics",
     "//components/leveldb_proto",
     "//components/lookalikes/core",
+    "//components/lookalikes/core:features",
     "//components/metrics:call_stack_profile_collector",
+    "//components/metrics:call_stack_profile_params",
     "//components/metrics:component_metrics",
     "//components/metrics:content",
     "//components/metrics:demographic_metrics_provider",
@@ -2001,14 +2033,23 @@
     "//components/ntp_tiles",
     "//components/offline_items_collection/core",
     "//components/offline_pages/buildflags",
+    "//components/offline_pages/core",
+    "//components/offline_pages/core/background:background_offliner",
+    "//components/offline_pages/core/prefetch",
+    "//components/offline_pages/core/request_header",
     "//components/omnibox/browser",
+    "//components/onc",
+    "//components/open_from_clipboard",
     "//components/optimization_guide",
     "//components/os_crypt",
+    "//components/page_load_metrics/browser",
+    "//components/page_load_metrics/common",
     "//components/paint_preview/buildflags",
     "//components/paint_preview/features",
     "//components/password_manager/content/browser",
     "//components/password_manager/core/browser",
     "//components/password_manager/core/common",
+    "//components/payments/content:utils",
     "//components/payments/core",
     "//components/performance_manager",
     "//components/permissions",
@@ -2024,15 +2065,27 @@
     "//components/prerender/common:mojo_bindings",
     "//components/previews/content",
     "//components/previews/core",
+    "//components/printing/browser",
     "//components/profile_metrics",
     "//components/proxy_config",
     "//components/query_parser",
     "//components/query_tiles",
     "//components/rappor",
+    "//components/reading_list/core",
     "//components/renderer_context_menu",
     "//components/resources",
+    "//components/safe_browsing/content/browser",
+    "//components/safe_browsing/content/password_protection",
+    "//components/safe_browsing/core:download_file_types_proto",
+    "//components/safe_browsing/core:features",
+    "//components/safe_browsing/core:file_type_policies",
     "//components/safe_browsing/core:public",
+    "//components/safe_browsing/core/browser",
+    "//components/safe_browsing/core/common",
     "//components/safe_browsing/core/common:safe_browsing_policy_handler",
+    "//components/safe_browsing/core/db:database_manager",
+    "//components/safe_browsing/core/realtime:policy_engine",
+    "//components/safe_browsing/core/realtime:url_lookup_service",
     "//components/safe_search_api",
     "//components/safe_search_api:safe_search_client",
     "//components/schema_org/common:improved_mojom",
@@ -2067,31 +2120,37 @@
     "//components/strings",
     "//components/subresource_filter/content/browser",
     "//components/subresource_filter/core/browser",
+    "//components/subresource_filter/core/common",
     "//components/suggestions",
     "//components/sync",
     "//components/sync_bookmarks",
     "//components/sync_preferences",
     "//components/sync_sessions",
     "//components/tab_count_metrics",
+    "//components/tab_groups",
     "//components/tracing:startup_tracing",
     "//components/translate/content/browser",
     "//components/translate/core/browser",
     "//components/translate/core/common",
     "//components/ui_devtools",
+    "//components/ukm",
     "//components/ukm:observers",
     "//components/undo",
     "//components/update_client",
     "//components/update_client:common_impl",
     "//components/upload_list",
     "//components/url_formatter",
+    "//components/url_formatter/spoof_checks/top_domains:common",
     "//components/url_formatter/spoof_checks/top_domains:top500_domains",
     "//components/url_formatter/spoof_checks/top_domains:top500_domains_header",
     "//components/url_matcher",
+    "//components/user_manager",
     "//components/user_prefs",
     "//components/variations",
     "//components/variations/field_trial_config",
     "//components/variations/net",
     "//components/variations/service",
+    "//components/vector_icons",
     "//components/version_info",
     "//components/visitedlink/browser",
     "//components/visitedlink/common",
@@ -2104,7 +2163,6 @@
     "//components/webrtc_logging/common",
     "//content/app/resources",
     "//content/public/browser",
-    "//content/public/browser",
     "//content/public/common",
     "//content/public/common:service_names",
     "//crypto",
@@ -2119,6 +2177,7 @@
     "//media",
     "//media:media_buildflags",
     "//media/capture",
+    "//media/capture:capture_switches",
     "//media/midi",
     "//media/mojo:buildflags",
     "//media/mojo/common",
@@ -2129,6 +2188,8 @@
     "//net",
     "//net:extras",
     "//ppapi/buildflags",
+    "//ppapi/host",
+    "//printing",
     "//printing/buildflags",
     "//rlz/buildflags",
     "//services/audio/public/cpp",
@@ -2153,6 +2214,7 @@
     "//services/proxy_resolver/public/mojom",
     "//services/resource_coordinator/public/cpp:resource_coordinator_cpp",
     "//services/resource_coordinator/public/cpp/memory_instrumentation:browser",
+    "//services/service_manager/embedder:embedder_result_codes",
     "//services/service_manager/public/cpp",
     "//services/shape_detection/public/mojom",
     "//services/strings",
@@ -2173,6 +2235,7 @@
     "//third_party/re2",
     "//third_party/webrtc_overrides:webrtc_component",
     "//third_party/widevine/cdm:buildflags",
+    "//third_party/widevine/cdm:headers",
     "//third_party/zlib",
     "//third_party/zlib:minizip",
     "//third_party/zlib/google:compression_utils",
@@ -2181,9 +2244,12 @@
     "//ui/accessibility",
     "//ui/base",
     "//ui/base:ui_data_pack",
+    "//ui/base/clipboard",
     "//ui/base/idle",
     "//ui/base/ime",
+    "//ui/compositor",
     "//ui/events:events_base",
+    "//ui/events/devices",
     "//ui/gfx",
     "//ui/gfx/geometry",
     "//ui/gl",
@@ -2192,10 +2258,63 @@
     "//ui/message_center/public/cpp",
     "//ui/resources",
     "//ui/shell_dialogs",
+    "//ui/snapshot",
     "//ui/strings",
     "//ui/surface",
     "//ui/web_dialogs",
+    "//ui/webui",
+    "//ui/webui/resources/cr_components/customize_themes:mojom",
   ]
+  if (is_chromeos) {
+    deps += [
+      "//chrome/app/theme:chrome_unscaled_resources_grit",
+      "//chrome/browser/ui/webui/chromeos/add_supervision:mojo_bindings",
+      "//chrome/browser/ui/webui/chromeos/crostini_installer:mojo_bindings",
+      "//chrome/browser/ui/webui/chromeos/crostini_upgrader:mojo_bindings",
+      "//chrome/browser/ui/webui/chromeos/file_manager:mojo_bindings",
+      "//chrome/browser/ui/webui/chromeos/machine_learning:mojo_bindings",
+      "//chrome/browser/ui/webui/settings/chromeos/constants:mojom",
+      "//chrome/browser/ui/webui/settings/chromeos/search:mojo_bindings",
+      "//chromeos/audio",
+      "//chromeos/components/camera_app_ui",
+      "//chromeos/components/camera_app_ui:mojo_bindings",
+      "//chromeos/components/help_app_ui",
+      "//chromeos/components/help_app_ui:mojo_bindings",
+      "//chromeos/components/local_search_service",
+      "//chromeos/components/media_app_ui",
+      "//chromeos/components/media_app_ui:mojo_bindings",
+      "//chromeos/components/multidevice/debug_webui",
+      "//chromeos/components/print_management",
+      "//chromeos/components/print_management/mojom",
+      "//chromeos/components/quick_answers/public/cpp:prefs",
+      "//chromeos/components/scanning",
+      "//chromeos/components/scanning/mojom",
+      "//chromeos/dbus/cryptohome",
+      "//chromeos/dbus/power",
+      "//chromeos/services/device_sync/public/cpp:prefs",
+      "//chromeos/services/multidevice_setup/public/cpp",
+      "//chromeos/services/multidevice_setup/public/cpp:prefs",
+      "//chromeos/system",
+      "//chromeos/timezone",
+      "//chromeos/tpm",
+      "//components/drive",
+      "//components/quirks",
+      "//components/session_manager/core",
+      "//device/vr/public/mojom",
+    ]
+    if (!is_official_build) {
+      deps += [
+        "//chromeos/components/telemetry_extension_ui",
+        "//chromeos/components/telemetry_extension_ui/mojom",
+      ]
+    }
+  }
+  if (use_ozone) {
+    deps += [
+      "//ui/events/ozone",
+      "//ui/ozone",
+    ]
+  }
 
   if (build_with_tflite_lib) {
     sources += [
@@ -2209,7 +2328,7 @@
       "tflite_experiment/tflite_experiment_switches.h",
     ]
 
-    deps += [ "//chrome/services/machine_learning:machine_learning" ]
+    deps += [ "//chrome/services/machine_learning" ]
   }
 
   if (is_posix || is_fuchsia) {
@@ -2871,7 +2990,6 @@
       "password_manager/android/password_scripts_fetcher_android.cc",
       "password_manager/android/save_password_infobar_delegate_android.cc",
       "password_manager/android/save_password_infobar_delegate_android.h",
-      "password_manager/android/touch_to_fill_view.h",
       "password_manager/android/update_password_infobar_delegate_android.cc",
       "password_manager/android/update_password_infobar_delegate_android.h",
       "password_manager/biometric_authenticator_android.cc",
@@ -2916,7 +3034,6 @@
       "search/contextual_search_policy_handler_android.cc",
       "search/contextual_search_policy_handler_android.h",
       "search_engines/template_url_service_factory_android.cc",
-      "search_engines/template_url_service_factory_android.h",
       "search_engines/ui_thread_search_terms_data_android.cc",
       "search_engines/ui_thread_search_terms_data_android.h",
       "sessions/session_restore_android.cc",
@@ -2981,17 +3098,27 @@
       "//chrome/browser/offline_pages/prefetch/notifications",
       "//chrome/browser/optimization_guide/android:jni_headers",
       "//chrome/browser/password_check/android:jni_headers",
+      "//chrome/browser/password_check/android:password_check_enums_srcjar",
       "//chrome/browser/password_manager/android:jni_headers",
       "//chrome/browser/payments/android:jni_headers",
       "//chrome/browser/policy/android:jni_headers",
       "//chrome/browser/privacy:jni_headers",
       "//chrome/browser/safety_check/android",
       "//chrome/browser/share",
+      "//chrome/browser/share/android:jni_headers",
       "//chrome/browser/tab:jni_headers",
+      "//chrome/browser/ui/webui/explore_sites_internals:mojo_bindings",
+      "//chrome/browser/ui/webui/snippets_internals:mojo_bindings",
       "//chrome/browser/updates",
+      "//chrome/browser/updates:factory",
+      "//chrome/browser/video_tutorials/internal",
+      "//chrome/browser/video_tutorials/internal:jni_headers",
       "//chrome/common:non_code_constants",
       "//chrome/services/media_gallery_util/public/cpp",
+      "//components/assist_ranker/proto",
       "//components/autofill_assistant/browser",
+      "//components/autofill_assistant/browser:proto",
+      "//components/bookmarks/common/android",
       "//components/browser_ui/contacts_picker/android",
       "//components/browser_ui/photo_picker/android",
       "//components/browser_ui/site_settings/android",
@@ -3003,31 +3130,46 @@
       "//components/content_settings/android",
       "//components/crash/android:crash_android",
       "//components/embedder_support/android:browser_context",
+      "//components/embedder_support/android:context_menu",
       "//components/embedder_support/android:util",
       "//components/embedder_support/android:web_contents_delegate",
       "//components/external_intents/android",
+      "//components/favicon/core:database",
       "//components/feed:buildflags",
       "//components/feed:feature_list",
+      "//components/image_fetcher/core:metrics",
+      "//components/infobars/android",
       "//components/invalidation/impl:feature_list",
       "//components/javascript_dialogs/android:jni_headers",
       "//components/language/android:language_bridge",
       "//components/location/android:settings",
       "//components/messages/android:feature_flags",
       "//components/module_installer/android:native",
+      "//components/offline_pages/task",
       "//components/omnibox/browser",
       "//components/page_info/android",
       "//components/page_load_metrics/browser",
+      "//components/paint_preview/browser",
       "//components/password_manager/content/browser",
+      "//components/password_manager/core/browser:affiliation",
+      "//components/password_manager/core/browser/leak_detection",
+      "//components/payments/content",
       "//components/payments/content/android",
+      "//components/payments/content/android:jni_headers",
       "//components/permissions/android:native",
       "//components/query_tiles",
+      "//components/resources:android_resources",
       "//components/resources:components_resources",
+      "//components/safe_browsing/content/password_protection:password_protection_metrics_util",
       "//components/security_state/content/android",
       "//components/send_tab_to_self",
       "//components/signin/internal/identity_manager",  # cf android / signin /
                                                         # DEPS
+      "//components/signin/public/android:jni_headers",
       "//components/subresource_filter/android",
       "//components/thin_webview/internal",
+      "//components/translate/core/language_detection",
+      "//components/ukm/content",
       "//components/viz/common",
       "//ipc:param_traits",
       "//media/mojo/clients",
@@ -3035,14 +3177,17 @@
       "//sandbox",
       "//sandbox:sandbox_buildflags",
       "//services/device/public/cpp:device_feature_list",
+      "//services/device/public/cpp/geolocation",
       "//services/proxy_resolver:lib",
       "//third_party/android_ndk:cpu_features",
       "//third_party/android_opengl/etc1",
       "//third_party/blink/public/common",
-      "//third_party/crashpad/crashpad/client:client",
+      "//third_party/blink/public/mojom:android_mojo_bindings_blink_headers",
+      "//third_party/crashpad/crashpad/client",
       "//third_party/libaddressinput:util",
       "//third_party/libphonenumber",
       "//third_party/smhasher:murmurhash2",
+      "//url:gurl_android",
       "//url:origin_android",
     ]
     allow_circular_includes_from += [ "//chrome/browser/share" ]
@@ -3841,11 +3986,14 @@
       ":theme_properties",
       "//base/util/memory_pressure",
       "//base/util/timer",
+      "//chrome/app:command_ids",
+      "//chrome/app/theme:chrome_unscaled_resources_grit",
       "//chrome/app/vector_icons",
+      "//chrome/browser/media/kaleidoscope:kaleidoscope_resources",
+      "//chrome/browser/media/kaleidoscope/mojom",
       "//chrome/browser/nearby_sharing:share_target",
       "//chrome/browser/nearby_sharing/certificates",
       "//chrome/browser/nearby_sharing/client",
-      "//chrome/browser/nearby_sharing/common",
       "//chrome/browser/nearby_sharing/contacts",
       "//chrome/browser/nearby_sharing/instantmessaging/proto",
       "//chrome/browser/nearby_sharing/local_device_data",
@@ -3860,18 +4008,29 @@
       "//chrome/browser/resource_coordinator/tab_ranker",
       "//chrome/browser/resources:component_extension_resources",
       "//chrome/browser/search:generated",
+      "//chrome/browser/ui/color:color_headers",
+      "//chrome/browser/ui/webui/nearby_share:mojom",
+      "//chrome/browser/ui/webui/nearby_share/public/mojom",
+      "//chrome/common/apps/platform_apps",
       "//chrome/common/importer:interfaces",
       "//chrome/common/search:generate_chrome_colors_info",
+      "//chrome/common/search:generate_colors_info",
       "//chrome/common/themes:autogenerated_theme_util",
+      "//chrome/services/media_gallery_util/public/cpp",
       "//chrome/services/sharing/public/cpp",
       "//chrome/services/sharing/public/mojom",
       "//chrome/services/sharing/public/proto",
       "//chrome/services/speech:buildflags",
+      "//components/download/quarantine",
       "//components/feedback",
       "//components/image_fetcher/core",
       "//components/keep_alive_registry",
       "//components/ntp_snippets",
+      "//components/pref_registry",
+      "//components/printing/common:mojo_interfaces",
+      "//components/schema_org",
       "//components/schema_org:extractor",
+      "//components/schema_org:schema_org_properties",
       "//components/services/app_service:lib",
       "//components/services/app_service/public/cpp:app_file_handling",
       "//components/services/app_service/public/cpp:app_share_target",
@@ -3881,11 +4040,27 @@
       "//components/services/app_service/public/cpp:preferred_apps",
       "//components/services/app_service/public/cpp:publisher",
       "//components/soda:constants",
-      "//components/vector_icons",
+      "//components/ukm/content",
       "//components/web_modal",
       "//components/zoom",
       "//courgette:courgette_lib",
+      "//third_party/sqlite",
     ]
+    if (is_win) {
+      # TODO (crbug.com/1126800): Include this dep when build bots are fixed.
+      deps -= [ "//third_party/sqlite" ]
+    }
+    if (is_chromeos) {
+      deps += [
+        "//chrome/browser/supervised_user:supervised_user_unscaled_resources",
+        "//chromeos/dbus/session_manager",
+        "//chromeos/login/session",
+        "//components/arc:arc_base_utils",
+      ]
+    }
+    if (enable_extensions) {
+      deps += [ "//extensions/browser" ]
+    }
 
     if (is_posix || is_fuchsia) {
       sources += [
@@ -4077,18 +4252,28 @@
       "upgrade_detector/upgrade_detector_chromeos.h",
     ]
     deps += [
+      "//ash",
       "//ash/public/cpp",
       "//ash/public/cpp/external_arc",
+      "//ash/public/cpp/vector_icons",
       "//chrome/browser/chromeos",
+      "//chrome/browser/chromeos/power/ml/smart_dim",
       "//chromeos/components/account_manager",
       "//chromeos/components/cdm_factory_daemon:cdm_factory_daemon_browser",
       "//chromeos/components/quick_answers",
       "//chromeos/components/sync_wifi",
       "//chromeos/crosapi/mojom",
+      "//chromeos/dbus",
+      "//chromeos/geolocation",
+      "//chromeos/login/login_state",
+      "//chromeos/memory",
       "//chromeos/memory/userspace_swap",
       "//chromeos/memory/userspace_swap:mojom",
+      "//chromeos/network",
       "//chromeos/services/assistant/public/cpp",
       "//chromeos/services/cellular_setup",
+      "//chromeos/services/cros_healthd/public/cpp",
+      "//chromeos/services/cros_healthd/public/mojom",
       "//chromeos/services/device_sync/public/cpp:prefs",
       "//chromeos/services/device_sync/public/mojom",
       "//chromeos/services/multidevice_setup",
@@ -4097,7 +4282,11 @@
       "//chromeos/services/network_config",
       "//chromeos/services/network_config/public/mojom",
       "//chromeos/services/secure_channel/public/mojom",
+      "//chromeos/settings",
       "//chromeos/strings",
+      "//components/arc",
+      "//components/arc:arc_base",
+      "//components/arc/mojom",
       "//components/metrics/structured",
       "//components/services/app_service/public/cpp:instance_update",
       "//components/services/font:lib",
@@ -4106,6 +4295,7 @@
       "//ui/chromeos",
       "//ui/events/ozone",
       "//ui/ozone",
+      "//ui/wm/public",
     ]
     allow_circular_includes_from += [ "//chrome/browser/chromeos" ]
   } else {  # Non - ChromeOS.
@@ -4170,6 +4360,8 @@
       "comsuppw.lib",
     ]
     sources += [
+      "accessibility/caption_settings_dialog.h",
+      "accessibility/caption_settings_dialog_win.cc",
       "badging/badge_manager_delegate_win.cc",
       "badging/badge_manager_delegate_win.h",
       "browser_process_platform_part_win.cc",
@@ -4310,22 +4502,32 @@
     ]
     deps += [
       ":chrome_process_finder",
+      "//base/win:base_win_buildflags",
+      "//chrome/app/theme:chrome_unscaled_resources_grit",
       "//chrome/browser/safe_browsing/chrome_cleaner",
       "//chrome/browser/safe_browsing/chrome_cleaner:public",
+      "//chrome/browser/web_applications/chrome_pwa_launcher:util",
       "//chrome/browser/win/conflicts:module_info",
       "//chrome/chrome_elf:constants",
       "//chrome/chrome_elf:dll_hash",
+      "//chrome/chrome_elf:third_party_shared_defines",
       "//chrome/common:version_header",
       "//chrome/credential_provider/common:common_constants",
       "//chrome/elevation_service:elevation_service_idl",
       "//chrome/install_static:install_static_util",
+      "//chrome/installer/util:with_no_strings",
       "//chrome/notification_helper:constants",
       "//chrome/services/util_win/public/mojom",
       "//components/browser_watcher:browser_watcher_client",
       "//components/browser_watcher:stability_client",
       "//components/chrome_cleaner/public/constants",
+      "//components/crash/core/app",
+      "//components/crash/core/app:crash_export_thunk_include",
       "//components/download/quarantine",
-      "//third_party/crashpad/crashpad/client:client",
+      "//components/services/quarantine/public/cpp:features",
+      "//google_update",
+      "//sandbox/win:sandbox",
+      "//third_party/crashpad/crashpad/client",
       "//third_party/iaccessible2",
       "//third_party/isimpledom",
       "//third_party/wtl",
@@ -4411,6 +4613,8 @@
   if (is_mac) {
     allow_circular_includes_from += [ "//chrome/browser/apps/app_shim" ]
     sources += [
+      "accessibility/caption_settings_dialog.h",
+      "accessibility/caption_settings_dialog_mac.mm",
       "app_controller_mac.h",
       "app_controller_mac.mm",
       "apps/intent_helper/mac_apps_navigation_throttle.h",
@@ -4429,6 +4633,8 @@
       "first_run/first_run_internal_mac.mm",
       "first_run/upgrade_util_mac.cc",
       "fullscreen_mac.mm",
+      "geolocation/geolocation_system_permission_mac.h",
+      "geolocation/geolocation_system_permission_mac.mm",
       "global_keyboard_shortcuts_mac.h",
       "global_keyboard_shortcuts_mac.mm",
       "hang_monitor/hang_crash_dump_mac.cc",
@@ -4484,9 +4690,10 @@
       "//chrome/app_shim",
       "//chrome/browser/apps/app_shim",
       "//chrome/browser/ui/cocoa/notifications:common",
+      "//components/crash/core/app",
       "//components/metal_util",
       "//services/video_capture/public/mojom:constants",
-      "//third_party/crashpad/crashpad/client:client",
+      "//third_party/crashpad/crashpad/client",
       "//third_party/google_toolbox_for_mac",
       "//third_party/mozilla",
     ]
@@ -4551,6 +4758,7 @@
       "themes/theme_service_aura_linux.h",
       "upgrade_detector/get_installed_version_linux.cc",
     ]
+    deps += [ "//chrome/app/theme:chrome_unscaled_resources_grit" ]
 
     if (use_dbus) {
       deps += [ "//components/dbus/thread_linux" ]
@@ -4608,20 +4816,6 @@
     ]
   }
 
-  if (is_mac) {
-    sources += [
-      "accessibility/caption_settings_dialog.h",
-      "accessibility/caption_settings_dialog_mac.mm",
-    ]
-  }
-
-  if (is_win) {
-    sources += [
-      "accessibility/caption_settings_dialog.h",
-      "accessibility/caption_settings_dialog_win.cc",
-    ]
-  }
-
   if (is_win || is_chromeos) {
     sources += [
       "webshare/share_service_impl.cc",
@@ -4771,6 +4965,10 @@
     sources += [
       "crash_upload_list/crash_upload_list_crashpad.cc",
       "crash_upload_list/crash_upload_list_crashpad.h",
+      "media/cast_mirroring_service_host.cc",
+      "media/cast_mirroring_service_host.h",
+      "media/offscreen_tab.cc",
+      "media/offscreen_tab.h",
       "payments/chrome_payment_request_delegate.cc",
       "payments/chrome_payment_request_delegate.h",
       "payments/payment_credential_factory.cc",
@@ -4780,7 +4978,16 @@
       "payments/payment_request_factory.cc",
       "payments/payment_request_factory.h",
     ]
-    deps += [ "//components/payments/content" ]
+    deps += [
+      "//chrome/browser/ui/webui/discards:mojo_bindings",
+      "//components/autofill/content/browser/webauthn",
+      "//components/mirroring/browser",
+      "//components/mirroring/mojom:host",
+      "//components/mirroring/mojom:service",
+      "//components/mirroring/service:mirroring_service",
+      "//components/payments/content",
+      "//media/cast:net",
+    ]
   }
 
   if (is_win || is_mac || (is_chromeos && use_dbus)) {
@@ -4817,6 +5024,7 @@
       "//ui/base/dragdrop/mojom:mojom_shared",
       "//ui/compositor",
       "//ui/snapshot",
+      "//ui/wm",
     ]
     if (use_gtk) {
       deps += [ "//ui/gtk" ]
@@ -4835,6 +5043,7 @@
       "chrome_browser_main_extra_parts_ozone.cc",
       "chrome_browser_main_extra_parts_ozone.h",
     ]
+    deps += [ "//ui/ozone" ]
   }
 
   if (enable_background_mode) {
@@ -5020,22 +5229,6 @@
     }
   }
 
-  if (is_win || is_mac || is_linux || is_chromeos) {
-    sources += [
-      "media/cast_mirroring_service_host.cc",
-      "media/cast_mirroring_service_host.h",
-      "media/offscreen_tab.cc",
-      "media/offscreen_tab.h",
-    ]
-    deps += [
-      "//components/mirroring/browser",
-      "//components/mirroring/mojom:host",
-      "//components/mirroring/mojom:service",
-      "//components/mirroring/service:mirroring_service",
-      "//media/cast:net",
-    ]
-  }
-
   if (enable_media_remoting) {
     sources += [
       "media/cast_remoting_connector.cc",
@@ -5252,6 +5445,7 @@
       "//chrome/common/extensions/api:extensions_features",
       "//components/drive",
       "//components/guest_view/browser",
+      "//media/cast:sender",
 
       # TODO(crbug.com/879012): mirroring shouldn't depend on enable_extensions.
       "//components/mirroring/browser",
@@ -5262,6 +5456,9 @@
       "//google_apis/drive",
       "//services/device/public/mojom",
     ]
+    if (is_chromeos) {
+      deps += [ "//chromeos/services/tts/public/mojom" ]
+    }
   }
 
   if (enable_feed_in_chrome) {
@@ -5299,6 +5496,7 @@
       "android/feed/v2/refresh_task_scheduler_impl.h",
     ]
     deps += [
+      "//chrome/browser/ui/webui/feed_internals:mojo_bindings",
       "//components/feed/content:feed_content",
       "//components/feed/core/v2:feed_core_v2",
     ]
@@ -5470,7 +5668,7 @@
       "//components/offline_pages/content/renovations",
       "//components/offline_pages/core/downloads:offline_pages_ui_adapter",
       "//components/offline_pages/core/renovations",
-      "//components/offline_pages/core/request_header:request_header",
+      "//components/offline_pages/core/request_header",
     ]
 
     # Used to build test harness locally.The harness is used manually to
@@ -5577,10 +5775,14 @@
       "//components/pdf/browser",
       "//media:media_buildflags",
       "//ppapi/buildflags",
+      "//ppapi/host",
       "//ppapi/proxy:ipc",
       "//services/device/public/mojom",
       "//third_party/adobe/flash:flapper_version_h",
     ]
+    if (is_chromeos) {
+      deps += [ "//chromeos/cryptohome" ]
+    }
   }
 
   if (enable_rlz) {
@@ -5678,6 +5880,7 @@
       "sessions/tab_loader_delegate.cc",
       "sessions/tab_loader_delegate.h",
     ]
+    deps += [ "//components/tab_groups" ]
   }
 
   if (enable_spellcheck) {
@@ -5784,7 +5987,9 @@
     ]
     deps += [
       "//chrome/browser/supervised_user/kids_chrome_management:proto",
+      "//chrome/browser/supervised_user/supervised_user_error_page",
       "//chrome/common:supervised_user_commands_mojom",
+      "//components/pref_registry",
     ]
   }
   if (enable_supervised_users && enable_extensions) {
@@ -5823,6 +6028,14 @@
       "//chrome/browser/vr:vr_common",
       "//device/vr",
     ]
+
+    if (is_android) {
+      if (enable_arcore) {
+        deps += [ "//device/vr/android/arcore" ]
+      }
+    } else {
+      deps += [ "//device/vr/public/mojom" ]
+    }
   }
 
   if (enable_wayland_server) {
@@ -6177,8 +6390,6 @@
     "net/dns_probe_test_util.h",
     "notifications/metrics/mock_notification_metrics_logger.cc",
     "notifications/metrics/mock_notification_metrics_logger.h",
-    "notifications/notification_display_service_tester.cc",
-    "notifications/notification_display_service_tester.h",
     "notifications/notification_test_util.cc",
     "notifications/notification_test_util.h",
     "notifications/stub_notification_display_service.cc",
@@ -6191,16 +6402,10 @@
     "reputation/safety_tip_test_utils.h",
     "resource_coordinator/tab_load_tracker_test_support.cc",
     "resource_coordinator/tab_load_tracker_test_support.h",
-    "search_engines/template_url_service_factory_test_util.cc",
-    "search_engines/template_url_service_factory_test_util.h",
-    "search_engines/template_url_service_test_util.cc",
-    "search_engines/template_url_service_test_util.h",
     "signin/chrome_signin_client_test_util.cc",
     "signin/chrome_signin_client_test_util.h",
     "signin/e2e_tests/test_accounts_util.cc",
     "signin/e2e_tests/test_accounts_util.h",
-    "signin/identity_test_environment_profile_adaptor.cc",
-    "signin/identity_test_environment_profile_adaptor.h",
     "ssl/ssl_browsertest_util.cc",
     "ssl/ssl_browsertest_util.h",
     "ssl/ssl_client_auth_requestor_mock.cc",
@@ -6221,10 +6426,12 @@
   deps = [
     "//chrome/app/theme:theme_resources",
     "//chrome/browser",
+    "//chrome/browser/reputation:proto",
     "//chrome/browser/subresource_filter:test_support",
     "//chrome/common",
     "//chrome/common/safe_browsing:proto",
     "//components/browser_sync:test_support",
+    "//components/consent_auditor:test_support",
     "//components/invalidation/impl",
     "//components/invalidation/impl:test_support",
     "//components/password_manager/core/browser:test_support",
@@ -6232,6 +6439,7 @@
     "//components/prefs:test_support",
     "//components/safe_browsing/core:csd_proto",
     "//components/search_engines:test_support",
+    "//components/security_interstitials/content:security_interstitial_page",
     "//components/services/unzip/content",
     "//components/sessions:test_support",
     "//components/signin/public/identity_manager:test_support",
@@ -6244,6 +6452,7 @@
     "//google_apis:test_support",
     "//net:test_support",
     "//services/data_decoder/public/cpp:test_support",
+    "//services/network/public/proto:tls_deprecation_config_proto",
     "//services/preferences/public/cpp/tracked:test_support",
     "//skia",
     "//testing/gmock",
@@ -6314,16 +6523,8 @@
       "chromeos/login/screens/mock_device_disabled_screen_view.h",
       "chromeos/login/session/user_session_manager_test_api.cc",
       "chromeos/login/session/user_session_manager_test_api.h",
-      "chromeos/login/test/js_checker.cc",
-      "chromeos/login/test/js_checker.h",
-      "chromeos/login/test/oobe_auth_page_waiter.cc",
-      "chromeos/login/test/oobe_auth_page_waiter.h",
       "chromeos/login/test/oobe_configuration_waiter.cc",
       "chromeos/login/test/oobe_configuration_waiter.h",
-      "chromeos/login/test/oobe_screen_exit_waiter.cc",
-      "chromeos/login/test/oobe_screen_exit_waiter.h",
-      "chromeos/login/test/oobe_screen_waiter.cc",
-      "chromeos/login/test/oobe_screen_waiter.h",
       "chromeos/login/ui/fake_login_display_host.cc",
       "chromeos/login/ui/fake_login_display_host.h",
       "chromeos/login/ui/mock_login_display.cc",
@@ -6332,8 +6533,6 @@
       "chromeos/login/ui/mock_login_display_host.h",
       "chromeos/login/users/avatar/mock_user_image_manager.cc",
       "chromeos/login/users/avatar/mock_user_image_manager.h",
-      "chromeos/login/users/fake_chrome_user_manager.cc",
-      "chromeos/login/users/fake_chrome_user_manager.h",
       "chromeos/login/users/fake_supervised_user_manager.cc",
       "chromeos/login/users/fake_supervised_user_manager.h",
       "chromeos/login/users/mock_user_manager.cc",
@@ -6348,15 +6547,24 @@
       "chromeos/policy/fake_device_cloud_policy_initializer.h",
       "chromeos/policy/fake_device_cloud_policy_manager.cc",
       "chromeos/policy/fake_device_cloud_policy_manager.h",
-      "chromeos/settings/device_settings_test_helper.cc",
-      "chromeos/settings/device_settings_test_helper.h",
       "ui/app_list/test/chrome_app_list_test_support.cc",
       "ui/app_list/test/chrome_app_list_test_support.h",
       "ui/app_list/test/test_app_list_controller_delegate.cc",
       "ui/app_list/test/test_app_list_controller_delegate.h",
     ]
     configs += [ "//build/config/linux/dbus" ]
-    deps += [ "//chromeos:test_support" ]
+    deps += [
+      "//ash/public/cpp",
+      "//chrome/test:test_support_ui",
+      "//chromeos:test_support",
+      "//chromeos/attestation:test_support",
+      "//chromeos/dbus",
+      "//chromeos/disks",
+      "//chromeos/login/auth",
+      "//components/session_manager/core",
+      "//ui/base:test_support",
+      "//ui/base/ime/chromeos",
+    ]
   }
 
   if (is_win) {
@@ -6382,10 +6590,6 @@
       "extensions/test_blocklist.h",
       "extensions/test_blocklist_state_fetcher.cc",
       "extensions/test_blocklist_state_fetcher.h",
-      "extensions/test_extension_environment.cc",
-      "extensions/test_extension_environment.h",
-      "extensions/test_extension_prefs.cc",
-      "extensions/test_extension_prefs.h",
       "extensions/test_extension_service.cc",
       "extensions/test_extension_service.h",
       "extensions/test_extension_system.cc",
@@ -6394,13 +6598,20 @@
       "media_galleries/media_galleries_test_util.h",
     ]
     deps += [
+      "//components/crx_file",
       "//components/drive:test_support",
+      "//components/safe_browsing/core/db:v4_test_util",
       "//components/services/unzip:in_process",
       "//components/storage_monitor:test_support",
       "//extensions:test_support",
+      "//extensions/browser",
+      "//extensions/browser:test_support",
       "//google_apis:test_support",
       "//services/data_decoder/public/cpp:test_support",
     ]
+    if (is_chromeos) {
+      deps += [ "//chrome/browser/chromeos" ]
+    }
   }
 
   if (enable_library_cdms) {
@@ -6429,6 +6640,11 @@
       "safe_browsing/mock_report_sender.cc",
       "safe_browsing/mock_report_sender.h",
     ]
+    deps += [
+      "//chrome/browser/safe_browsing",
+      "//components/encrypted_messages",
+      "//components/security_interstitials/content:security_interstitial_page",
+    ]
   }
 
   if (safe_browsing_mode == 1) {
@@ -6438,6 +6654,11 @@
       "safe_browsing/cloud_content_scanning/fake_deep_scanning_dialog_delegate.cc",
       "safe_browsing/cloud_content_scanning/fake_deep_scanning_dialog_delegate.h",
     ]
+    deps += [
+      "//chrome/browser/safe_browsing",
+      "//components/enterprise/common/proto:connectors_proto",
+      "//components/safe_browsing/core/db:test_database_manager",
+    ]
   }
 
   if (has_spellcheck_panel) {
@@ -6447,6 +6668,7 @@
       "spellchecker/test/spellcheck_panel_browsertest_helper.cc",
       "spellchecker/test/spellcheck_panel_browsertest_helper.h",
     ]
+    deps += [ "//components/spellcheck/common" ]
   }
 }
 
@@ -6459,16 +6681,8 @@
     visibility = [ "//chrome/test:test_support_ui" ]
 
     sources = [
-      "interstitials/security_interstitial_idn_test.cc",
-      "interstitials/security_interstitial_idn_test.h",
-      "password_manager/password_manager_test_base.cc",
-      "password_manager/password_manager_test_base.h",
       "signin/token_revoker_test_utils.cc",
       "signin/token_revoker_test_utils.h",
-      "ssl/cert_verifier_platform_browser_test.cc",
-      "ssl/cert_verifier_platform_browser_test.h",
-      "ui/webui/signin/login_ui_test_utils.cc",
-      "ui/webui/signin/login_ui_test_utils.h",
       "ui/webui/test_data_source.cc",
       "ui/webui/test_data_source.h",
       "ui/webui/web_ui_test_handler.cc",
@@ -6482,7 +6696,10 @@
       "//chrome/test/data:web_ui_test_bindings",
       "//components/metrics:test_support",
       "//components/password_manager/core/browser:test_support",
+      "//components/signin/public/identity_manager",
+      "//components/sync/driver:test_support",
       "//components/translate/content/common",
+      "//content/test:test_support",
     ]
 
     public_deps = [ "//net:test_support" ]
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 645778a..32808a38 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -287,9 +287,9 @@
 const FeatureEntry::Choice kTouchTextSelectionStrategyChoices[] = {
     {flags_ui::kGenericExperimentChoiceDefault, "", ""},
     {flag_descriptions::kTouchSelectionStrategyCharacter,
-     switches::kTouchTextSelectionStrategy, "character"},
+     blink::switches::kTouchTextSelectionStrategy, "character"},
     {flag_descriptions::kTouchSelectionStrategyDirection,
-     switches::kTouchTextSelectionStrategy, "direction"}};
+     blink::switches::kTouchTextSelectionStrategy, "direction"}};
 
 const FeatureEntry::Choice kTraceUploadURL[] = {
     {flags_ui::kGenericExperimentChoiceDisabled, "", ""},
@@ -306,9 +306,9 @@
 const FeatureEntry::Choice kPassiveListenersChoices[] = {
     {flags_ui::kGenericExperimentChoiceDefault, "", ""},
     {flag_descriptions::kPassiveEventListenerTrue,
-     switches::kPassiveListenersDefault, "true"},
+     blink::switches::kPassiveListenersDefault, "true"},
     {flag_descriptions::kPassiveEventListenerForceAllTrue,
-     switches::kPassiveListenersDefault, "forcealltrue"},
+     blink::switches::kPassiveListenersDefault, "forcealltrue"},
 };
 
 const FeatureEntry::Choice kDataReductionProxyServerExperiment[] = {
@@ -2909,7 +2909,7 @@
          "IPH_DemoMode")},
     {"disable-threaded-scrolling", flag_descriptions::kThreadedScrollingName,
      flag_descriptions::kThreadedScrollingDescription, kOsAll,
-     SINGLE_DISABLE_VALUE_TYPE(switches::kDisableThreadedScrolling)},
+     SINGLE_DISABLE_VALUE_TYPE(blink::switches::kDisableThreadedScrolling)},
     {"extension-content-verification",
      flag_descriptions::kExtensionContentVerificationName,
      flag_descriptions::kExtensionContentVerificationDescription, kOsDesktop,
@@ -3278,9 +3278,9 @@
      // features controlled by kBlinkSettings, we'll need to add logic to
      // merge the flag values.
      ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(
-         switches::kBlinkSettings,
+         blink::switches::kBlinkSettings,
          "disallowFetchForDocWrittenScriptsInMainFrame=true",
-         switches::kBlinkSettings,
+         blink::switches::kBlinkSettings,
          "disallowFetchForDocWrittenScriptsInMainFrame=false")},
 #if defined(OS_WIN)
     {"use-winrt-midi-api", flag_descriptions::kUseWinrtMidiApiName,
@@ -4119,6 +4119,10 @@
      flag_descriptions::kTabGroupsDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(features::kTabGroups)},
 
+    {"tab-groups-auto-create", flag_descriptions::kTabGroupsAutoCreateName,
+     flag_descriptions::kTabGroupsAutoCreateDescription, kOsDesktop,
+     FEATURE_VALUE_TYPE(features::kTabGroupsAutoCreate)},
+
     {"tab-groups-collapse", flag_descriptions::kTabGroupsCollapseName,
      flag_descriptions::kTabGroupsCollapseDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(features::kTabGroupsCollapse)},
@@ -6459,6 +6463,13 @@
      FEATURE_VALUE_TYPE(ash::features::kTemporaryHoldingSpace)},
 #endif
 
+#if defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) || \
+    defined(OS_CHROMEOS)
+    {"enable-oop-print-drivers", flag_descriptions::kEnableOopPrintDriversName,
+     flag_descriptions::kEnableOopPrintDriversDescription, kOsDesktop,
+     FEATURE_VALUE_TYPE(printing::features::kEnableOopPrintDrivers)},
+#endif
+
     // NOTE: Adding a new flag requires adding a corresponding entry to enum
     // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag
     // Histograms" in tools/metrics/histograms/README.md (run the
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index d14f38ef..2569646 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -4160,7 +4160,7 @@
   auto* find_helper =
       find_in_page::FindTabHelper::FromWebContents(embedder_web_contents);
   find_helper->StartFinding(base::ASCIIToUTF16("doesn't matter"), true, true,
-                            true);
+                            false);
   auto pending =
       content::GetRenderFrameHostsWithPendingFindResults(embedder_web_contents);
   // Request for main frame of the tab.
diff --git a/chrome/browser/apps/platform_apps/app_browsertest.cc b/chrome/browser/apps/platform_apps/app_browsertest.cc
index 84976d72..b5e06a21 100644
--- a/chrome/browser/apps/platform_apps/app_browsertest.cc
+++ b/chrome/browser/apps/platform_apps/app_browsertest.cc
@@ -152,7 +152,7 @@
   }
 
   // PrintPreviewUI::TestDelegate implementation.
-  void DidGetPreviewPageCount(int page_count) override {
+  void DidGetPreviewPageCount(uint32_t page_count) override {
     total_page_count_ = page_count;
   }
 
@@ -178,8 +178,8 @@
   gfx::Size dialog_size() { return dialog_size_; }
 
  private:
-  int total_page_count_ = 1;
-  int rendered_page_count_ = 0;
+  uint32_t total_page_count_ = 1;
+  uint32_t rendered_page_count_ = 0;
   base::RunLoop* run_loop_ = nullptr;
   gfx::Size dialog_size_;
 };
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
index 48ea2b1..fdf6ee9 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -135,7 +135,7 @@
 #include "chrome/browser/android/search_permissions/search_permissions_service.h"
 #include "chrome/browser/android/webapps/webapp_registry.h"
 #include "chrome/browser/offline_pages/offline_page_model_factory.h"
-#include "components/cdm/browser/media_drm_storage_impl.h"
+#include "components/cdm/browser/media_drm_storage_impl.h"  // nogncheck crbug.com/1125897
 #include "components/feed/buildflags.h"
 #include "components/feed/core/v2/public/feed_service.h"
 #include "components/feed/feed_feature_list.h"
diff --git a/chrome/browser/browsing_data/counters/site_data_counting_helper.cc b/chrome/browser/browsing_data/counters/site_data_counting_helper.cc
index 4d41386..47e0891f 100644
--- a/chrome/browser/browsing_data/counters/site_data_counting_helper.cc
+++ b/chrome/browser/browsing_data/counters/site_data_counting_helper.cc
@@ -28,7 +28,7 @@
 #include "url/origin.h"
 
 #if defined(OS_ANDROID)
-#include "components/cdm/browser/media_drm_storage_impl.h"
+#include "components/cdm/browser/media_drm_storage_impl.h"  // nogncheck crbug.com/1125897
 #endif
 
 using content::BrowserThread;
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc
index 5771450..3de6004 100644
--- a/chrome/browser/chrome_browser_interface_binders.cc
+++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -118,9 +118,6 @@
 #include "chrome/browser/ui/webui/downloads/downloads.mojom.h"
 #include "chrome/browser/ui/webui/downloads/downloads_ui.h"
 #include "chrome/browser/ui/webui/media/media_feeds_ui.h"
-#include "chrome/browser/ui/webui/nearby_share/nearby_share.mojom.h"
-#include "chrome/browser/ui/webui/nearby_share/nearby_share_dialog_ui.h"
-#include "chrome/browser/ui/webui/nearby_share/public/mojom/nearby_share_settings.mojom.h"
 #include "chrome/browser/ui/webui/new_tab_page/new_tab_page.mojom.h"
 #include "chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.h"
 #include "chrome/browser/ui/webui/read_later/read_later.mojom.h"
@@ -164,6 +161,9 @@
 #include "chrome/browser/ui/webui/chromeos/multidevice_setup/multidevice_setup_dialog.h"
 #include "chrome/browser/ui/webui/chromeos/network_ui.h"
 #include "chrome/browser/ui/webui/internals/web_app/web_app_internals.mojom.h"
+#include "chrome/browser/ui/webui/nearby_share/nearby_share.mojom.h"
+#include "chrome/browser/ui/webui/nearby_share/nearby_share_dialog_ui.h"
+#include "chrome/browser/ui/webui/nearby_share/public/mojom/nearby_share_settings.mojom.h"  // nogncheck crbug.com/1125897
 #include "chrome/browser/ui/webui/settings/chromeos/os_settings_ui.h"
 #include "chrome/browser/ui/webui/settings/chromeos/search/search.mojom.h"
 #include "chrome/browser/ui/webui/settings/chromeos/search/user_action_recorder.mojom.h"
@@ -195,8 +195,8 @@
 #endif
 
 #if defined(OS_CHROMEOS) && !defined(OFFICIAL_BUILD)
-#include "chromeos/components/telemetry_extension_ui/mojom/diagnostics_service.mojom.h"
-#include "chromeos/components/telemetry_extension_ui/mojom/probe_service.mojom.h"
+#include "chromeos/components/telemetry_extension_ui/mojom/diagnostics_service.mojom.h"  // nogncheck crbug.com/1125897
+#include "chromeos/components/telemetry_extension_ui/mojom/probe_service.mojom.h"  // nogncheck crbug.com/1125897
 #include "chromeos/components/telemetry_extension_ui/telemetry_extension_ui.h"
 #endif
 
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 346cc5c..eeb78fa 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -291,7 +291,7 @@
 
 #if BUILDFLAG(ENABLE_RLZ)
 #include "chrome/browser/rlz/chrome_rlz_tracker_delegate.h"
-#include "components/rlz/rlz_tracker.h"
+#include "components/rlz/rlz_tracker.h"  // nogncheck crbug.com/1125897
 #endif  // BUILDFLAG(ENABLE_RLZ)
 
 #if BUILDFLAG(IS_LACROS)
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 735af5af..221a1007 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -115,8 +115,6 @@
 #include "chrome/browser/resource_coordinator/background_tab_navigation_throttle.h"
 #include "chrome/browser/safe_browsing/certificate_reporting_service.h"
 #include "chrome/browser/safe_browsing/certificate_reporting_service_factory.h"
-#include "chrome/browser/safe_browsing/chrome_enterprise_url_lookup_service.h"
-#include "chrome/browser/safe_browsing/chrome_enterprise_url_lookup_service_factory.h"
 #include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h"
 #include "chrome/browser/safe_browsing/delayed_warning_navigation_throttle.h"
 #include "chrome/browser/safe_browsing/safe_browsing_navigation_throttle.h"
@@ -473,7 +471,7 @@
 #include "chrome/browser/webauthn/authenticator_request_scheduler.h"
 #include "chrome/browser/webauthn/chrome_authenticator_request_delegate.h"
 #include "chrome/common/importer/profile_import.mojom.h"
-#include "chrome/grit/chrome_unscaled_resources.h"
+#include "chrome/grit/chrome_unscaled_resources.h"  // nogncheck crbug.com/1125897
 #endif  //  !defined(OS_ANDROID)
 
 #if defined(OS_WIN) || defined(OS_MAC) || \
@@ -609,13 +607,18 @@
 #include "chrome/browser/safe_browsing/client_side_detection_service_factory.h"
 #endif
 
+#if BUILDFLAG(SAFE_BROWSING_DB_LOCAL)
+#include "chrome/browser/safe_browsing/chrome_enterprise_url_lookup_service.h"  // nogncheck crbug.com/1125897
+#include "chrome/browser/safe_browsing/chrome_enterprise_url_lookup_service_factory.h"  // nogncheck crbug.com/1125897
+#endif
+
 #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
 #include "chrome/browser/offline_pages/offline_page_tab_helper.h"
 #include "chrome/browser/offline_pages/offline_page_url_loader_request_interceptor.h"
 #endif
 
 #if BUILDFLAG(ENABLE_VR) && !defined(OS_ANDROID)
-#include "device/vr/public/mojom/isolated_xr_service.mojom.h"
+#include "device/vr/public/mojom/isolated_xr_service.mojom.h"  // nogncheck crbug.com/1125897
 #endif
 
 #if BUILDFLAG(ENABLE_WEBUI_TAB_STRIP)
@@ -2082,8 +2085,8 @@
     return;
   }
 
-  if (browser_command_line.HasSwitch(switches::kBlinkSettings) ||
-      command_line->HasSwitch(switches::kBlinkSettings)) {
+  if (browser_command_line.HasSwitch(blink::switches::kBlinkSettings) ||
+      command_line->HasSwitch(blink::switches::kBlinkSettings)) {
     // The field trials should be configured to force users that specify the
     // blink-settings flag into a group with no params, and we return
     // above if no params were specified, so it's an error if we reach
@@ -2093,7 +2096,7 @@
     return;
   }
 
-  command_line->AppendSwitchASCII(switches::kBlinkSettings,
+  command_line->AppendSwitchASCII(blink::switches::kBlinkSettings,
                                   base::JoinString(blink_settings, ","));
 }
 
diff --git a/chrome/browser/chrome_content_browser_client_unittest.cc b/chrome/browser/chrome_content_browser_client_unittest.cc
index 6c7a60f..786cf0b 100644
--- a/chrome/browser/chrome_content_browser_client_unittest.cc
+++ b/chrome/browser/chrome_content_browser_client_unittest.cc
@@ -48,6 +48,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/common/switches.h"
 #include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
 #include "url/gurl.h"
 
@@ -476,7 +477,7 @@
   }
 
   void AppendBlinkSettingsSwitch(const char* value) {
-    command_line_.AppendSwitchASCII(switches::kBlinkSettings, value);
+    command_line_.AppendSwitchASCII(blink::switches::kBlinkSettings, value);
   }
 
  private:
@@ -494,13 +495,13 @@
 
 TEST_F(BlinkSettingsFieldTrialTest, NoFieldTrial) {
   AppendContentBrowserClientSwitches();
-  EXPECT_FALSE(command_line().HasSwitch(switches::kBlinkSettings));
+  EXPECT_FALSE(command_line().HasSwitch(blink::switches::kBlinkSettings));
 }
 
 TEST_F(BlinkSettingsFieldTrialTest, FieldTrialWithoutParams) {
   CreateFieldTrial(kDisallowFetchFieldTrialName, kFakeGroupName);
   AppendContentBrowserClientSwitches();
-  EXPECT_FALSE(command_line().HasSwitch(switches::kBlinkSettings));
+  EXPECT_FALSE(command_line().HasSwitch(blink::switches::kBlinkSettings));
 }
 
 TEST_F(BlinkSettingsFieldTrialTest, BlinkSettingsSwitchAlreadySpecified) {
@@ -508,18 +509,18 @@
   CreateFieldTrialWithParams(kDisallowFetchFieldTrialName, kFakeGroupName,
                              "key1", "value1", "key2", "value2");
   AppendContentBrowserClientSwitches();
-  EXPECT_TRUE(command_line().HasSwitch(switches::kBlinkSettings));
-  EXPECT_EQ("foo",
-            command_line().GetSwitchValueASCII(switches::kBlinkSettings));
+  EXPECT_TRUE(command_line().HasSwitch(blink::switches::kBlinkSettings));
+  EXPECT_EQ("foo", command_line().GetSwitchValueASCII(
+                       blink::switches::kBlinkSettings));
 }
 
 TEST_F(BlinkSettingsFieldTrialTest, FieldTrialEnabled) {
   CreateFieldTrialWithParams(kDisallowFetchFieldTrialName, kFakeGroupName,
                              "key1", "value1", "key2", "value2");
   AppendContentBrowserClientSwitches();
-  EXPECT_TRUE(command_line().HasSwitch(switches::kBlinkSettings));
-  EXPECT_EQ("key1=value1,key2=value2",
-            command_line().GetSwitchValueASCII(switches::kBlinkSettings));
+  EXPECT_TRUE(command_line().HasSwitch(blink::switches::kBlinkSettings));
+  EXPECT_EQ("key1=value1,key2=value2", command_line().GetSwitchValueASCII(
+                                           blink::switches::kBlinkSettings));
 }
 
 #if !defined(OS_ANDROID)
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index e17bbb92..fa2f67c 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -2961,6 +2961,14 @@
     "login/screens/recommend_apps/fake_recommend_apps_fetcher_delegate.h",
     "login/test/dialog_window_waiter.cc",
     "login/test/dialog_window_waiter.h",
+    "login/test/js_checker.cc",
+    "login/test/js_checker.h",
+    "login/test/oobe_auth_page_waiter.cc",
+    "login/test/oobe_auth_page_waiter.h",
+    "login/test/oobe_screen_exit_waiter.cc",
+    "login/test/oobe_screen_exit_waiter.h",
+    "login/test/oobe_screen_waiter.cc",
+    "login/test/oobe_screen_waiter.h",
     "login/test/scoped_help_app_for_test.cc",
     "login/test/scoped_help_app_for_test.h",
     "login/test/test_condition_waiter.h",
diff --git a/chrome/browser/chromeos/arc/file_system_watcher/arc_file_system_watcher_service.cc b/chrome/browser/chromeos/arc/file_system_watcher/arc_file_system_watcher_service.cc
index 8cd8a277..9673c65 100644
--- a/chrome/browser/chromeos/arc/file_system_watcher/arc_file_system_watcher_service.cc
+++ b/chrome/browser/chromeos/arc/file_system_watcher/arc_file_system_watcher_service.cc
@@ -42,26 +42,27 @@
 
 namespace {
 
+// The storage path inside ARC container. This will be the path that is used in
+// MediaScanner.scanFile request.
+constexpr base::FilePath::CharType kAndroidStorageDir[] =
+    FILE_PATH_LITERAL("/storage");
+
 // The Downloads path inside ARC container. This will be the path that
 // is used in MediaScanner.scanFile request.
 constexpr base::FilePath::CharType kAndroidDownloadDir[] =
     FILE_PATH_LITERAL("/storage/emulated/0/Download");
 
+// TODO(crbug.com/929031): Move this to arc_volume_mounter_bridge.h.
 // The MyFiles path inside ARC container. This will be the path that is used in
-// MediaScanner.scanFile request. MediaScanner scans MyFiles under
-// /storage/MyFiles-read instead of /storage/MyFiles because non-system apps has
-// no access to /storage/MyFiles.
+// MediaScanner.scanFile request. UUID for the MyFiles volume is taken from
+// components/arc/volume_mounter/arc_volume_mounter_bridge.cc.
 constexpr base::FilePath::CharType kAndroidMyFilesDir[] =
-    FILE_PATH_LITERAL("/storage/MyFiles-read");
+    FILE_PATH_LITERAL("/storage/0000000000000000000000000000CAFEF00D2019");
 
 // The path for Downloads under MyFiles inside ARC container.
 constexpr base::FilePath::CharType kAndroidMyFilesDownloadsDir[] =
-    FILE_PATH_LITERAL("/storage/MyFiles-read/Downloads/");
-
-// The removable media path inside ARC container. This will be the path that
-// is used in MediaScanner.scanFile request.
-constexpr base::FilePath::CharType kAndroidRemovableMediaDir[] =
-    FILE_PATH_LITERAL("/storage");
+    FILE_PATH_LITERAL(
+        "/storage/0000000000000000000000000000CAFEF00D2019/Downloads/");
 
 // How long to wait for new inotify events before building the updated timestamp
 // map.
@@ -121,24 +122,9 @@
     if (!HasAndroidSupportedMediaExtension(cros_path))
       continue;
 
-    // TODO(b/163951541): Temporary hack, this will be changed when we change
-    // the path to UUID. The cros_dir for removable media is now changed to
-    // /media/removable/volume_name instead of just /media/removable.
-    // Meanwhile, the GetAndroidPath function accept the second parameter
-    // cros_dir as a way to identify if it is a removable media directory.
-    // Since the second parameter is only used for identification,
-    // and the identification happens through equality check with
-    // kCrosRemovableMediaDir string, it is safe to just pass
-    // kCrosRemovableMediaDir string directly when we know it is a removable
-    // media. In other word, the cros_removable_media_dir below is used as
-    // the ChromeOS analogue for the Android /storage directory.
-    base::FilePath cros_removable_media_dir =
-        base::FilePath(kCrosRemovableMediaDir);
-    base::FilePath android_path = GetAndroidPath(
-        cros_path,
-        cros_removable_media_dir.IsParent(cros_dir) ? cros_removable_media_dir
-                                                    : cros_dir,
-        android_dir);
+    base::FilePath android_path(android_dir);
+    cros_dir.AppendRelativePath(cros_path, &android_path);
+
     const base::FileEnumerator::FileInfo& info = enumerator.GetInfo();
     timestamp_map[android_path] = info.GetLastModifiedTime();
   }
@@ -453,13 +439,10 @@
 
   // Make sure the callback is triggered after the file system is attached in
   // file_task_runner.
-  // TODO(b/163951541): Temporary hack, this will be changed when we change the
-  // path to UUID. The kAndroidRemovableMediaDir is hardcoded here because
-  // CreateAndStartFileSystemWatcher accepts the removable media's volume's
-  // directory's parent in Android as second argument (i.e., /storage).
+  base::FilePath android_path =
+      base::FilePath(kAndroidStorageDir).Append(fs_uuid);
   removable_media_watchers_[fs_uuid] = CreateAndStartFileSystemWatcher(
-      base::FilePath(mount_path), base::FilePath(kAndroidRemovableMediaDir),
-      std::move(callback));
+      base::FilePath(mount_path), android_path, std::move(callback));
 }
 
 void ArcFileSystemWatcherService::StopWatchingRemovableMedia(
diff --git a/chrome/browser/chromeos/concierge_helper_service.cc b/chrome/browser/chromeos/concierge_helper_service.cc
index 38b98eb..8abed5d 100644
--- a/chrome/browser/chromeos/concierge_helper_service.cc
+++ b/chrome/browser/chromeos/concierge_helper_service.cc
@@ -18,13 +18,6 @@
 namespace chromeos {
 namespace {
 
-void OnStartConcierge(bool started) {
-  if (started)
-    VLOG(1) << "Concierge D-Bus service successfully started";
-  else
-    LOG(ERROR) << "Unable to start Concierge D-Bus service";
-}
-
 void OnSetVmCpuRestriction(
     base::Optional<vm_tools::concierge::SetVmCpuRestrictionResponse> response) {
   if (!response || !response->success()) {
@@ -33,18 +26,6 @@
   }
 }
 
-// Starts Concierge DBus service through debugd. If the service is already
-// running, this request will be ignored.
-void StartConcierge() {
-  auto* client = DBusThreadManager::Get()->GetDebugDaemonClient();
-  if (!client) {
-    LOG(WARNING) << "DebugDaemonClient is not available";
-    OnStartConcierge(false);
-    return;
-  }
-  client->StartConcierge(base::BindOnce(&OnStartConcierge));
-}
-
 // Adds a callback to be run when Concierge DBus service becomes available.
 // If the service is already available, runs the callback immediately.
 void WaitForConciergeToBeAvailable(
@@ -103,9 +84,7 @@
   return ConciergeHelperServiceFactory::GetForBrowserContext(context);
 }
 
-ConciergeHelperService::ConciergeHelperService() {
-  StartConcierge();
-}
+ConciergeHelperService::ConciergeHelperService() = default;
 
 void ConciergeHelperService::SetArcVmCpuRestriction(bool do_restrict) {
   MakeRestrictionRequest(vm_tools::concierge::CPU_CGROUP_ARCVM, do_restrict);
diff --git a/chrome/browser/chromeos/concierge_helper_service_unittest.cc b/chrome/browser/chromeos/concierge_helper_service_unittest.cc
index 9d5f2a9e..fac19b2e 100644
--- a/chrome/browser/chromeos/concierge_helper_service_unittest.cc
+++ b/chrome/browser/chromeos/concierge_helper_service_unittest.cc
@@ -11,7 +11,6 @@
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/dbus/concierge/concierge_service.pb.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/debug_daemon/fake_debug_daemon_client.h"
 #include "chromeos/dbus/fake_concierge_client.h"
 #include "content/public/test/browser_task_environment.h"
 #include "dbus/bus.h"
@@ -20,24 +19,6 @@
 
 namespace chromeos {
 
-class TestDebugDaemonClient : public FakeDebugDaemonClient {
- public:
-  TestDebugDaemonClient() = default;
-  ~TestDebugDaemonClient() override = default;
-
-  void StartConcierge(ConciergeCallback callback) override {
-    ++start_concierge_called_;
-    FakeDebugDaemonClient::StartConcierge(std::move(callback));
-  }
-
-  size_t start_concierge_called() const { return start_concierge_called_; }
-
- private:
-  size_t start_concierge_called_{0};
-
-  DISALLOW_COPY_AND_ASSIGN(TestDebugDaemonClient);
-};
-
 class TestConciergeClient : public FakeConciergeClient {
  public:
   TestConciergeClient() = default;
@@ -96,7 +77,6 @@
   // testing::Test:
   void SetUp() override {
     auto setter = DBusThreadManager::GetSetterForTesting();
-    setter->SetDebugDaemonClient(std::make_unique<TestDebugDaemonClient>());
     setter->SetConciergeClient(std::make_unique<TestConciergeClient>());
     service_ = ConciergeHelperService::GetForBrowserContext(&profile_);
   }
@@ -111,11 +91,6 @@
         DBusThreadManager::Get()->GetConciergeClient());
   }
 
-  TestDebugDaemonClient* fake_debug_client() {
-    return static_cast<TestDebugDaemonClient*>(
-        DBusThreadManager::Get()->GetDebugDaemonClient());
-  }
-
   content::BrowserTaskEnvironment* task_environment() {
     return &task_environment_;
   }
@@ -128,12 +103,6 @@
   DISALLOW_COPY_AND_ASSIGN(ConciergeHelperServiceTest);
 };
 
-// Tests that ConciergeHelperService can be constructed and destructed. Also,
-// check that ConciergeHelperService starts Concierge on construction.
-TEST_F(ConciergeHelperServiceTest, TestConstructDestruct) {
-  EXPECT_EQ(1U, fake_debug_client()->start_concierge_called());
-}
-
 // Tests that ConciergeHelperService makes cpu restriction requests correctly.
 TEST_F(ConciergeHelperServiceTest, TestSetVmCpuRestriction) {
   vm_tools::concierge::SetVmCpuRestrictionResponse response;
diff --git a/chrome/browser/chromeos/crostini/crostini_disk.cc b/chrome/browser/chromeos/crostini/crostini_disk.cc
index 225174f..8ea4a8c6 100644
--- a/chrome/browser/chromeos/crostini/crostini_disk.cc
+++ b/chrome/browser/chromeos/crostini/crostini_disk.cc
@@ -73,26 +73,15 @@
         base::BindOnce(&OnAmountOfFreeDiskSpace, std::move(callback), profile,
                        std::move(vm_name)));
   } else {
-    VLOG(1) << "Starting concierge";
     // Since we only care about the disk's current size and whether it's a
     // sparse disk, we claim there's plenty of free space available to prevent
     // error conditions in |OnCrostiniSufficientlyRunning|.
     constexpr int64_t kFakeAvailableDiskBytes =
         kDiskHeadroomBytes + kRecommendedDiskSizeBytes;
 
-    CrostiniManager::GetForProfile(profile)->StartConcierge(base::BindOnce(
-        [](OnceDiskInfoCallback callback, Profile* profile, std::string vm_name,
-           bool success) {
-          if (!success) {
-            LOG(ERROR) << "Failed to start concierge";
-            std::move(callback).Run(nullptr);
-            return;
-          }
-          OnCrostiniSufficientlyRunning(
-              std::move(callback), profile, std::move(vm_name),
-              kFakeAvailableDiskBytes, CrostiniResult::SUCCESS);
-        },
-        std::move(callback), profile, std::move(vm_name)));
+    OnCrostiniSufficientlyRunning(std::move(callback), profile,
+                                  std::move(vm_name), kFakeAvailableDiskBytes,
+                                  CrostiniResult::SUCCESS);
   }
 }
 
diff --git a/chrome/browser/chromeos/crostini/crostini_installer.cc b/chrome/browser/chromeos/crostini/crostini_installer.cc
index 8de0de66..9faad08a 100644
--- a/chrome/browser/chromeos/crostini/crostini_installer.cc
+++ b/chrome/browser/chromeos/crostini/crostini_installer.cc
@@ -113,8 +113,6 @@
       return SetupResult::kSuccess;
     case InstallerError::kErrorLoadingTermina:
       return SetupResult::kErrorLoadingTermina;
-    case InstallerError::kErrorStartingConcierge:
-      return SetupResult::kErrorStartingConcierge;
     case InstallerError::kErrorCreatingDiskImage:
       return SetupResult::kErrorCreatingDiskImage;
     case InstallerError::kErrorStartingTermina:
@@ -149,8 +147,6 @@
       return SetupResult::kUserCancelledStart;
     case InstallerState::kInstallImageLoader:
       return SetupResult::kUserCancelledInstallImageLoader;
-    case InstallerState::kStartConcierge:
-      return SetupResult::kUserCancelledStartConcierge;
     case InstallerState::kCreateDiskImage:
       return SetupResult::kUserCancelledCreateDiskImage;
     case InstallerState::kStartTerminaVm:
@@ -326,15 +322,6 @@
     }
     return;
   }
-  UpdateInstallingState(InstallerState::kStartConcierge);
-}
-
-void CrostiniInstaller::OnConciergeStarted(bool success) {
-  DCHECK_EQ(installing_state_, InstallerState::kStartConcierge);
-  if (!success) {
-    HandleError(InstallerError::kErrorStartingConcierge);
-    return;
-  }
   UpdateInstallingState(InstallerState::kCreateDiskImage);
 }
 
@@ -499,12 +486,8 @@
       state_end_mark = 0.20;
       state_max_time = base::TimeDelta::FromSeconds(30);
       break;
-    case InstallerState::kStartConcierge:
-      state_start_mark = 0.20;
-      state_end_mark = 0.21;
-      break;
     case InstallerState::kCreateDiskImage:
-      state_start_mark = 0.21;
+      state_start_mark = 0.20;
       state_end_mark = 0.22;
       break;
     case InstallerState::kStartTerminaVm:
diff --git a/chrome/browser/chromeos/crostini/crostini_installer.h b/chrome/browser/chromeos/crostini/crostini_installer.h
index ce26ed5..ce38ef5f 100644
--- a/chrome/browser/chromeos/crostini/crostini_installer.h
+++ b/chrome/browser/chromeos/crostini/crostini_installer.h
@@ -37,7 +37,7 @@
     // kUserCancelled = 1,
     kSuccess = 2,
     kErrorLoadingTermina = 3,
-    kErrorStartingConcierge = 4,
+    // kErrorStartingConcierge = 4,
     kErrorCreatingDiskImage = 5,
     kErrorStartingTermina = 6,
     kErrorStartingContainer = 7,
@@ -48,7 +48,7 @@
 
     kUserCancelledStart = 12,
     kUserCancelledInstallImageLoader = 13,
-    kUserCancelledStartConcierge = 14,
+    // kUserCancelledStartConcierge = 14,
     kUserCancelledCreateDiskImage = 15,
     kUserCancelledStartTerminaVm = 16,
     kUserCancelledCreateContainer = 17,
@@ -88,7 +88,6 @@
   // CrostiniManager::RestartObserver:
   void OnStageStarted(crostini::mojom::InstallerState stage) override;
   void OnComponentLoaded(crostini::CrostiniResult result) override;
-  void OnConciergeStarted(bool success) override;
   void OnDiskImageCreated(bool success,
                           vm_tools::concierge::DiskImageStatus status,
                           int64_t disk_size_available) override;
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.cc b/chrome/browser/chromeos/crostini/crostini_manager.cc
index 903c98f..7a7fce0 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager.cc
@@ -333,23 +333,6 @@
     }
     // Set the pref here, after we first successfully install something
     profile_->GetPrefs()->SetBoolean(crostini::prefs::kCrostiniEnabled, true);
-    StartStage(mojom::InstallerState::kStartConcierge);
-    crostini_manager_->StartConcierge(base::BindOnce(
-        &CrostiniRestarter::ConciergeStarted, weak_ptr_factory_.GetWeakPtr()));
-  }
-
-  void ConciergeStarted(bool is_started) {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-    for (auto& observer : observer_list_) {
-      observer.OnConciergeStarted(is_started);
-    }
-    if (ReturnEarlyIfAborted()) {
-      return;
-    }
-    if (!is_started) {
-      FinishRestart(CrostiniResult::CONCIERGE_START_FAILED);
-      return;
-    }
 
     // Allow concierge to choose an appropriate disk image size.
     int64_t disk_size_bytes = options_.disk_size_bytes.value_or(0);
@@ -1044,34 +1027,6 @@
   termina_installer_.Uninstall(std::move(callback));
 }
 
-void CrostiniManager::StartConcierge(BoolCallback callback) {
-  VLOG(1) << "Starting Concierge service";
-  chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->StartConcierge(
-      base::BindOnce(&CrostiniManager::OnStartConcierge,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void CrostiniManager::OnStartConcierge(BoolCallback callback, bool success) {
-  if (!success) {
-    LOG(ERROR) << "Failed to start Concierge service";
-    std::move(callback).Run(success);
-    return;
-  }
-  VLOG(1) << "Concierge service started";
-  VLOG(1) << "Waiting for Cicerone to announce availability.";
-
-  GetCiceroneClient()->WaitForServiceToBeAvailable(std::move(callback));
-}
-
-void CrostiniManager::OnStopConcierge(BoolCallback callback, bool success) {
-  if (!success) {
-    LOG(ERROR) << "Failed to stop Concierge service";
-  } else {
-    VLOG(1) << "Concierge service stopped";
-  }
-  std::move(callback).Run(success);
-}
-
 void CrostiniManager::CreateDiskImage(
     const base::FilePath& disk_path,
     vm_tools::concierge::StorageLocation storage_location,
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.h b/chrome/browser/chromeos/crostini/crostini_manager.h
index 459f9c816..1ff400d 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.h
+++ b/chrome/browser/chromeos/crostini/crostini_manager.h
@@ -189,7 +189,6 @@
     virtual ~RestartObserver() {}
     virtual void OnStageStarted(mojom::InstallerState stage) {}
     virtual void OnComponentLoaded(CrostiniResult result) {}
-    virtual void OnConciergeStarted(bool success) {}
     virtual void OnDiskImageCreated(bool success,
                                     vm_tools::concierge::DiskImageStatus status,
                                     int64_t disk_size_bytes) {}
@@ -243,10 +242,6 @@
   // Unloads and removes termina.
   void UninstallTermina(BoolCallback callback);
 
-  // Starts the Concierge service. |callback| is called after the method call
-  // finishes.
-  void StartConcierge(BoolCallback callback);
-
   // Checks the arguments for creating a new Termina VM disk image. Creates a
   // disk image for a Termina VM via ConciergeClient::CreateDiskImage.
   // |callback| is called if the arguments are bad, or after the method call
@@ -703,14 +698,6 @@
       base::Optional<vm_tools::concierge::GetVmEnterpriseReportingInfoResponse>
           response);
 
-  // Callback for CrostiniClient::StartConcierge. Called after the
-  // DebugDaemon service method finishes.
-  void OnStartConcierge(BoolCallback callback, bool success);
-
-  // Callback for CrostiniClient::StopConcierge. Called after the
-  // DebugDaemon service method finishes.
-  void OnStopConcierge(BoolCallback callback, bool success);
-
   // Callback for CiceroneClient::StartLxd. May indicate that LXD is still being
   // started in which case we will wait for OnStartLxdProgress events.
   void OnStartLxd(
diff --git a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
index c80358bec..d694b35 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
@@ -645,12 +645,6 @@
     }
   }
 
-  void OnConciergeStarted(bool success) override {
-    if (abort_on_concierge_started_) {
-      Abort();
-    }
-  }
-
   void OnDiskImageCreated(bool success,
                           vm_tools::concierge::DiskImageStatus status,
                           int64_t disk_size_available) override {
@@ -753,7 +747,6 @@
   const CrostiniManager::RestartId uninitialized_id_ =
       CrostiniManager::kUninitializedRestartId;
   bool abort_on_component_loaded_ = false;
-  bool abort_on_concierge_started_ = false;
   bool abort_on_disk_image_created_ = false;
   bool abort_on_vm_started_ = false;
   bool abort_on_container_created_ = false;
@@ -864,21 +857,6 @@
   ExpectRestarterUmaCount(1);
 }
 
-TEST_F(CrostiniManagerRestartTest, AbortOnConciergeStarted) {
-  abort_on_concierge_started_ = true;
-  restart_id_ = crostini_manager()->RestartCrostini(
-      container_id(),
-      base::BindOnce(&CrostiniManagerRestartTest::RestartCrostiniCallback,
-                     base::Unretained(this), run_loop()->QuitClosure()),
-      this);
-  run_loop()->Run();
-  EXPECT_FALSE(fake_concierge_client_->create_disk_image_called());
-  EXPECT_FALSE(fake_concierge_client_->start_termina_vm_called());
-  EXPECT_FALSE(fake_concierge_client_->get_container_ssh_keys_called());
-  ExpectCrostiniRestartResult(CrostiniResult::RESTART_ABORTED);
-  ExpectRestarterUmaCount(1);
-}
-
 TEST_F(CrostiniManagerRestartTest, AbortOnDiskImageCreated) {
   abort_on_disk_image_created_ = true;
   restart_id_ = crostini_manager()->RestartCrostini(
diff --git a/chrome/browser/chromeos/crostini/crostini_remover.cc b/chrome/browser/chromeos/crostini/crostini_remover.cc
index e3133ab..ed92fb8 100644
--- a/chrome/browser/chromeos/crostini/crostini_remover.cc
+++ b/chrome/browser/chromeos/crostini/crostini_remover.cc
@@ -34,15 +34,6 @@
 
 void CrostiniRemover::RemoveCrostini() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  CrostiniManager::GetForProfile(profile_)->StartConcierge(
-      base::BindOnce(&CrostiniRemover::OnConciergeStarted, this));
-}
-
-void CrostiniRemover::OnConciergeStarted(bool is_successful) {
-  if (!is_successful) {
-    std::move(callback_).Run(CrostiniResult::UNKNOWN_ERROR);
-    return;
-  }
   CrostiniManager::GetForProfile(profile_)->StopVm(
       vm_name_, base::BindOnce(&CrostiniRemover::StopVmFinished, this));
 }
diff --git a/chrome/browser/chromeos/crostini/crostini_remover.h b/chrome/browser/chromeos/crostini/crostini_remover.h
index afc43327..89c92c5 100644
--- a/chrome/browser/chromeos/crostini/crostini_remover.h
+++ b/chrome/browser/chromeos/crostini/crostini_remover.h
@@ -22,7 +22,6 @@
 
   ~CrostiniRemover();
 
-  void OnConciergeStarted(bool is_successful);
   void StopVmFinished(crostini::CrostiniResult result);
   void DestroyDiskImageFinished(bool success);
   void UninstallTerminaFinished(bool success);
diff --git a/chrome/browser/chromeos/crostini/crostini_types.mojom b/chrome/browser/chromeos/crostini/crostini_types.mojom
index 65efb5c..56420cda 100644
--- a/chrome/browser/chromeos/crostini/crostini_types.mojom
+++ b/chrome/browser/chromeos/crostini/crostini_types.mojom
@@ -7,7 +7,6 @@
 enum InstallerState {
   kStart,               // Just started installation
   kInstallImageLoader,  // Loading the Termina VM component.
-  kStartConcierge,      // Starting the Concierge D-Bus client.
   kCreateDiskImage,     // Creating the image for the Termina VM.
   kStartTerminaVm,      // Starting the Termina VM.
   kCreateContainer,     // Creating the container inside the Termina VM.
@@ -21,7 +20,6 @@
 enum InstallerError {
   kNone,
   kErrorLoadingTermina,
-  kErrorStartingConcierge,
   kErrorCreatingDiskImage,
   kErrorStartingTermina,
   kErrorStartingContainer,
diff --git a/chrome/browser/chromeos/file_manager/fake_disk_mount_manager.cc b/chrome/browser/chromeos/file_manager/fake_disk_mount_manager.cc
index 1cd1c67..baa5942 100644
--- a/chrome/browser/chromeos/file_manager/fake_disk_mount_manager.cc
+++ b/chrome/browser/chromeos/file_manager/fake_disk_mount_manager.cc
@@ -164,7 +164,14 @@
 
 bool FakeDiskMountManager::AddMountPointForTest(
     const MountPointInfo& mount_point) {
-  return false;
+  if (mount_point.mount_type == chromeos::MOUNT_TYPE_DEVICE &&
+      disks_.find(mount_point.source_path) == disks_.end()) {
+    // Device mount point must have a disk entry.
+    return false;
+  }
+
+  mount_points_.insert(std::make_pair(mount_point.mount_path, mount_point));
+  return true;
 }
 
 void FakeDiskMountManager::InvokeDiskEventForTest(
diff --git a/chrome/browser/chromeos/file_manager/path_util.cc b/chrome/browser/chromeos/file_manager/path_util.cc
index eac3c98..5877feb 100644
--- a/chrome/browser/chromeos/file_manager/path_util.cc
+++ b/chrome/browser/chromeos/file_manager/path_util.cc
@@ -33,6 +33,8 @@
 #include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chromeos/constants/chromeos_features.h"
+#include "chromeos/disks/disk.h"
+#include "chromeos/disks/disk_mount_manager.h"
 #include "components/arc/arc_util.h"
 #include "components/drive/file_system_core_util.h"
 #include "components/user_manager/user.h"
@@ -70,9 +72,13 @@
     FILE_PATH_LITERAL("/external_files");
 // Sync with the volume provider in ARC++ side.
 constexpr char kArcRemovableMediaContentUrlPrefix[] =
-    "content://org.chromium.arc.volumeprovider/removable/";
+    "content://org.chromium.arc.volumeprovider/";
+// The dummy UUID of the MyFiles volume is taken from
+// components/arc/volume_mounter/arc_volume_mounter_bridge.cc.
+// TODO(crbug.com/929031): Move MyFiles constants to a common place.
 constexpr char kArcMyFilesContentUrlPrefix[] =
-    "content://org.chromium.arc.volumeprovider/MyFiles/";
+    "content://org.chromium.arc.volumeprovider/"
+    "0000000000000000000000000000CAFEF00D2019/";
 constexpr char kArcDriveContentUrlPrefix[] =
     "content://org.chromium.arc.volumeprovider/MyDrive/";
 
@@ -140,6 +146,51 @@
   return drive_path;
 }
 
+// Extracts the volume name of a removable device. |relative_path| is expected
+// to be of the form <volume name>/..., which is relative to /media/removable.
+std::string ExtractVolumeNameFromRelativePathForRemovableMedia(
+    const base::FilePath& relative_path) {
+  std::vector<base::FilePath::StringType> components;
+  relative_path.GetComponents(&components);
+  if (components.empty()) {
+    LOG(WARNING) << "Failed to extract volume name from relative path: "
+                 << relative_path;
+    return std::string();
+  }
+  return components[0];
+}
+
+// Returns the source path of a removable device using its volume name as a key.
+// An empty string is returned when it fails to get a valid mount point from
+// DiskMountManager.
+std::string GetSourcePathForRemovableMedia(const std::string& volume_name) {
+  const std::string mount_path(
+      base::StringPrintf("%s/%s", kRemovableMediaPath, volume_name.c_str()));
+  const auto& mount_points =
+      chromeos::disks::DiskMountManager::GetInstance()->mount_points();
+  const auto found = mount_points.find(mount_path);
+  return found == mount_points.end() ? std::string()
+                                     : found->second.source_path;
+}
+
+// Returns the UUID of a removable device using its volume name as a key.
+// An empty string is returned when it fails to get valid source path and disk
+// from DiskMountManager.
+std::string GetFsUuidForRemovableMedia(const std::string& volume_name) {
+  const std::string source_path = GetSourcePathForRemovableMedia(volume_name);
+  if (source_path.empty()) {
+    LOG(WARNING) << "No source path is found for volume name: " << volume_name;
+    return std::string();
+  }
+  const chromeos::disks::Disk* disk =
+      chromeos::disks::DiskMountManager::GetInstance()->FindDiskBySourcePath(
+          source_path);
+  std::string fs_uuid = disk == nullptr ? std::string() : disk->fs_uuid();
+  if (fs_uuid.empty())
+    LOG(WARNING) << "No UUID is found for volume name: " << volume_name;
+  return fs_uuid;
+}
+
 }  // namespace
 
 const base::FilePath::CharType kRemovableMediaPath[] =
@@ -422,12 +473,29 @@
   base::FilePath relative_path;
   if (base::FilePath(kRemovableMediaPath)
           .AppendRelativePath(path, &relative_path)) {
-    *arc_url_out = GURL(kArcRemovableMediaContentUrlPrefix)
-                       .Resolve(net::EscapePath(relative_path.AsUTF8Unsafe()));
+    const std::string volume_name =
+        ExtractVolumeNameFromRelativePathForRemovableMedia(relative_path);
+    if (volume_name.empty())
+      return false;
+    const std::string fs_uuid = GetFsUuidForRemovableMedia(volume_name);
+    if (fs_uuid.empty())
+      return false;
+    // Replace the volume name in the relative path with the UUID.
+    base::FilePath relative_path_with_uuid = base::FilePath(fs_uuid);
+    if (!base::FilePath(volume_name)
+             .AppendRelativePath(relative_path, &relative_path_with_uuid)) {
+      LOG(WARNING) << "Failed to replace volume name \"" << volume_name
+                   << "\" in relative path \"" << relative_path
+                   << "\" with UUID \"" << fs_uuid << "\"";
+      return false;
+    }
+    *arc_url_out =
+        GURL(kArcRemovableMediaContentUrlPrefix)
+            .Resolve(net::EscapePath(relative_path_with_uuid.AsUTF8Unsafe()));
     return true;
   }
 
-  // Convert paths under MyFiles
+  // Convert paths under MyFiles.
   if (base::FilePath(GetMyFilesFolderForProfile(primary_profile))
           .AppendRelativePath(path, &relative_path)) {
     *arc_url_out = GURL(kArcMyFilesContentUrlPrefix)
@@ -463,6 +531,12 @@
     force_external = true;
   }
 
+  // Force external URL for files under /media/archive.
+  if (base::FilePath(kArchiveMountPath)
+          .AppendRelativePath(path, &relative_path)) {
+    force_external = true;
+  }
+
   // Force external URL for smbfs.
   chromeos::smb_client::SmbService* smb_service =
       chromeos::smb_client::SmbServiceFactory::Get(primary_profile);
diff --git a/chrome/browser/chromeos/file_manager/path_util_unittest.cc b/chrome/browser/chromeos/file_manager/path_util_unittest.cc
index b3ff2593..1c9c211 100644
--- a/chrome/browser/chromeos/file_manager/path_util_unittest.cc
+++ b/chrome/browser/chromeos/file_manager/path_util_unittest.cc
@@ -29,6 +29,7 @@
 #include "chrome/test/base/testing_profile_manager.h"
 #include "chromeos/constants/chromeos_features.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/disks/disk.h"
 #include "components/account_id/account_id.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/arc_util.h"
@@ -597,6 +598,23 @@
                                      storage::FileSystemMountOption(),
                                      crostini_mount_point_);
 
+    chromeos::disks::DiskMountManager::InitializeForTesting(
+        new FakeDiskMountManager);
+
+    // Add the disk and mount point for a fake removable device.
+    ASSERT_TRUE(
+        chromeos::disks::DiskMountManager::GetInstance()->AddDiskForTest(
+            chromeos::disks::Disk::Builder()
+                .SetDevicePath("/device/source_path")
+                .SetFileSystemUUID("0123-abcd")
+                .Build()));
+    ASSERT_TRUE(
+        chromeos::disks::DiskMountManager::GetInstance()->AddMountPointForTest(
+            chromeos::disks::DiskMountManager::MountPointInfo(
+                "/device/source_path", "/media/removable/a",
+                chromeos::MOUNT_TYPE_DEVICE,
+                chromeos::disks::MOUNT_CONDITION_NONE)));
+
     // Run pending async tasks resulting from profile construction to ensure
     // these are complete before the test begins.
     base::RunLoop().RunUntilIdle();
@@ -610,6 +628,8 @@
 
     // Run all pending tasks before destroying testing profile.
     base::RunLoop().RunUntilIdle();
+
+    chromeos::disks::DiskMountManager::Shutdown();
   }
 
  protected:
@@ -634,7 +654,7 @@
   GURL url;
   EXPECT_TRUE(ConvertPathToArcUrl(
       base::FilePath::FromUTF8Unsafe("/media/removable/a/b/c"), &url));
-  EXPECT_EQ(GURL("content://org.chromium.arc.volumeprovider/removable/a/b/c"),
+  EXPECT_EQ(GURL("content://org.chromium.arc.volumeprovider/0123-abcd/b/c"),
             url);
 }
 
@@ -646,7 +666,9 @@
       chromeos::ProfileHelper::Get()->GetProfileByUserIdHashForTest(
           "user@gmail.com-hash"));
   EXPECT_TRUE(ConvertPathToArcUrl(myfiles.AppendASCII("a/b/c"), &url));
-  EXPECT_EQ(GURL("content://org.chromium.arc.volumeprovider/MyFiles/a/b/c"),
+  EXPECT_EQ(GURL("content://org.chromium.arc.volumeprovider/"
+                 "0000000000000000000000000000CAFEF00D2019/"
+                 "a/b/c"),
             url);
 }
 
@@ -729,9 +751,9 @@
           [](base::RunLoop* run_loop, const std::vector<GURL>& urls) {
             run_loop->Quit();
             ASSERT_EQ(1U, urls.size());
-            EXPECT_EQ(GURL("content://org.chromium.arc.volumeprovider/"
-                           "removable/a/b/c"),
-                      urls[0]);
+            EXPECT_EQ(
+                GURL("content://org.chromium.arc.volumeprovider/0123-abcd/b/c"),
+                urls[0]);
           },
           &run_loop));
   run_loop.Run();
@@ -751,9 +773,10 @@
           [](base::RunLoop* run_loop, const std::vector<GURL>& urls) {
             run_loop->Quit();
             ASSERT_EQ(1U, urls.size());
-            EXPECT_EQ(
-                GURL("content://org.chromium.arc.volumeprovider/MyFiles/a/b/c"),
-                urls[0]);
+            EXPECT_EQ(GURL("content://org.chromium.arc.volumeprovider/"
+                           "0000000000000000000000000000CAFEF00D2019/"
+                           "a/b/c"),
+                      urls[0]);
           },
           &run_loop));
   run_loop.Run();
@@ -935,9 +958,9 @@
             run_loop->Quit();
             ASSERT_EQ(4U, urls.size());
             EXPECT_EQ(GURL(), urls[0]);  // Invalid URL.
-            EXPECT_EQ(GURL("content://org.chromium.arc.volumeprovider/"
-                           "removable/a/b/c"),
-                      urls[1]);
+            EXPECT_EQ(
+                GURL("content://org.chromium.arc.volumeprovider/0123-abcd/b/c"),
+                urls[1]);
             EXPECT_EQ(GURL("content://org.chromium.arc.chromecontentprovider/"
                            "externalfile%3Adrivefs-b1f44746e7144c3caafeacaa8bb5"
                            "c569%2Fa%2Fb%2Fc"),
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
index dc6bed5..9a09c0b 100644
--- a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
+++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
@@ -1145,7 +1145,7 @@
             unfiltered_input_method_id)) {
       // Legacy IMEs or xkb layouts are alwayes active.
       state->active_input_method_ids.push_back(unfiltered_input_method_id);
-    } else if (component_extension_ime_manager_->IsWhitelisted(
+    } else if (component_extension_ime_manager_->IsAllowlisted(
                    unfiltered_input_method_id)) {
       if (enable_extension_loading_) {
         component_extension_ime_manager_->LoadComponentExtensionIME(
diff --git a/chrome/browser/chromeos/input_method/native_input_method_engine_browsertest.cc b/chrome/browser/chromeos/input_method/native_input_method_engine_browsertest.cc
index 312ffe2..9f287e1e 100644
--- a/chrome/browser/chromeos/input_method/native_input_method_engine_browsertest.cc
+++ b/chrome/browser/chromeos/input_method/native_input_method_engine_browsertest.cc
@@ -142,6 +142,8 @@
   NativeInputMethodEngineTest() : input_method_(this) {
     feature_list_.InitWithFeatures(
         /*enabled_features=*/{chromeos::features::kAssistPersonalInfo,
+                              chromeos::features::kAssistPersonalInfoEmail,
+                              chromeos::features::kAssistPersonalInfoName,
                               chromeos::features::kEmojiSuggestAddition},
         /*disabled_features=*/{});
   }
@@ -639,7 +641,7 @@
  public:
   NativeInputMethodEngineAssistiveOff() {
     feature_list_.InitWithFeatures(
-        /*enabled_features=*/{},
+        /*enabled_features=*/{chromeos::features::kAssistPersonalInfoName},
         /*disabled_features=*/{chromeos::features::kAssistPersonalInfo,
                                chromeos::features::kEmojiSuggestAddition});
   }
diff --git a/chrome/browser/chromeos/input_method/personal_info_suggester.cc b/chrome/browser/chromeos/input_method/personal_info_suggester.cc
index cc1673d..a5e65b8 100644
--- a/chrome/browser/chromeos/input_method/personal_info_suggester.cc
+++ b/chrome/browser/chromeos/input_method/personal_info_suggester.cc
@@ -7,6 +7,7 @@
 #include "chrome/browser/extensions/api/input_ime/input_ime_api.h"
 
 #include "ash/public/cpp/ash_pref_names.h"
+#include "base/feature_list.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/no_destructor.h"
 #include "base/strings/string_util.h"
@@ -17,6 +18,7 @@
 #include "chrome/browser/chromeos/input_method/ui/suggestion_details.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "components/autofill/core/browser/data_model/autofill_profile.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
@@ -133,36 +135,54 @@
   if (!(RE2::FullMatch(lower_case_utf8_text, ".* $"))) {
     return AssistiveType::kGenericAction;
   }
-  if (RE2::FullMatch(lower_case_utf8_text,
-                     base::StringPrintf(".*%s%s%s", kSingleSubjectRegex,
-                                        kEmailRegex, kTriggersRegex))) {
-    return AssistiveType::kPersonalEmail;
+
+  if (base::FeatureList::IsEnabled(
+          chromeos::features::kAssistPersonalInfoAddress)) {
+    if (RE2::FullMatch(
+            lower_case_utf8_text,
+            base::StringPrintf(".*%s%s%s", kSingleOrPluralSubjectRegex,
+                               kAddressRegex, kTriggersRegex))) {
+      return AssistiveType::kPersonalAddress;
+    }
   }
-  if (RE2::FullMatch(lower_case_utf8_text,
-                     base::StringPrintf(".*%s%s%s", kSingleSubjectRegex,
-                                        kNameRegex, kTriggersRegex))) {
-    return AssistiveType::kPersonalName;
+
+  if (base::FeatureList::IsEnabled(
+          chromeos::features::kAssistPersonalInfoEmail)) {
+    if (RE2::FullMatch(lower_case_utf8_text,
+                       base::StringPrintf(".*%s%s%s", kSingleSubjectRegex,
+                                          kEmailRegex, kTriggersRegex))) {
+      return AssistiveType::kPersonalEmail;
+    }
   }
-  if (RE2::FullMatch(lower_case_utf8_text,
-                     base::StringPrintf(".*%s%s%s", kSingleOrPluralSubjectRegex,
-                                        kAddressRegex, kTriggersRegex))) {
-    return AssistiveType::kPersonalAddress;
+
+  if (base::FeatureList::IsEnabled(
+          chromeos::features::kAssistPersonalInfoName)) {
+    if (RE2::FullMatch(lower_case_utf8_text,
+                       base::StringPrintf(".*%s%s%s", kSingleSubjectRegex,
+                                          kNameRegex, kTriggersRegex))) {
+      return AssistiveType::kPersonalName;
+    }
+    if (RE2::FullMatch(lower_case_utf8_text,
+                       base::StringPrintf(".*%s%s%s", kSingleSubjectRegex,
+                                          kFirstNameRegex, kTriggersRegex))) {
+      return AssistiveType::kPersonalFirstName;
+    }
+    if (RE2::FullMatch(lower_case_utf8_text,
+                       base::StringPrintf(".*%s%s%s", kSingleSubjectRegex,
+                                          kLastNameRegex, kTriggersRegex))) {
+      return AssistiveType::kPersonalLastName;
+    }
   }
-  if (RE2::FullMatch(lower_case_utf8_text,
-                     base::StringPrintf(".*%s%s%s", kSingleSubjectRegex,
-                                        kPhoneNumberRegex, kTriggersRegex))) {
-    return AssistiveType::kPersonalPhoneNumber;
+
+  if (base::FeatureList::IsEnabled(
+          chromeos::features::kAssistPersonalInfoPhoneNumber)) {
+    if (RE2::FullMatch(lower_case_utf8_text,
+                       base::StringPrintf(".*%s%s%s", kSingleSubjectRegex,
+                                          kPhoneNumberRegex, kTriggersRegex))) {
+      return AssistiveType::kPersonalPhoneNumber;
+    }
   }
-  if (RE2::FullMatch(lower_case_utf8_text,
-                     base::StringPrintf(".*%s%s%s", kSingleSubjectRegex,
-                                        kFirstNameRegex, kTriggersRegex))) {
-    return AssistiveType::kPersonalFirstName;
-  }
-  if (RE2::FullMatch(lower_case_utf8_text,
-                     base::StringPrintf(".*%s%s%s", kSingleSubjectRegex,
-                                        kLastNameRegex, kTriggersRegex))) {
-    return AssistiveType::kPersonalLastName;
-  }
+
   return AssistiveType::kGenericAction;
 }
 
diff --git a/chrome/browser/chromeos/input_method/personal_info_suggester_unittest.cc b/chrome/browser/chromeos/input_method/personal_info_suggester_unittest.cc
index 2052552..38b4f0a1 100644
--- a/chrome/browser/chromeos/input_method/personal_info_suggester_unittest.cc
+++ b/chrome/browser/chromeos/input_method/personal_info_suggester_unittest.cc
@@ -8,9 +8,11 @@
 #include "base/guid.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/chromeos/input_method/ui/suggestion_details.h"
 #include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h"
 #include "chrome/test/base/testing_profile.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/data_model/autofill_profile.h"
@@ -191,6 +193,11 @@
 };
 
 TEST_F(PersonalInfoSuggesterTest, SuggestEmail) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{chromeos::features::kAssistPersonalInfoEmail},
+      /*disabled_features=*/{});
+
   profile_->set_profile_name(base::UTF16ToUTF8(email_));
 
   suggester_->Suggest(base::UTF8ToUTF16("my email is "));
@@ -205,7 +212,24 @@
   suggestion_handler_->VerifySuggestion(email_, 0);
 }
 
-TEST_F(PersonalInfoSuggesterTest, DoNotSuggestEmail) {
+TEST_F(PersonalInfoSuggesterTest, DoNotSuggestEmailWhenFlagIsDisabled) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{},
+      /*disabled_features=*/{chromeos::features::kAssistPersonalInfoEmail});
+
+  profile_->set_profile_name(base::UTF16ToUTF8(email_));
+
+  suggester_->Suggest(base::UTF8ToUTF16("my email is "));
+  suggestion_handler_->VerifySuggestion(base::EmptyString16(), 0);
+}
+
+TEST_F(PersonalInfoSuggesterTest, DoNotSuggestEmailWhenPrefixDoesNotMatch) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{chromeos::features::kAssistPersonalInfoEmail},
+      /*disabled_features=*/{});
+
   profile_->set_profile_name(base::UTF16ToUTF8(email_));
 
   suggester_->Suggest(base::UTF8ToUTF16("my email is John"));
@@ -216,6 +240,11 @@
 }
 
 TEST_F(PersonalInfoSuggesterTest, DoNotSuggestWhenVirtualKeyboardEnabled) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{chromeos::features::kAssistPersonalInfoEmail},
+      /*disabled_features=*/{});
+
   chrome_keyboard_controller_client_->set_keyboard_visible_for_test(true);
   profile_->set_profile_name(base::UTF16ToUTF8(email_));
 
@@ -225,6 +254,11 @@
 
 TEST_F(PersonalInfoSuggesterTest,
        SendsEmailSuggestionToExtensionWhenVirtualKeyboardEnabled) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{chromeos::features::kAssistPersonalInfoEmail},
+      /*disabled_features=*/{});
+
   chrome_keyboard_controller_client_->set_keyboard_visible_for_test(true);
   profile_->set_profile_name(base::UTF16ToUTF8(email_));
 
@@ -234,6 +268,11 @@
 }
 
 TEST_F(PersonalInfoSuggesterTest, SuggestNames) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{chromeos::features::kAssistPersonalInfoName},
+      /*disabled_features=*/{});
+
   autofill::AutofillProfile autofill_profile(base::GenerateGUID(),
                                              autofill::test::kEmptyOrigin);
   autofill_profile.SetRawInfo(autofill::ServerFieldType::NAME_FIRST,
@@ -258,7 +297,36 @@
   suggestion_handler_->VerifySuggestion(full_name_, 0);
 }
 
-TEST_F(PersonalInfoSuggesterTest, DoNotSuggestNames) {
+TEST_F(PersonalInfoSuggesterTest, DoNotSuggestNamesWhenFlagIsDisabled) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{},
+      /*disabled_features=*/{chromeos::features::kAssistPersonalInfoName});
+
+  autofill::AutofillProfile autofill_profile(base::GenerateGUID(),
+                                             autofill::test::kEmptyOrigin);
+  autofill_profile.SetRawInfo(autofill::ServerFieldType::NAME_FIRST,
+                              first_name_);
+  autofill_profile.SetRawInfo(autofill::ServerFieldType::NAME_LAST, last_name_);
+  autofill_profile.SetRawInfo(autofill::ServerFieldType::NAME_FULL, full_name_);
+  personal_data_->AddProfile(autofill_profile);
+
+  suggester_->Suggest(base::UTF8ToUTF16("my first name is "));
+  suggestion_handler_->VerifySuggestion(base::EmptyString16(), 0);
+
+  suggester_->Suggest(base::UTF8ToUTF16("my last name is: "));
+  suggestion_handler_->VerifySuggestion(base::EmptyString16(), 0);
+
+  suggester_->Suggest(base::UTF8ToUTF16("my name is "));
+  suggestion_handler_->VerifySuggestion(base::EmptyString16(), 0);
+}
+
+TEST_F(PersonalInfoSuggesterTest, DoNotSuggestNamesWhenPrefixDoesNotMatch) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{chromeos::features::kAssistPersonalInfoEmail},
+      /*disabled_features=*/{});
+
   autofill::AutofillProfile autofill_profile(base::GenerateGUID(),
                                              autofill::test::kEmptyOrigin);
   autofill_profile.SetRawInfo(autofill::ServerFieldType::NAME_FIRST,
@@ -281,6 +349,11 @@
 }
 
 TEST_F(PersonalInfoSuggesterTest, SuggestAddress) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{chromeos::features::kAssistPersonalInfoAddress},
+      /*disabled_features=*/{});
+
   autofill::CountryNames::SetLocaleString("en-US");
   autofill::AutofillProfile autofill_profile(base::GenerateGUID(),
                                              autofill::test::kEmptyOrigin);
@@ -316,7 +389,37 @@
   suggestion_handler_->VerifySuggestion(address_, 0);
 }
 
-TEST_F(PersonalInfoSuggesterTest, DoNotSuggestAddress) {
+TEST_F(PersonalInfoSuggesterTest, DoNotSuggestAddressWhenFlagIsDisabled) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{},
+      /*disabled_features=*/{chromeos::features::kAssistPersonalInfoAddress});
+
+  autofill::CountryNames::SetLocaleString("en-US");
+  autofill::AutofillProfile autofill_profile(base::GenerateGUID(),
+                                             autofill::test::kEmptyOrigin);
+  autofill_profile.SetRawInfo(autofill::ServerFieldType::ADDRESS_HOME_LINE1,
+                              base::UTF8ToUTF16("1 Dream Road"));
+  autofill_profile.SetRawInfo(autofill::ServerFieldType::ADDRESS_HOME_CITY,
+                              base::UTF8ToUTF16("Hollywood"));
+  autofill_profile.SetRawInfo(autofill::ServerFieldType::ADDRESS_HOME_ZIP,
+                              base::UTF8ToUTF16("12345"));
+  autofill_profile.SetRawInfo(autofill::ServerFieldType::ADDRESS_HOME_STATE,
+                              base::UTF8ToUTF16("CA"));
+  autofill_profile.SetRawInfo(autofill::ServerFieldType::ADDRESS_HOME_COUNTRY,
+                              base::UTF8ToUTF16("US"));
+  personal_data_->AddProfile(autofill_profile);
+
+  suggester_->Suggest(base::UTF8ToUTF16("my address is "));
+  suggestion_handler_->VerifySuggestion(base::EmptyString16(), 0);
+}
+
+TEST_F(PersonalInfoSuggesterTest, DoNotSuggestAddressWhenPrefixDoesNotMatch) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{chromeos::features::kAssistPersonalInfoAddress},
+      /*disabled_features=*/{});
+
   autofill::CountryNames::SetLocaleString("en-US");
   autofill::AutofillProfile autofill_profile(base::GenerateGUID(),
                                              autofill::test::kEmptyOrigin);
@@ -343,6 +446,11 @@
 }
 
 TEST_F(PersonalInfoSuggesterTest, SuggestPhoneNumber) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{chromeos::features::kAssistPersonalInfoPhoneNumber},
+      /*disabled_features=*/{});
+
   autofill::AutofillProfile autofill_profile(base::GenerateGUID(),
                                              autofill::test::kEmptyOrigin);
   autofill_profile.SetRawInfo(
@@ -369,7 +477,30 @@
   suggestion_handler_->VerifySuggestion(phone_number_, 0);
 }
 
-TEST_F(PersonalInfoSuggesterTest, DoNotSuggestPhoneNumber) {
+TEST_F(PersonalInfoSuggesterTest, DoNotSuggestPhoneNumberWhenFlagIsDisabled) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{},
+      /*disabled_features=*/{
+          chromeos::features::kAssistPersonalInfoPhoneNumber});
+
+  autofill::AutofillProfile autofill_profile(base::GenerateGUID(),
+                                             autofill::test::kEmptyOrigin);
+  autofill_profile.SetRawInfo(
+      autofill::ServerFieldType::PHONE_HOME_WHOLE_NUMBER, phone_number_);
+  personal_data_->AddProfile(autofill_profile);
+
+  suggester_->Suggest(base::UTF8ToUTF16("my phone number is "));
+  suggestion_handler_->VerifySuggestion(base::EmptyString16(), 0);
+}
+
+TEST_F(PersonalInfoSuggesterTest,
+       DoNotSuggestPhoneNumberWhenPrefixDoesNotMatch) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{chromeos::features::kAssistPersonalInfoPhoneNumber},
+      /*disabled_features=*/{});
+
   autofill::AutofillProfile autofill_profile(base::GenerateGUID(),
                                              autofill::test::kEmptyOrigin);
   autofill_profile.SetRawInfo(
@@ -390,6 +521,11 @@
 }
 
 TEST_F(PersonalInfoSuggesterTest, AcceptSuggestionWithDownEnter) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{chromeos::features::kAssistPersonalInfoEmail},
+      /*disabled_features=*/{});
+
   profile_->set_profile_name(base::UTF16ToUTF8(email_));
 
   suggester_->Suggest(base::UTF8ToUTF16("my email is "));
@@ -401,6 +537,11 @@
 }
 
 TEST_F(PersonalInfoSuggesterTest, AcceptSuggestionWithUpEnter) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{chromeos::features::kAssistPersonalInfoEmail},
+      /*disabled_features=*/{});
+
   DictionaryPrefUpdate update(profile_->GetPrefs(),
                               prefs::kAssistiveInputFeatureSettings);
   update->SetIntKey(kPersonalInfoSuggesterAcceptanceCount, 1);
@@ -415,6 +556,11 @@
 }
 
 TEST_F(PersonalInfoSuggesterTest, DismissSuggestion) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{chromeos::features::kAssistPersonalInfoName},
+      /*disabled_features=*/{});
+
   autofill::AutofillProfile autofill_profile(base::GenerateGUID(),
                                              autofill::test::kEmptyOrigin);
   autofill_profile.SetRawInfo(autofill::ServerFieldType::NAME_FULL, full_name_);
@@ -427,6 +573,11 @@
 }
 
 TEST_F(PersonalInfoSuggesterTest, SuggestWithConfirmedLength) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{chromeos::features::kAssistPersonalInfoPhoneNumber},
+      /*disabled_features=*/{});
+
   autofill::AutofillProfile autofill_profile(base::GenerateGUID(),
                                              autofill::test::kEmptyOrigin);
   autofill_profile.SetRawInfo(
@@ -440,6 +591,11 @@
 
 TEST_F(PersonalInfoSuggesterTest,
        DoNotAnnounceSpokenFeedbackWhenChromeVoxIsOff) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{chromeos::features::kAssistPersonalInfoEmail},
+      /*disabled_features=*/{});
+
   profile_->set_profile_name(base::UTF16ToUTF8(email_));
   profile_->GetPrefs()->SetBoolean(
       ash::prefs::kAccessibilitySpokenFeedbackEnabled, false);
@@ -455,6 +611,11 @@
 }
 
 TEST_F(PersonalInfoSuggesterTest, AnnounceSpokenFeedbackWhenChromeVoxIsOn) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{chromeos::features::kAssistPersonalInfoEmail},
+      /*disabled_features=*/{});
+
   profile_->set_profile_name(base::UTF16ToUTF8(email_));
   profile_->GetPrefs()->SetBoolean(
       ash::prefs::kAccessibilitySpokenFeedbackEnabled, true);
@@ -482,6 +643,11 @@
 }
 
 TEST_F(PersonalInfoSuggesterTest, DoNotShowAnnotationAfterMaxAcceptanceCount) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{chromeos::features::kAssistPersonalInfoEmail},
+      /*disabled_features=*/{});
+
   for (int i = 0; i < kMaxAcceptanceCount; i++) {
     suggester_->Suggest(base::UTF8ToUTF16("my email is "));
     SendKeyboardEvent("Down");
@@ -493,6 +659,11 @@
 }
 
 TEST_F(PersonalInfoSuggesterTest, ShowSettingLink) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{chromeos::features::kAssistPersonalInfoEmail},
+      /*disabled_features=*/{});
+
   DictionaryPrefUpdate update(profile_->GetPrefs(),
                               prefs::kAssistiveInputFeatureSettings);
   update->RemoveKey(kPersonalInfoSuggesterShowSettingCount);
@@ -508,6 +679,11 @@
 }
 
 TEST_F(PersonalInfoSuggesterTest, DoNotShowSettingLinkAfterAcceptance) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{chromeos::features::kAssistPersonalInfoEmail},
+      /*disabled_features=*/{});
+
   DictionaryPrefUpdate update(profile_->GetPrefs(),
                               prefs::kAssistiveInputFeatureSettings);
   update->SetIntKey(kPersonalInfoSuggesterShowSettingCount, 0);
@@ -521,6 +697,11 @@
 }
 
 TEST_F(PersonalInfoSuggesterTest, ClickSettingsWithDownDownEnter) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{chromeos::features::kAssistPersonalInfoEmail},
+      /*disabled_features=*/{});
+
   DictionaryPrefUpdate update(profile_->GetPrefs(),
                               prefs::kAssistiveInputFeatureSettings);
   update->RemoveKey(kPersonalInfoSuggesterShowSettingCount);
@@ -537,6 +718,11 @@
 }
 
 TEST_F(PersonalInfoSuggesterTest, ClickSettingsWithUpEnter) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{chromeos::features::kAssistPersonalInfoEmail},
+      /*disabled_features=*/{});
+
   DictionaryPrefUpdate update(profile_->GetPrefs(),
                               prefs::kAssistiveInputFeatureSettings);
   update->RemoveKey(kPersonalInfoSuggesterShowSettingCount);
@@ -552,6 +738,11 @@
 }
 
 TEST_F(PersonalInfoSuggesterTest, RecordsTimeToAccept) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{chromeos::features::kAssistPersonalInfoEmail},
+      /*disabled_features=*/{});
+
   base::HistogramTester histogram_tester;
   histogram_tester.ExpectTotalCount(
       "InputMethod.Assistive.TimeToAccept.PersonalInfo", 0);
@@ -568,6 +759,11 @@
 }
 
 TEST_F(PersonalInfoSuggesterTest, RecordsTimeToDismiss) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{chromeos::features::kAssistPersonalInfoEmail},
+      /*disabled_features=*/{});
+
   base::HistogramTester histogram_tester;
   histogram_tester.ExpectTotalCount(
       "InputMethod.Assistive.TimeToAccept.PersonalInfo", 0);
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc
index f2772aa..985eae6 100644
--- a/chrome/browser/chromeos/login/chrome_restart_request.cc
+++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -86,7 +86,6 @@
     sandbox::policy::switches::kGpuSandboxAllowSysVShm,
     sandbox::policy::switches::kGpuSandboxFailuresFatal,
     sandbox::policy::switches::kNoSandbox,
-    ::switches::kBlinkSettings,
     ::switches::kDisable2dCanvasImageChromium,
     ::switches::kDisableAccelerated2dCanvas,
     ::switches::kDisableAcceleratedMjpegDecode,
@@ -103,7 +102,6 @@
     ::switches::kDisableGpuRasterization,
     ::switches::kDisableOopRasterization,
     ::switches::kDisablePepper3DImageChromium,
-    ::switches::kDisableThreadedScrolling,
     ::switches::kDisableTouchDragDrop,
     ::switches::kDisableVideoCaptureUseGpuMemoryBuffer,
     ::switches::kDisableYUVImageDecoding,
@@ -162,10 +160,12 @@
     ash::switches::kAuraLegacyPowerButton,
     ash::switches::kEnableDimShelf,
     ash::switches::kShowTaps,
+    blink::switches::kBlinkSettings,
     blink::switches::kDisableLowResTiling,
     blink::switches::kDisablePartialRaster,
     blink::switches::kDisablePreferCompositingToLCDText,
     blink::switches::kDisableRGBA4444Textures,
+    blink::switches::kDisableThreadedScrolling,
     blink::switches::kDisableZeroCopy,
     blink::switches::kEnableLowResTiling,
     blink::switches::kEnablePreferCompositingToLCDText,
diff --git a/chrome/browser/chromeos/note_taking_helper_unittest.cc b/chrome/browser/chromeos/note_taking_helper_unittest.cc
index 0aa56d7..c8faeda 100644
--- a/chrome/browser/chromeos/note_taking_helper_unittest.cc
+++ b/chrome/browser/chromeos/note_taking_helper_unittest.cc
@@ -18,6 +18,7 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/arc/fileapi/arc_file_system_bridge.h"
+#include "chrome/browser/chromeos/file_manager/fake_disk_mount_manager.h"
 #include "chrome/browser/chromeos/file_manager/path_util.h"
 #include "chrome/browser/chromeos/note_taking_controller_client.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -30,6 +31,7 @@
 #include "chrome/test/base/testing_profile_manager.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/session_manager/fake_session_manager_client.h"
+#include "chromeos/disks/disk.h"
 #include "components/arc/arc_prefs.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/arc_util.h"
@@ -964,6 +966,21 @@
 }
 
 TEST_F(NoteTakingHelperTest, LaunchAndroidAppWithPath) {
+  chromeos::disks::DiskMountManager::InitializeForTesting(
+      new file_manager::FakeDiskMountManager);
+
+  ASSERT_TRUE(chromeos::disks::DiskMountManager::GetInstance()->AddDiskForTest(
+      chromeos::disks::Disk::Builder()
+          .SetDevicePath("/device/source_path")
+          .SetFileSystemUUID("0123-abcd")
+          .Build()));
+  ASSERT_TRUE(
+      chromeos::disks::DiskMountManager::GetInstance()->AddMountPointForTest(
+          chromeos::disks::DiskMountManager::MountPointInfo(
+              "/device/source_path", "/media/removable/UNTITLED",
+              chromeos::MOUNT_TYPE_DEVICE,
+              chromeos::disks::MOUNT_CONDITION_NONE)));
+
   const std::string kPackage = "org.chromium.package";
   std::vector<IntentHandlerInfoPtr> handlers;
   handlers.emplace_back(CreateIntentHandlerInfo("App", kPackage));
@@ -993,7 +1010,7 @@
 
   const base::FilePath kRemovablePath =
       base::FilePath(file_manager::util::kRemovableMediaPath)
-          .Append("image.jpg");
+          .Append("UNTITLED/image.jpg");
   intent_helper_.clear_handled_intents();
   file_system_->clear_handled_requests();
   helper()->LaunchAppForNewNote(profile(), kRemovablePath);
@@ -1024,6 +1041,8 @@
   histogram_tester.ExpectUniqueSample(
       NoteTakingHelper::kDefaultLaunchResultHistogramName,
       static_cast<int>(LaunchResult::ANDROID_FAILED_TO_CONVERT_PATH), 1);
+
+  chromeos::disks::DiskMountManager::Shutdown();
 }
 
 TEST_F(NoteTakingHelperTest, NoAppsAvailable) {
diff --git a/chrome/browser/diagnostics/sqlite_diagnostics.cc b/chrome/browser/diagnostics/sqlite_diagnostics.cc
index 6e6b8951..60e0074 100644
--- a/chrome/browser/diagnostics/sqlite_diagnostics.cc
+++ b/chrome/browser/diagnostics/sqlite_diagnostics.cc
@@ -28,7 +28,7 @@
 #include "sql/database.h"
 #include "sql/statement.h"
 #include "storage/browser/database/database_tracker.h"
-#include "third_party/sqlite/sqlite3.h"
+#include "third_party/sqlite/sqlite3.h"  // nogncheck crbug.com/1126800
 
 #if defined(OS_CHROMEOS)
 #include "chromeos/constants/chromeos_constants.h"
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
index e7fcd26..50cf2fb 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
@@ -557,7 +557,7 @@
   chromeos::input_method::InputMethodDescriptors descriptors;
   // Only creates descriptors for 3rd party IME extension, because the
   // descriptors for component IME extensions are managed by InputMethodUtil.
-  if (!comp_ext_ime_manager->IsWhitelistedExtension(extension_id)) {
+  if (!comp_ext_ime_manager->IsAllowlistedExtension(extension_id)) {
     for (const auto& component : input_components) {
       DCHECK(component.type == INPUT_COMPONENT_TYPE_IME);
 
@@ -1056,7 +1056,7 @@
   chromeos::ComponentExtensionIMEManager* comp_ext_ime_manager =
       manager->GetComponentExtensionIMEManager();
 
-  if (comp_ext_ime_manager->IsWhitelistedExtension(extension->id())) {
+  if (comp_ext_ime_manager->IsAllowlistedExtension(extension->id())) {
     // Since the first party ime is not allow to uninstall, and when it's
     // unloaded unexpectedly, OS will recover the extension at once.
     // So should not unregister the IMEs. Otherwise the IME icons on the
diff --git a/chrome/browser/extensions/api/terminal/crostini_startup_status.cc b/chrome/browser/extensions/api/terminal/crostini_startup_status.cc
index 46b9d08..ccdbe0e 100644
--- a/chrome/browser/extensions/api/terminal/crostini_startup_status.cc
+++ b/chrome/browser/extensions/api/terminal/crostini_startup_status.cc
@@ -100,9 +100,6 @@
           {InstallerState::kInstallImageLoader,
            l10n_util::GetStringUTF8(
                IDS_CROSTINI_TERMINAL_STATUS_INSTALL_IMAGE_LOADER)},
-          {InstallerState::kStartConcierge,
-           l10n_util::GetStringUTF8(
-               IDS_CROSTINI_TERMINAL_STATUS_START_CONCIERGE)},
           {InstallerState::kCreateDiskImage,
            l10n_util::GetStringUTF8(
                IDS_CROSTINI_TERMINAL_STATUS_CREATE_DISK_IMAGE)},
diff --git a/chrome/browser/extensions/install_signer.cc b/chrome/browser/extensions/install_signer.cc
index ac4c0758..e6f69bce 100644
--- a/chrome/browser/extensions/install_signer.cc
+++ b/chrome/browser/extensions/install_signer.cc
@@ -37,7 +37,7 @@
 #include "url/gurl.h"
 
 #if BUILDFLAG(ENABLE_RLZ)
-#include "rlz/lib/machine_id.h"
+#include "rlz/lib/machine_id.h"  // nogncheck crbug.com/1125897
 #endif
 
 namespace {
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index a42bf75..7b46ad9 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1890,6 +1890,11 @@
     "expiry_milestone": 88
   },
   {
+    "name": "enable-oop-print-drivers",
+    "owners": [ "awscreen", "thestig" ],
+    "expiry_milestone": 92
+  },
+  {
     "name": "enable-oop-rasterization",
     "owners": [ "enne", "khushalsagar" ],
     "expiry_milestone": 86
@@ -4344,6 +4349,11 @@
     "expiry_milestone": 88
   },
   {
+    "name": "tab-groups-auto-create",
+    "owners": [ "chrome-desktop-ui-seattle@google.com", "xialinyan" ],
+    "expiry_milestone": 89
+  },
+  {
     "name": "tab-groups-collapse",
     "owners": [ "chrome-desktop-ui-seattle@google.com", "xialinyan" ],
     "expiry_milestone": 89
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 4b0f7c5a..f810a0b 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2311,6 +2311,10 @@
     "Allows users to organize tabs into visually distinct groups, e.g. to "
     "separate tabs associated with different tasks.";
 
+const char kTabGroupsAutoCreateName[] = "Tab Groups Auto Create";
+const char kTabGroupsAutoCreateDescription[] =
+    "Automatically creates groups for users, if tab groups are enabled.";
+
 const char kTabGroupsCollapseName[] = "Tab Groups Collapse";
 const char kTabGroupsCollapseDescription[] =
     "Allows a tab group to be collapsible and expandable, if tab groups are "
@@ -4506,6 +4510,12 @@
     "Enables the Media Feeds background fetch feature which allows feeds to be "
     "fetched in the background. Requires #enable-media-feeds to be enabled. ";
 
+const char kEnableOopPrintDriversName[] =
+    "Enables Out-of-Process Printer Drivers";
+const char kEnableOopPrintDriversDescription[] =
+    "Enables printing interactions with the operating system to be performed "
+    "out-of-process.";
+
 const char kRemoteCopyReceiverName[] =
     "Enables the remote copy feature to receive messages";
 const char kRemoteCopyReceiverDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 94e20f0..6afb426 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1326,6 +1326,9 @@
 extern const char kTabGroupsName[];
 extern const char kTabGroupsDescription[];
 
+extern const char kTabGroupsAutoCreateName[];
+extern const char kTabGroupsAutoCreateDescription[];
+
 extern const char kTabGroupsCollapseName[];
 extern const char kTabGroupsCollapseDescription[];
 
@@ -2626,6 +2629,9 @@
 extern const char kEnableMediaFeedsBackgroundFetchName[];
 extern const char kEnableMediaFeedsBackgroundFetchDescription[];
 
+extern const char kEnableOopPrintDriversName[];
+extern const char kEnableOopPrintDriversDescription[];
+
 extern const char kRemoteCopyReceiverName[];
 extern const char kRemoteCopyReceiverDescription[];
 
diff --git a/chrome/browser/lifetime/browser_shutdown.cc b/chrome/browser/lifetime/browser_shutdown.cc
index a6025cf..0e35788 100644
--- a/chrome/browser/lifetime/browser_shutdown.cc
+++ b/chrome/browser/lifetime/browser_shutdown.cc
@@ -67,7 +67,7 @@
 #endif
 
 #if BUILDFLAG(ENABLE_RLZ)
-#include "components/rlz/rlz_tracker.h"
+#include "components/rlz/rlz_tracker.h"  // nogncheck crbug.com/1125897
 #endif
 
 #if BUILDFLAG(CLANG_PROFILING_INSIDE_SANDBOX)
diff --git a/chrome/browser/nearby_sharing/certificates/BUILD.gn b/chrome/browser/nearby_sharing/certificates/BUILD.gn
index 6685920..45b57b9 100644
--- a/chrome/browser/nearby_sharing/certificates/BUILD.gn
+++ b/chrome/browser/nearby_sharing/certificates/BUILD.gn
@@ -12,6 +12,7 @@
     "nearby_share_certificate_manager.h",
     "nearby_share_certificate_manager_impl.cc",
     "nearby_share_certificate_manager_impl.h",
+    "nearby_share_certificate_storage.cc",
     "nearby_share_certificate_storage.h",
     "nearby_share_certificate_storage_impl.cc",
     "nearby_share_certificate_storage_impl.h",
diff --git a/chrome/browser/nearby_sharing/certificates/fake_nearby_share_certificate_storage.cc b/chrome/browser/nearby_sharing/certificates/fake_nearby_share_certificate_storage.cc
index a6c19f28..c8166c3 100644
--- a/chrome/browser/nearby_sharing/certificates/fake_nearby_share_certificate_storage.cc
+++ b/chrome/browser/nearby_sharing/certificates/fake_nearby_share_certificate_storage.cc
@@ -87,12 +87,6 @@
 }
 
 base::Optional<base::Time>
-FakeNearbyShareCertificateStorage::NextPrivateCertificateExpirationTime()
-    const {
-  return next_private_certificate_expiration_time_;
-}
-
-base::Optional<base::Time>
 FakeNearbyShareCertificateStorage::NextPublicCertificateExpirationTime() const {
   return next_public_certificate_expiration_time_;
 }
@@ -125,10 +119,6 @@
                                                          std::move(callback));
 }
 
-void FakeNearbyShareCertificateStorage::ClearPrivateCertificates() {
-  ++num_clear_private_certificates_calls_;
-}
-
 void FakeNearbyShareCertificateStorage::ClearPublicCertificates(
     ResultCallback callback) {
   clear_public_certificates_callbacks_.push_back(std::move(callback));
@@ -139,17 +129,6 @@
   public_certificate_ids_ = ids;
 }
 
-void FakeNearbyShareCertificateStorage::SetPrivateCertificates(
-    base::Optional<std::vector<NearbySharePrivateCertificate>>
-        private_certificates) {
-  private_certificates_ = std::move(private_certificates);
-}
-
-void FakeNearbyShareCertificateStorage::SetNextPrivateCertificateExpirationTime(
-    base::Optional<base::Time> time) {
-  next_private_certificate_expiration_time_ = time;
-}
-
 void FakeNearbyShareCertificateStorage::SetNextPublicCertificateExpirationTime(
     base::Optional<base::Time> time) {
   next_public_certificate_expiration_time_ = time;
diff --git a/chrome/browser/nearby_sharing/certificates/fake_nearby_share_certificate_storage.h b/chrome/browser/nearby_sharing/certificates/fake_nearby_share_certificate_storage.h
index 643343f..16aec9c 100644
--- a/chrome/browser/nearby_sharing/certificates/fake_nearby_share_certificate_storage.h
+++ b/chrome/browser/nearby_sharing/certificates/fake_nearby_share_certificate_storage.h
@@ -100,8 +100,6 @@
   void GetPublicCertificates(PublicCertificateCallback callback) override;
   base::Optional<std::vector<NearbySharePrivateCertificate>>
   GetPrivateCertificates() const override;
-  base::Optional<base::Time> NextPrivateCertificateExpirationTime()
-      const override;
   base::Optional<base::Time> NextPublicCertificateExpirationTime()
       const override;
   void ReplacePrivateCertificates(
@@ -117,14 +115,9 @@
       ResultCallback callback) override;
   void RemoveExpiredPublicCertificates(base::Time now,
                                        ResultCallback callback) override;
-  void ClearPrivateCertificates() override;
   void ClearPublicCertificates(ResultCallback callback) override;
 
   void SetPublicCertificateIds(const std::vector<std::string>& ids);
-  void SetPrivateCertificates(
-      base::Optional<std::vector<NearbySharePrivateCertificate>>
-          private_certificates);
-  void SetNextPrivateCertificateExpirationTime(base::Optional<base::Time> time);
   void SetNextPublicCertificateExpirationTime(base::Optional<base::Time> time);
 
   std::vector<PublicCertificateCallback>& get_public_certificates_callbacks() {
@@ -145,17 +138,11 @@
     return remove_expired_public_certificates_calls_;
   }
 
-  size_t num_clear_private_certificates_calls() {
-    return num_clear_private_certificates_calls_;
-  }
-
   std::vector<ResultCallback>& clear_public_certificates_callbacks() {
     return clear_public_certificates_callbacks_;
   }
 
  private:
-  size_t num_clear_private_certificates_calls_ = 0;
-  base::Optional<base::Time> next_private_certificate_expiration_time_;
   base::Optional<base::Time> next_public_certificate_expiration_time_;
   std::vector<std::string> public_certificate_ids_;
   base::Optional<std::vector<NearbySharePrivateCertificate>>
diff --git a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.cc b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.cc
index 4113bc1..ad8167f 100644
--- a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.cc
+++ b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.cc
@@ -56,6 +56,42 @@
   return kVisibilities.size() * kNearbyShareNumPrivateCertificates;
 }
 
+base::Optional<nearbyshare::proto::EncryptedMetadata> BuildMetadata(
+    base::Optional<std::string> device_name,
+    base::Optional<std::string> full_name,
+    base::Optional<std::string> icon_url,
+    device::BluetoothAdapter* bluetooth_adapter) {
+  nearbyshare::proto::EncryptedMetadata metadata;
+  if (!device_name) {
+    NS_LOG(WARNING)
+        << __func__
+        << ": Cannot create private certificate metadata; missing device name.";
+    return base::nullopt;
+  }
+
+  metadata.set_device_name(*device_name);
+  if (full_name) {
+    metadata.set_full_name(*full_name);
+  }
+  if (icon_url) {
+    metadata.set_icon_url(*icon_url);
+  }
+  std::array<uint8_t, 6> bytes;
+  if (bluetooth_adapter &&
+      device::ParseBluetoothAddress(bluetooth_adapter->GetAddress(), bytes)) {
+    metadata.set_bluetooth_mac_address(std::string(bytes.begin(), bytes.end()));
+  } else {
+    NS_LOG(WARNING) << __func__
+                    << ": No valid Bluetooth MAC available for private "
+                    << "certificate metadata.";
+    // TODO(https://crbug.com/1122641): Decide the best way to handle
+    // missing/invalid Bluetooth MAC addresses. Also, log a metric to track how
+    // often this happens.
+  }
+
+  return metadata;
+}
+
 void RecordGetDecryptedPublicCertificateResultMetric(
     GetDecryptedPublicCertificateResult result) {
   base::UmaHistogramEnumeration(
@@ -355,86 +391,52 @@
   NS_LOG(VERBOSE)
       << __func__
       << ": Private certificate expiration detected; refreshing certificates.";
+
+  device::BluetoothAdapterFactory::Get()->GetAdapter(base::BindOnce(
+      &NearbyShareCertificateManagerImpl::FinishPrivateCertificateRefresh,
+      weak_ptr_factory_.GetWeakPtr()));
+}
+
+void NearbyShareCertificateManagerImpl::FinishPrivateCertificateRefresh(
+    scoped_refptr<device::BluetoothAdapter> bluetooth_adapter) {
   base::Time now = clock_->Now();
-  base::flat_map<nearby_share::mojom::Visibility, size_t> num_valid_certs;
-  base::flat_map<nearby_share::mojom::Visibility, base::Time> latest_not_after;
-  for (nearby_share::mojom::Visibility visibility : kVisibilities) {
-    num_valid_certs[visibility] = 0;
-    latest_not_after[visibility] = now;
-  }
+  certificate_storage_->RemoveExpiredPrivateCertificates(now);
 
-  // Remove all expired certificates.
-  std::vector<NearbySharePrivateCertificate> old_certs =
+  std::vector<NearbySharePrivateCertificate> certs =
       *certificate_storage_->GetPrivateCertificates();
-  std::vector<NearbySharePrivateCertificate> new_certs;
-  for (const NearbySharePrivateCertificate& cert : old_certs) {
-    if (IsNearbyShareCertificateExpired(
-            now, cert.not_after(),
-            /*use_public_certificate_tolerance=*/false)) {
-      continue;
-    }
-    ++num_valid_certs[cert.visibility()];
-    latest_not_after[cert.visibility()] =
-        std::max(latest_not_after[cert.visibility()], cert.not_after());
-    new_certs.push_back(cert);
-  }
-
-  if (!old_certs.empty() && new_certs.size() == old_certs.size()) {
+  if (certs.size() == NumExpectedPrivateCertificates()) {
     NS_LOG(VERBOSE) << __func__
                     << ": All private certificates are still valid.";
     private_certificate_expiration_scheduler_->HandleResult(/*success=*/true);
     return;
   }
 
-  device::BluetoothAdapterFactory::Get()->GetAdapter(base::BindOnce(
-      &NearbyShareCertificateManagerImpl::FinishPrivateCertificateRefresh,
-      weak_ptr_factory_.GetWeakPtr(), std::move(new_certs),
-      std::move(num_valid_certs), std::move(latest_not_after)));
-}
+  // Determine how many private certificates of each visibility need to be
+  // created, and determine the validity period for the new certificates.
+  base::flat_map<nearby_share::mojom::Visibility, size_t> num_valid_certs;
+  base::flat_map<nearby_share::mojom::Visibility, base::Time> latest_not_after;
+  for (nearby_share::mojom::Visibility visibility : kVisibilities) {
+    num_valid_certs[visibility] = 0;
+    latest_not_after[visibility] = now;
+  }
+  for (const NearbySharePrivateCertificate& cert : certs) {
+    ++num_valid_certs[cert.visibility()];
+    latest_not_after[cert.visibility()] =
+        std::max(latest_not_after[cert.visibility()], cert.not_after());
+  }
 
-void NearbyShareCertificateManagerImpl::FinishPrivateCertificateRefresh(
-    std::vector<NearbySharePrivateCertificate> new_certs,
-    base::flat_map<nearby_share::mojom::Visibility, size_t> num_valid_certs,
-    base::flat_map<nearby_share::mojom::Visibility, base::Time>
-        latest_not_after,
-    scoped_refptr<device::BluetoothAdapter> bluetooth_adapter) {
-  nearbyshare::proto::EncryptedMetadata metadata;
-
-  base::Optional<std::string> device_name =
-      local_device_data_manager_->GetDeviceName();
-  if (!device_name) {
-    NS_LOG(WARNING)
-        << __func__
-        << ": Cannot create private certificates; missing device name.";
+  base::Optional<nearbyshare::proto::EncryptedMetadata> metadata =
+      BuildMetadata(local_device_data_manager_->GetDeviceName(),
+                    local_device_data_manager_->GetFullName(),
+                    local_device_data_manager_->GetIconUrl(),
+                    bluetooth_adapter.get());
+  if (!metadata) {
     private_certificate_expiration_scheduler_->HandleResult(/*success=*/false);
     return;
   }
-  metadata.set_device_name(*device_name);
 
-  base::Optional<std::string> full_name =
-      local_device_data_manager_->GetFullName();
-  base::Optional<std::string> icon_url =
-      local_device_data_manager_->GetIconUrl();
-  if (full_name) {
-    metadata.set_full_name(*full_name);
-  }
-  if (icon_url) {
-    metadata.set_icon_url(*icon_url);
-  }
-
-  std::array<uint8_t, 6> bytes;
-  if (bluetooth_adapter &&
-      device::ParseBluetoothAddress(bluetooth_adapter->GetAddress(), bytes)) {
-    metadata.set_bluetooth_mac_address(std::string(bytes.begin(), bytes.end()));
-  } else {
-    NS_LOG(WARNING) << __func__
-                    << ": No valid Bluetooth MAC available during private "
-                    << "certificate creation.";
-    // TODO(https://crbug.com/1122641): Decide the best way to handle
-    // missing/invalid Bluetooth MAC addresses. Also, log a metric to track how
-    // often this happens.
-  }
-
+  // Add new certificates if necessary. Each visibility should have
+  // kNearbyShareNumPrivateCertificates.
   NS_LOG(VERBOSE)
       << __func__ << ": Creating "
       << kNearbyShareNumPrivateCertificates -
@@ -443,18 +445,17 @@
       << kNearbyShareNumPrivateCertificates -
              num_valid_certs[nearby_share::mojom::Visibility::kSelectedContacts]
       << " selected-contacts visibility private certificates.";
-  // Add new certificates if necessary. Each visibility should have
-  // kNearbyShareNumPrivateCertificates.
   for (nearby_share::mojom::Visibility visibility : kVisibilities) {
     while (num_valid_certs[visibility] < kNearbyShareNumPrivateCertificates) {
-      new_certs.emplace_back(
-          visibility, /*not_before=*/latest_not_after[visibility], metadata);
+      certs.emplace_back(visibility,
+                         /*not_before=*/latest_not_after[visibility],
+                         *metadata);
       ++num_valid_certs[visibility];
-      latest_not_after[visibility] = new_certs.back().not_after();
+      latest_not_after[visibility] = certs.back().not_after();
     }
   }
 
-  certificate_storage_->ReplacePrivateCertificates(new_certs);
+  certificate_storage_->ReplacePrivateCertificates(certs);
   NotifyPrivateCertificatesChanged();
   private_certificate_expiration_scheduler_->HandleResult(/*success=*/true);
 
diff --git a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.h b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.h
index 75d86c2..e1c1733 100644
--- a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.h
+++ b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.h
@@ -150,10 +150,6 @@
   void OnPrivateCertificateExpiration();
 
   void FinishPrivateCertificateRefresh(
-      std::vector<NearbySharePrivateCertificate> new_certs,
-      base::flat_map<nearby_share::mojom::Visibility, size_t> num_valid_certs,
-      base::flat_map<nearby_share::mojom::Visibility, base::Time>
-          latest_not_after,
       scoped_refptr<device::BluetoothAdapter> bluetooth_adapter);
 
   // Invoked by the certificate upload scheduler when private certificates need
diff --git a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl_unittest.cc b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl_unittest.cc
index 8f9037a..8f142295 100644
--- a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl_unittest.cc
+++ b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl_unittest.cc
@@ -411,7 +411,7 @@
 };
 
 TEST_F(NearbyShareCertificateManagerImplTest, GetValidPrivateCertificate) {
-  cert_store_->SetPrivateCertificates(private_certificates_);
+  cert_store_->ReplacePrivateCertificates(private_certificates_);
   FastForward(kNearbyShareCertificateValidityPeriod * 1.5);
   auto cert = cert_manager_->GetValidPrivateCertificate(
       nearby_share::mojom::Visibility::kAllContacts);
@@ -504,7 +504,7 @@
 
 TEST_F(NearbyShareCertificateManagerImplTest,
        RefreshPrivateCertificates_ValidCertificates) {
-  cert_store_->SetPrivateCertificates(private_certificates_);
+  cert_store_->ReplacePrivateCertificates(private_certificates_);
 
   cert_manager_->Start();
   HandlePrivateCertificateRefresh(/*expect_private_cert_refresh=*/false,
@@ -514,7 +514,7 @@
 
 TEST_F(NearbyShareCertificateManagerImplTest,
        RefreshPrivateCertificates_NoCertificates_UploadSuccess) {
-  cert_store_->SetPrivateCertificates(
+  cert_store_->ReplacePrivateCertificates(
       std::vector<NearbySharePrivateCertificate>());
 
   cert_manager_->Start();
@@ -526,7 +526,7 @@
 
 TEST_F(NearbyShareCertificateManagerImplTest,
        RefreshPrivateCertificates_NoCertificates_UploadFailure) {
-  cert_store_->SetPrivateCertificates(
+  cert_store_->ReplacePrivateCertificates(
       std::vector<NearbySharePrivateCertificate>());
 
   cert_manager_->Start();
@@ -548,12 +548,12 @@
       contact_manager_->NotifyAllowlistChanged(
           were_contacts_added_to_allowlist,
           were_contacts_removed_from_allowlist);
-      if (were_contacts_removed_from_allowlist)
+      if (were_contacts_removed_from_allowlist) {
         ++num_expected_calls;
+        EXPECT_TRUE(cert_store_->GetPrivateCertificates()->empty());
+      }
 
       EXPECT_EQ(num_expected_calls,
-                cert_store_->num_clear_private_certificates_calls());
-      EXPECT_EQ(num_expected_calls,
                 private_cert_exp_scheduler_->num_immediate_requests());
     }
   }
@@ -569,12 +569,12 @@
   for (bool did_contacts_change_since_last_upload : {true, false}) {
     contact_manager_->NotifyContactsUploaded(
         did_contacts_change_since_last_upload);
-    if (did_contacts_change_since_last_upload)
+    if (did_contacts_change_since_last_upload) {
       ++num_expected_calls;
+      EXPECT_TRUE(cert_store_->GetPrivateCertificates()->empty());
+    }
 
     EXPECT_EQ(num_expected_calls,
-              cert_store_->num_clear_private_certificates_calls());
-    EXPECT_EQ(num_expected_calls,
               private_cert_exp_scheduler_->num_immediate_requests());
   }
 }
@@ -594,11 +594,10 @@
         if (did_device_name_change || did_full_name_change ||
             did_icon_url_change) {
           ++num_expected_calls;
+          EXPECT_TRUE(cert_store_->GetPrivateCertificates()->empty());
         }
 
         EXPECT_EQ(num_expected_calls,
-                  cert_store_->num_clear_private_certificates_calls());
-        EXPECT_EQ(num_expected_calls,
                   private_cert_exp_scheduler_->num_immediate_requests());
       }
     }
@@ -609,7 +608,7 @@
        RefreshPrivateCertificates_ExpiredCertificate) {
   // First certificates are expired;
   FastForward(kNearbyShareCertificateValidityPeriod * 1.5);
-  cert_store_->SetPrivateCertificates(private_certificates_);
+  cert_store_->ReplacePrivateCertificates(private_certificates_);
 
   cert_manager_->Start();
   HandlePrivateCertificateRefresh(/*expect_private_cert_refresh=*/true,
@@ -620,7 +619,7 @@
 
 TEST_F(NearbyShareCertificateManagerImplTest,
        RefreshPrivateCertificates_InvalidDeviceName) {
-  cert_store_->SetPrivateCertificates(
+  cert_store_->ReplacePrivateCertificates(
       std::vector<NearbySharePrivateCertificate>());
 
   // Device name is missing in local device data manager.
@@ -635,7 +634,7 @@
 
 TEST_F(NearbyShareCertificateManagerImplTest,
        RefreshPrivateCertificates_InvalidBluetoothMacAddress) {
-  cert_store_->SetPrivateCertificates(
+  cert_store_->ReplacePrivateCertificates(
       std::vector<NearbySharePrivateCertificate>());
 
   // The bluetooth adapter returns an invalid Bluetooth MAC address.
@@ -655,7 +654,7 @@
 
 TEST_F(NearbyShareCertificateManagerImplTest,
        RefreshPrivateCertificates_MissingFullNameAndIconUrl) {
-  cert_store_->SetPrivateCertificates(
+  cert_store_->ReplacePrivateCertificates(
       std::vector<NearbySharePrivateCertificate>());
 
   // Full name and icon URL are missing in local device data manager.
diff --git a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage.cc b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage.cc
new file mode 100644
index 0000000..ba93ad3
--- /dev/null
+++ b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage.cc
@@ -0,0 +1,85 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <algorithm>
+
+#include "chrome/browser/nearby_sharing/certificates/common.h"
+#include "chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage.h"
+
+base::Optional<base::Time>
+NearbyShareCertificateStorage::NextPrivateCertificateExpirationTime() {
+  base::Optional<std::vector<NearbySharePrivateCertificate>> certs =
+      GetPrivateCertificates();
+  if (!certs || certs->empty())
+    return base::nullopt;
+
+  base::Time min_time = base::Time::Max();
+  for (const NearbySharePrivateCertificate& cert : *certs)
+    min_time = std::min(min_time, cert.not_after());
+
+  return min_time;
+}
+
+void NearbyShareCertificateStorage::UpdatePrivateCertificate(
+    const NearbySharePrivateCertificate& private_certificate) {
+  base::Optional<std::vector<NearbySharePrivateCertificate>> certs =
+      GetPrivateCertificates();
+  if (!certs)
+    return;
+
+  auto it = std::find_if(
+      certs->begin(), certs->end(),
+      [&private_certificate](const NearbySharePrivateCertificate& cert) {
+        return cert.id() == private_certificate.id();
+      });
+  if (it == certs->end())
+    return;
+
+  *it = private_certificate;
+  ReplacePrivateCertificates(*certs);
+}
+
+void NearbyShareCertificateStorage::RemoveExpiredPrivateCertificates(
+    base::Time now) {
+  base::Optional<std::vector<NearbySharePrivateCertificate>> certs =
+      GetPrivateCertificates();
+  if (!certs)
+    return;
+
+  std::vector<NearbySharePrivateCertificate> unexpired_certs;
+  for (const NearbySharePrivateCertificate& cert : *certs) {
+    if (!IsNearbyShareCertificateExpired(
+            now, cert.not_after(),
+            /*use_public_certificate_tolerance=*/false)) {
+      unexpired_certs.push_back(cert);
+    }
+  }
+
+  ReplacePrivateCertificates(unexpired_certs);
+}
+
+void NearbyShareCertificateStorage::ClearPrivateCertificates() {
+  ReplacePrivateCertificates(std::vector<NearbySharePrivateCertificate>());
+}
+
+void NearbyShareCertificateStorage::ClearPrivateCertificatesOfVisibility(
+    nearby_share::mojom::Visibility visibility) {
+  base::Optional<std::vector<NearbySharePrivateCertificate>> certs =
+      GetPrivateCertificates();
+  if (!certs)
+    return;
+
+  bool were_certs_removed = false;
+  std::vector<NearbySharePrivateCertificate> new_certs;
+  for (const NearbySharePrivateCertificate& cert : *certs) {
+    if (cert.visibility() == visibility) {
+      were_certs_removed = true;
+    } else {
+      new_certs.push_back(cert);
+    }
+  }
+
+  if (were_certs_removed)
+    ReplacePrivateCertificates(new_certs);
+}
diff --git a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage.h b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage.h
index 339409b..7ee94d3 100644
--- a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage.h
+++ b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage.h
@@ -10,6 +10,7 @@
 #include "base/time/time.h"
 #include "chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.h"
 #include "chrome/browser/nearby_sharing/proto/rpc_resources.pb.h"
+#include "chrome/browser/ui/webui/nearby_share/public/mojom/nearby_share_settings.mojom.h"
 
 // Stores local-device private certificates and remote-device public
 // certificates. Provides methods to help manage certificate expiration. Due to
@@ -39,8 +40,7 @@
 
   // Returns the next time a certificate expires or base::nullopt if no
   // certificates are present.
-  virtual base::Optional<base::Time> NextPrivateCertificateExpirationTime()
-      const = 0;
+  base::Optional<base::Time> NextPrivateCertificateExpirationTime();
   virtual base::Optional<base::Time> NextPublicCertificateExpirationTime()
       const = 0;
 
@@ -57,6 +57,13 @@
           public_certificates,
       ResultCallback callback) = 0;
 
+  // Overwrites an existing record with |private_certificate| if that records
+  // has the same ID . If no such record exists in storage, no action is taken.
+  // This method is necessary for updating the private certificate's list of
+  // consumed salts.
+  void UpdatePrivateCertificate(
+      const NearbySharePrivateCertificate& private_certificate);
+
   // Adds public certificates, or replaces existing certificates
   // by secret_id
   virtual void AddPublicCertificates(
@@ -64,13 +71,22 @@
           public_certificates,
       ResultCallback callback) = 0;
 
+  // Removes all private certificates from storage with expiration date after
+  // |now|.
+  void RemoveExpiredPrivateCertificates(base::Time now);
+
   // Removes all public certificates from storage with expiration date after
   // |now|.
   virtual void RemoveExpiredPublicCertificates(base::Time now,
                                                ResultCallback callback) = 0;
 
   // Delete all private certificates from memory and persistent storage.
-  virtual void ClearPrivateCertificates() = 0;
+  void ClearPrivateCertificates();
+
+  // Delete private certificates with |visibility| from memory and persistent
+  // storage.
+  void ClearPrivateCertificatesOfVisibility(
+      nearby_share::mojom::Visibility visibility);
 
   // Delete all public certificates from memory and persistent storage.
   virtual void ClearPublicCertificates(ResultCallback callback) = 0;
diff --git a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage_impl.cc b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage_impl.cc
index 4c518286..eeafab4 100644
--- a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage_impl.cc
+++ b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage_impl.cc
@@ -442,31 +442,12 @@
     if (!cert)
       return base::nullopt;
 
-    certs.emplace_back(*std::move(cert));
+    certs.push_back(*std::move(cert));
   }
   return certs;
 }
 
 base::Optional<base::Time>
-NearbyShareCertificateStorageImpl::NextPrivateCertificateExpirationTime()
-    const {
-  const base::Value* list =
-      pref_service_->Get(prefs::kNearbySharingPrivateCertificateListPrefName);
-  if (!list || list->GetList().empty())
-    return base::nullopt;
-
-  base::Time min_time = base::Time::Max();
-  for (const base::Value& cert_dict : list->GetList()) {
-    auto cert(NearbySharePrivateCertificate::FromDictionary(cert_dict));
-    if (!cert)
-      return base::nullopt;
-
-    min_time = std::min(min_time, cert->not_after());
-  }
-  return min_time;
-}
-
-base::Optional<base::Time>
 NearbyShareCertificateStorageImpl::NextPublicCertificateExpirationTime() const {
   if (public_certificate_expirations_.empty())
     return base::nullopt;
@@ -481,8 +462,8 @@
   for (const NearbySharePrivateCertificate& cert : private_certificates) {
     list.Append(cert.ToDictionary());
   }
-  NS_LOG(VERBOSE) << __func__ << ": Overwriting private certificates pref. "
-                  << private_certificates.size() << " new certificates.";
+  NS_LOG(VERBOSE) << __func__ << ": Overwriting private certificates pref with "
+                  << private_certificates.size() << " certificates.";
   pref_service_->Set(prefs::kNearbySharingPrivateCertificateListPrefName, list);
 }
 
@@ -612,10 +593,6 @@
                      std::move(callback)));
 }
 
-void NearbyShareCertificateStorageImpl::ClearPrivateCertificates() {
-  pref_service_->ClearPref(prefs::kNearbySharingPrivateCertificateListPrefName);
-}
-
 void NearbyShareCertificateStorageImpl::ClearPublicCertificates(
     ResultCallback callback) {
   if (init_status_ == InitStatus::kFailed) {
diff --git a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage_impl.h b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage_impl.h
index d8251b65..59651948 100644
--- a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage_impl.h
+++ b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage_impl.h
@@ -66,8 +66,6 @@
   void GetPublicCertificates(PublicCertificateCallback callback) override;
   base::Optional<std::vector<NearbySharePrivateCertificate>>
   GetPrivateCertificates() const override;
-  base::Optional<base::Time> NextPrivateCertificateExpirationTime()
-      const override;
   base::Optional<base::Time> NextPublicCertificateExpirationTime()
       const override;
   void ReplacePrivateCertificates(
@@ -83,7 +81,6 @@
       ResultCallback callback) override;
   void RemoveExpiredPublicCertificates(base::Time now,
                                        ResultCallback callback) override;
-  void ClearPrivateCertificates() override;
   void ClearPublicCertificates(ResultCallback callback) override;
 
  private:
@@ -131,7 +128,6 @@
       leveldb_proto::ProtoDatabase<nearbyshare::proto::PublicCertificate>>
       db_;
 
-  std::vector<NearbySharePrivateCertificate> private_certificates_;
   ExpirationList public_certificate_expirations_;
   base::queue<base::OnceClosure> deferred_callbacks_;
 };
diff --git a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage_impl_unittest.cc b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage_impl_unittest.cc
index 28f4ed8..83e0d8f 100644
--- a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage_impl_unittest.cc
+++ b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_storage_impl_unittest.cc
@@ -104,12 +104,14 @@
   return cert;
 }
 
-std::vector<NearbySharePrivateCertificate> CreatePrivateCertificates(size_t n) {
+std::vector<NearbySharePrivateCertificate> CreatePrivateCertificates(
+    size_t n,
+    nearby_share::mojom::Visibility visibility) {
   std::vector<NearbySharePrivateCertificate> certs;
   certs.reserve(n);
   for (size_t i = 0; i < n; ++i) {
-    certs.emplace_back(nearby_share::mojom::Visibility::kAllContacts,
-                       base::Time::Now(), GetNearbyShareTestMetadata());
+    certs.emplace_back(visibility, base::Time::Now(),
+                       GetNearbyShareTestMetadata());
   }
   return certs;
 }
@@ -119,6 +121,7 @@
          base::TimeDelta::FromSeconds(timestamp.seconds()) +
          base::TimeDelta::FromNanoseconds(timestamp.nanos());
 }
+
 }  // namespace
 
 class NearbyShareCertificateStorageImplTest : public ::testing::Test {
@@ -431,6 +434,33 @@
   ASSERT_EQ(0u, db_entries_.size());
 }
 
+TEST_F(NearbyShareCertificateStorageImplTest,
+       RemoveExpiredPrivateCertificates) {
+  db_->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
+
+  std::vector<NearbySharePrivateCertificate> certs = CreatePrivateCertificates(
+      3, nearby_share::mojom::Visibility::kAllContacts);
+  cert_store_->ReplacePrivateCertificates(certs);
+
+  std::vector<base::Time> expiration_times;
+  for (const NearbySharePrivateCertificate& cert : certs) {
+    expiration_times.push_back(cert.not_after());
+  }
+  std::sort(expiration_times.begin(), expiration_times.end());
+
+  // Set current time to exceed the expiration times of the first two
+  // certificates.
+  base::Time now = expiration_times[1];
+
+  cert_store_->RemoveExpiredPrivateCertificates(now);
+
+  certs = *cert_store_->GetPrivateCertificates();
+  ASSERT_EQ(1u, certs.size());
+  for (const NearbySharePrivateCertificate& cert : certs) {
+    EXPECT_LE(now, cert.not_after());
+  }
+}
+
 TEST_F(NearbyShareCertificateStorageImplTest, RemoveExpiredPublicCertificates) {
   db_->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
 
@@ -464,7 +494,8 @@
 TEST_F(NearbyShareCertificateStorageImplTest, ReplaceGetPrivateCertificates) {
   db_->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
 
-  auto certs_before = CreatePrivateCertificates(3);
+  auto certs_before = CreatePrivateCertificates(
+      3, nearby_share::mojom::Visibility::kAllContacts);
   cert_store_->ReplacePrivateCertificates(certs_before);
   auto certs_after = cert_store_->GetPrivateCertificates();
 
@@ -474,7 +505,8 @@
     EXPECT_EQ(certs_before[i].ToDictionary(), (*certs_after)[i].ToDictionary());
   }
 
-  certs_before = CreatePrivateCertificates(1);
+  certs_before = CreatePrivateCertificates(
+      1, nearby_share::mojom::Visibility::kAllContacts);
   cert_store_->ReplacePrivateCertificates(certs_before);
   certs_after = cert_store_->GetPrivateCertificates();
 
@@ -485,11 +517,37 @@
   }
 }
 
+TEST_F(NearbyShareCertificateStorageImplTest, UpdatePrivateCertificates) {
+  db_->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
+
+  std::vector<NearbySharePrivateCertificate> initial_certs =
+      CreatePrivateCertificates(3,
+                                nearby_share::mojom::Visibility::kAllContacts);
+  cert_store_->ReplacePrivateCertificates(initial_certs);
+
+  NearbySharePrivateCertificate cert_to_update = initial_certs[1];
+  EXPECT_EQ(initial_certs[1].ToDictionary(), cert_to_update.ToDictionary());
+  cert_to_update.EncryptMetadataKey();
+  EXPECT_NE(initial_certs[1].ToDictionary(), cert_to_update.ToDictionary());
+
+  cert_store_->UpdatePrivateCertificate(cert_to_update);
+
+  std::vector<NearbySharePrivateCertificate> new_certs =
+      *cert_store_->GetPrivateCertificates();
+  EXPECT_EQ(initial_certs.size(), new_certs.size());
+  for (size_t i = 0; i < new_certs.size(); ++i) {
+    NearbySharePrivateCertificate expected_cert =
+        i == 1 ? cert_to_update : initial_certs[i];
+    EXPECT_EQ(expected_cert.ToDictionary(), new_certs[i].ToDictionary());
+  }
+}
+
 TEST_F(NearbyShareCertificateStorageImplTest,
        NextPrivateCertificateExpirationTime) {
   db_->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
 
-  auto certs = CreatePrivateCertificates(3);
+  auto certs = CreatePrivateCertificates(
+      3, nearby_share::mojom::Visibility::kAllContacts);
   cert_store_->ReplacePrivateCertificates(certs);
   base::Optional<base::Time> next_expiration =
       cert_store_->NextPrivateCertificateExpirationTime();
@@ -526,7 +584,8 @@
   db_->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
 
   std::vector<NearbySharePrivateCertificate> certs_before =
-      CreatePrivateCertificates(3);
+      CreatePrivateCertificates(3,
+                                nearby_share::mojom::Visibility::kAllContacts);
   cert_store_->ReplacePrivateCertificates(certs_before);
   cert_store_->ClearPrivateCertificates();
   auto certs_after = cert_store_->GetPrivateCertificates();
@@ -534,3 +593,61 @@
   ASSERT_TRUE(certs_after.has_value());
   EXPECT_EQ(0u, certs_after->size());
 }
+
+TEST_F(NearbyShareCertificateStorageImplTest,
+       ClearPrivateCertificatesOfVisibility) {
+  db_->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
+
+  std::vector<NearbySharePrivateCertificate> certs_all_contacts =
+      CreatePrivateCertificates(3,
+                                nearby_share::mojom::Visibility::kAllContacts);
+  std::vector<NearbySharePrivateCertificate> certs_selected_contacts =
+      CreatePrivateCertificates(
+          3, nearby_share::mojom::Visibility::kSelectedContacts);
+  std::vector<NearbySharePrivateCertificate> all_certs;
+  all_certs.reserve(certs_all_contacts.size() + certs_selected_contacts.size());
+  all_certs.insert(all_certs.end(), certs_all_contacts.begin(),
+                   certs_all_contacts.end());
+  all_certs.insert(all_certs.end(), certs_selected_contacts.begin(),
+                   certs_selected_contacts.end());
+
+  // Remove all-contacts certs then selected-contacts certs.
+  {
+    cert_store_->ReplacePrivateCertificates(all_certs);
+    cert_store_->ClearPrivateCertificatesOfVisibility(
+        nearby_share::mojom::Visibility::kAllContacts);
+    auto certs_after = cert_store_->GetPrivateCertificates();
+    ASSERT_TRUE(certs_after.has_value());
+    ASSERT_EQ(certs_selected_contacts.size(), certs_after->size());
+    for (size_t i = 0; i < certs_selected_contacts.size(); ++i) {
+      EXPECT_EQ(certs_selected_contacts[i].ToDictionary(),
+                (*certs_after)[i].ToDictionary());
+    }
+
+    cert_store_->ClearPrivateCertificatesOfVisibility(
+        nearby_share::mojom::Visibility::kSelectedContacts);
+    certs_after = cert_store_->GetPrivateCertificates();
+    ASSERT_TRUE(certs_after.has_value());
+    EXPECT_EQ(0u, certs_after->size());
+  }
+
+  // Remove selected-contacts certs then all-contacts certs.
+  {
+    cert_store_->ReplacePrivateCertificates(all_certs);
+    cert_store_->ClearPrivateCertificatesOfVisibility(
+        nearby_share::mojom::Visibility::kSelectedContacts);
+    auto certs_after = cert_store_->GetPrivateCertificates();
+    ASSERT_TRUE(certs_after.has_value());
+    ASSERT_EQ(certs_all_contacts.size(), certs_after->size());
+    for (size_t i = 0; i < certs_all_contacts.size(); ++i) {
+      EXPECT_EQ(certs_all_contacts[i].ToDictionary(),
+                (*certs_after)[i].ToDictionary());
+    }
+
+    cert_store_->ClearPrivateCertificatesOfVisibility(
+        nearby_share::mojom::Visibility::kAllContacts);
+    certs_after = cert_store_->GetPrivateCertificates();
+    ASSERT_TRUE(certs_after.has_value());
+    EXPECT_EQ(0u, certs_after->size());
+  }
+}
diff --git a/chrome/browser/net/chrome_mojo_proxy_resolver_factory.cc b/chrome/browser/net/chrome_mojo_proxy_resolver_factory.cc
index 99dfc41..859c368 100644
--- a/chrome/browser/net/chrome_mojo_proxy_resolver_factory.cc
+++ b/chrome/browser/net/chrome_mojo_proxy_resolver_factory.cc
@@ -19,7 +19,7 @@
 #include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
 
 #if defined(OS_ANDROID)
-#include "services/proxy_resolver/proxy_resolver_factory_impl.h"
+#include "services/proxy_resolver/proxy_resolver_factory_impl.h"  // nogncheck crbug.com/1125897
 #else
 #include "content/public/browser/service_process_host.h"
 #include "services/strings/grit/services_strings.h"
diff --git a/chrome/browser/page_load_metrics/observers/translate_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/translate_page_load_metrics_observer.cc
new file mode 100644
index 0000000..fdfb2502
--- /dev/null
+++ b/chrome/browser/page_load_metrics/observers/translate_page_load_metrics_observer.cc
@@ -0,0 +1,68 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/page_load_metrics/observers/translate_page_load_metrics_observer.h"
+
+#include "components/translate/core/browser/translate_metrics_logger_impl.h"
+
+std::unique_ptr<TranslatePageLoadMetricsObserver>
+TranslatePageLoadMetricsObserver::CreateIfNeeded() {
+  // TODO(curranamx): Connect the new TranslateMetricsLogger to a
+  // TranslateManager. https://crbug.com/1114868.
+  std::unique_ptr<translate::TranslateMetricsLogger> translate_metrics_logger =
+      std::make_unique<translate::TranslateMetricsLoggerImpl>();
+
+  return std::make_unique<TranslatePageLoadMetricsObserver>(
+      std::move(translate_metrics_logger));
+}
+
+TranslatePageLoadMetricsObserver::TranslatePageLoadMetricsObserver(
+    std::unique_ptr<translate::TranslateMetricsLogger> translate_metrics_logger)
+    : translate_metrics_logger_(std::move(translate_metrics_logger)) {}
+
+TranslatePageLoadMetricsObserver::~TranslatePageLoadMetricsObserver() = default;
+
+page_load_metrics::PageLoadMetricsObserver::ObservePolicy
+TranslatePageLoadMetricsObserver::OnStart(
+    content::NavigationHandle* navigation_handle,
+    const GURL& currently_committed_url,
+    bool started_in_foreground) {
+  DCHECK(translate_metrics_logger_ != nullptr);
+
+  translate_metrics_logger_->OnPageLoadStart(started_in_foreground);
+  return CONTINUE_OBSERVING;
+}
+
+page_load_metrics::PageLoadMetricsObserver::ObservePolicy
+TranslatePageLoadMetricsObserver::OnHidden(
+    const page_load_metrics::mojom::PageLoadTiming& timing) {
+  DCHECK(translate_metrics_logger_ != nullptr);
+
+  translate_metrics_logger_->OnForegroundChange(false);
+  return CONTINUE_OBSERVING;
+}
+
+page_load_metrics::PageLoadMetricsObserver::ObservePolicy
+TranslatePageLoadMetricsObserver::OnShown() {
+  DCHECK(translate_metrics_logger_ != nullptr);
+
+  translate_metrics_logger_->OnForegroundChange(true);
+  return CONTINUE_OBSERVING;
+}
+
+page_load_metrics::PageLoadMetricsObserver::ObservePolicy
+TranslatePageLoadMetricsObserver::FlushMetricsOnAppEnterBackground(
+    const page_load_metrics::mojom::PageLoadTiming& timing) {
+  DCHECK(translate_metrics_logger_ != nullptr);
+
+  translate_metrics_logger_->RecordMetrics(false);
+  return CONTINUE_OBSERVING;
+}
+
+void TranslatePageLoadMetricsObserver::OnComplete(
+    const page_load_metrics::mojom::PageLoadTiming& timing) {
+  DCHECK(translate_metrics_logger_ != nullptr);
+
+  translate_metrics_logger_->RecordMetrics(true);
+}
diff --git a/chrome/browser/page_load_metrics/observers/translate_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/translate_page_load_metrics_observer.h
new file mode 100644
index 0000000..8ef882e
--- /dev/null
+++ b/chrome/browser/page_load_metrics/observers/translate_page_load_metrics_observer.h
@@ -0,0 +1,55 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_TRANSLATE_PAGE_LOAD_METRICS_OBSERVER_H_
+#define CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_TRANSLATE_PAGE_LOAD_METRICS_OBSERVER_H_
+
+#include <memory>
+
+#include "components/page_load_metrics/browser/page_load_metrics_observer.h"
+
+namespace translate {
+class TranslateMetricsLogger;
+}  // namespace translate
+
+namespace content {
+class NavigationHandle;
+}  // namespace content
+
+// Observer responsible for notifying Translate of the status of a page load.
+// This information is used to log UKM and UMA metrics at a page load level, as
+// well as tracking the time a page is in the foreground and either translated
+// or not translated.
+class TranslatePageLoadMetricsObserver
+    : public page_load_metrics::PageLoadMetricsObserver {
+ public:
+  static std::unique_ptr<TranslatePageLoadMetricsObserver> CreateIfNeeded();
+
+  explicit TranslatePageLoadMetricsObserver(
+      std::unique_ptr<translate::TranslateMetricsLogger>
+          translate_metrics_logger);
+  ~TranslatePageLoadMetricsObserver() override;
+
+  TranslatePageLoadMetricsObserver(const TranslatePageLoadMetricsObserver&) =
+      delete;
+  TranslatePageLoadMetricsObserver& operator=(
+      const TranslatePageLoadMetricsObserver&) = delete;
+
+  // page_load_metrics::PageLoadMetricsObserver
+  ObservePolicy OnStart(content::NavigationHandle* navigation_handle,
+                        const GURL& currently_committed_url,
+                        bool started_in_foreground) override;
+  ObservePolicy OnHidden(
+      const page_load_metrics::mojom::PageLoadTiming& timing) override;
+  ObservePolicy OnShown() override;
+  ObservePolicy FlushMetricsOnAppEnterBackground(
+      const page_load_metrics::mojom::PageLoadTiming& timing) override;
+  void OnComplete(
+      const page_load_metrics::mojom::PageLoadTiming& timing) override;
+
+ private:
+  std::unique_ptr<translate::TranslateMetricsLogger> translate_metrics_logger_;
+};
+
+#endif  // CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_TRANSLATE_PAGE_LOAD_METRICS_OBSERVER_H_
diff --git a/chrome/browser/page_load_metrics/observers/translate_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/translate_page_load_metrics_observer_unittest.cc
new file mode 100644
index 0000000..3d31eb1
--- /dev/null
+++ b/chrome/browser/page_load_metrics/observers/translate_page_load_metrics_observer_unittest.cc
@@ -0,0 +1,125 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/page_load_metrics/observers/translate_page_load_metrics_observer.h"
+
+#include "base/memory/ptr_util.h"
+#include "chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h"
+#include "components/page_load_metrics/browser/page_load_tracker.h"
+#include "components/translate/core/browser/translate_metrics_logger.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+class MockTranslateMetricsLogger : public translate::TranslateMetricsLogger {
+ public:
+  MOCK_METHOD1(OnPageLoadStart, void(bool));
+  MOCK_METHOD1(OnForegroundChange, void(bool));
+  MOCK_METHOD1(RecordMetrics, void(bool));
+};
+
+// Wraps the above MockTranslateMetricsLogger so that test can retain a pointer
+// to the MockTranslateMetricsLogger after the TranslatePageLoadMetricsObserver
+// is done with it.
+class MockTranslateMetricsLoggerContainer
+    : public translate::TranslateMetricsLogger {
+ public:
+  explicit MockTranslateMetricsLoggerContainer(
+      MockTranslateMetricsLogger* mock_translate_metrics_logger)
+      : mock_translate_metrics_logger_(mock_translate_metrics_logger) {}
+
+  void OnPageLoadStart(bool is_foreground) override {
+    mock_translate_metrics_logger_->OnPageLoadStart(is_foreground);
+  }
+
+  void OnForegroundChange(bool is_foreground) override {
+    mock_translate_metrics_logger_->OnForegroundChange(is_foreground);
+  }
+
+  void RecordMetrics(bool is_final) override {
+    mock_translate_metrics_logger_->RecordMetrics(is_final);
+  }
+
+ private:
+  MockTranslateMetricsLogger* mock_translate_metrics_logger_;  // Weak.
+};
+
+class TranslatePageLoadMetricsObserverTest
+    : public page_load_metrics::PageLoadMetricsObserverTestHarness {
+ public:
+  void SetUp() override {
+    PageLoadMetricsObserverTestHarness::SetUp();
+
+    // Creates the MockTranslateMetricsLogger that will be used for this test.
+    mock_translate_metrics_logger_ =
+        std::make_unique<MockTranslateMetricsLogger>();
+  }
+
+  void RegisterObservers(page_load_metrics::PageLoadTracker* tracker) override {
+    MockTranslateMetricsLogger* raw_mock_translate_metrics_logger =
+        mock_translate_metrics_logger_.get();
+
+    // Wraps the raw pointer in a container.
+    std::unique_ptr<MockTranslateMetricsLoggerContainer>
+        mock_translate_metrics_logger_container =
+            std::make_unique<MockTranslateMetricsLoggerContainer>(
+                raw_mock_translate_metrics_logger);
+
+    tracker->AddObserver(std::make_unique<TranslatePageLoadMetricsObserver>(
+        std::move(mock_translate_metrics_logger_container)));
+  }
+
+  MockTranslateMetricsLogger& mock_translate_metrics_logger() const {
+    return *mock_translate_metrics_logger_;
+  }
+
+ private:
+  // This is the TranslateMetricsLoggers used in a test.It is owned by the
+  // TranslatePageLoadMetricsObserverTest.
+  std::unique_ptr<MockTranslateMetricsLogger> mock_translate_metrics_logger_;
+};
+
+TEST_F(TranslatePageLoadMetricsObserverTest, SinglePageLoad) {
+  EXPECT_CALL(mock_translate_metrics_logger(), OnPageLoadStart(true)).Times(1);
+  EXPECT_CALL(mock_translate_metrics_logger(), OnPageLoadStart(false)).Times(0);
+  EXPECT_CALL(mock_translate_metrics_logger(), OnForegroundChange(testing::_))
+      .Times(0);
+  EXPECT_CALL(mock_translate_metrics_logger(), RecordMetrics(true)).Times(1);
+  EXPECT_CALL(mock_translate_metrics_logger(), RecordMetrics(false)).Times(0);
+
+  NavigateAndCommit(GURL("https://www.example.com"));
+  tester()->NavigateToUntrackedUrl();
+}
+
+TEST_F(TranslatePageLoadMetricsObserverTest, AppEntersBackground) {
+  EXPECT_CALL(mock_translate_metrics_logger(), OnPageLoadStart(true)).Times(1);
+  EXPECT_CALL(mock_translate_metrics_logger(), OnPageLoadStart(false)).Times(0);
+  EXPECT_CALL(mock_translate_metrics_logger(), OnForegroundChange(testing::_))
+      .Times(0);
+  EXPECT_CALL(mock_translate_metrics_logger(), RecordMetrics(true)).Times(1);
+  EXPECT_CALL(mock_translate_metrics_logger(), RecordMetrics(false)).Times(1);
+
+  NavigateAndCommit(GURL("https://www.example.com"));
+  tester()->SimulateAppEnterBackground();
+  tester()->NavigateToUntrackedUrl();
+}
+
+TEST_F(TranslatePageLoadMetricsObserverTest, RepeatedAppEntersBackground) {
+  int num_times_enter_background = 100;
+
+  EXPECT_CALL(mock_translate_metrics_logger(), OnPageLoadStart(true)).Times(1);
+  EXPECT_CALL(mock_translate_metrics_logger(), OnPageLoadStart(false)).Times(0);
+  EXPECT_CALL(mock_translate_metrics_logger(), OnForegroundChange(testing::_))
+      .Times(0);
+  EXPECT_CALL(mock_translate_metrics_logger(), RecordMetrics(true)).Times(1);
+  EXPECT_CALL(mock_translate_metrics_logger(), RecordMetrics(false))
+      .Times(num_times_enter_background);
+
+  NavigateAndCommit(GURL("https://www.example.com"));
+  for (int i = 0; i < num_times_enter_background; ++i)
+    tester()->SimulateAppEnterBackground();
+
+  tester()->NavigateToUntrackedUrl();
+}
+
+// TODO(curranmax): Add unit tests that confirm behavior when the hidden/shown.
+// status of the tab changes. https://crbug.com/1114868.
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
index f20c73f..3763314 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
@@ -38,6 +38,7 @@
 #include "chrome/browser/page_load_metrics/observers/signed_exchange_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/third_party_metrics_observer.h"
+#include "chrome/browser/page_load_metrics/observers/translate_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h"
 #include "chrome/browser/prerender/chrome_prerender_contents_delegate.h"
 #include "chrome/browser/profiles/profile.h"
@@ -165,6 +166,10 @@
       SecurityStatePageLoadMetricsObserver::MaybeCreateForProfile(
           web_contents()->GetBrowserContext()));
   tracker->AddObserver(std::make_unique<DataUseMetricsObserver>());
+  std::unique_ptr<TranslatePageLoadMetricsObserver> translate_observer =
+      TranslatePageLoadMetricsObserver::CreateIfNeeded();
+  if (translate_observer != nullptr)
+    tracker->AddObserver(std::move(translate_observer));
 }
 
 bool PageLoadMetricsEmbedder::IsPrerendering() const {
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 953e8e5..a672abf 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -126,7 +126,7 @@
 #include "chromeos/dbus/power/power_policy_controller.h"
 #include "chromeos/services/multidevice_setup/public/cpp/prefs.h"
 #include "components/arc/arc_prefs.h"
-#include "components/drive/drive_pref_names.h"
+#include "components/drive/drive_pref_names.h"  // nogncheck crbug.com/1125897
 #include "components/user_manager/user.h"
 #include "components/user_manager/user_manager.h"
 #else  // defined(OS_CHROMEOS)
diff --git a/chrome/browser/policy/messaging_layer/encryption/encryption_module.cc b/chrome/browser/policy/messaging_layer/encryption/encryption_module.cc
index 4be5d74..7e6c26d 100644
--- a/chrome/browser/policy/messaging_layer/encryption/encryption_module.cc
+++ b/chrome/browser/policy/messaging_layer/encryption/encryption_module.cc
@@ -4,10 +4,11 @@
 
 #include "chrome/browser/policy/messaging_layer/encryption/encryption_module.h"
 
+#include "base/bind.h"
 #include "base/callback.h"
 #include "base/feature_list.h"
 #include "base/strings/string_piece.h"
-#include "base/test/task_environment.h"
+#include "base/task/thread_pool.h"
 #include "chrome/browser/policy/messaging_layer/util/status.h"
 #include "chrome/browser/policy/messaging_layer/util/statusor.h"
 #include "components/policy/proto/record.pb.h"
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index c5734a3..e2f18aa 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -222,7 +222,7 @@
 #include "chrome/browser/first_run/android/first_run_prefs.h"
 #include "chrome/browser/media/android/cdm/media_drm_origin_id_manager.h"
 #include "chrome/browser/ssl/known_interception_disclosure_infobar_delegate.h"
-#include "components/cdm/browser/media_drm_storage_impl.h"
+#include "components/cdm/browser/media_drm_storage_impl.h"  // nogncheck crbug.com/1125897
 #include "components/feed/buildflags.h"
 #include "components/feed/core/shared_prefs/pref_names.h"
 #include "components/games/core/games_prefs.h"
diff --git a/chrome/browser/prefs/chrome_pref_service_factory.cc b/chrome/browser/prefs/chrome_pref_service_factory.cc
index 105e7ff..04f82a8 100644
--- a/chrome/browser/prefs/chrome_pref_service_factory.cc
+++ b/chrome/browser/prefs/chrome_pref_service_factory.cc
@@ -77,7 +77,7 @@
 #if defined(OS_WIN)
 #include "base/enterprise_util.h"
 #if BUILDFLAG(ENABLE_RLZ)
-#include "rlz/lib/machine_id.h"
+#include "rlz/lib/machine_id.h"  // nogncheck crbug.com/1125897
 #endif  // BUILDFLAG(ENABLE_RLZ)
 #endif  // defined(OS_WIN)
 
diff --git a/chrome/browser/printing/pdf_to_emf_converter.cc b/chrome/browser/printing/pdf_to_emf_converter.cc
index c9a0a51..09c5377 100644
--- a/chrome/browser/printing/pdf_to_emf_converter.cc
+++ b/chrome/browser/printing/pdf_to_emf_converter.cc
@@ -132,7 +132,8 @@
  private:
   class GetPageCallbackData {
    public:
-    GetPageCallbackData(int page_number, PdfConverter::GetPageCallback callback)
+    GetPageCallbackData(uint32_t page_number,
+                        PdfConverter::GetPageCallback callback)
         : page_number_(page_number), callback_(callback) {}
 
     GetPageCallbackData(GetPageCallbackData&& other) {
@@ -145,12 +146,12 @@
       return *this;
     }
 
-    int page_number() const { return page_number_; }
+    uint32_t page_number() const { return page_number_; }
 
     PdfConverter::GetPageCallback callback() const { return callback_; }
 
    private:
-    int page_number_;
+    uint32_t page_number_;
 
     PdfConverter::GetPageCallback callback_;
 
@@ -159,7 +160,7 @@
 
   void Initialize(scoped_refptr<base::RefCountedMemory> data);
 
-  void GetPage(int page_number,
+  void GetPage(uint32_t page_number,
                PdfConverter::GetPageCallback get_page_callback) override;
 
   void Stop();
@@ -305,7 +306,7 @@
 }
 
 void PdfConverterImpl::GetPage(
-    int page_number,
+    uint32_t page_number,
     PdfConverter::GetPageCallback get_page_callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(pdf_to_emf_converter_.is_bound());
diff --git a/chrome/browser/printing/pdf_to_emf_converter.h b/chrome/browser/printing/pdf_to_emf_converter.h
index f1d6791..0f0f2e8 100644
--- a/chrome/browser/printing/pdf_to_emf_converter.h
+++ b/chrome/browser/printing/pdf_to_emf_converter.h
@@ -17,9 +17,9 @@
 
 class PdfConverter {
  public:
-  using StartCallback = base::OnceCallback<void(int page_count)>;
+  using StartCallback = base::OnceCallback<void(uint32_t page_count)>;
   using GetPageCallback =
-      base::RepeatingCallback<void(int page_number,
+      base::RepeatingCallback<void(uint32_t page_number,
                                    float scale_factor,
                                    std::unique_ptr<MetafilePlayer> file)>;
   virtual ~PdfConverter();
@@ -35,7 +35,8 @@
   // PDF provided in Start() call.
   // Calls |get_page_callback| after conversion. |emf| of callback in not NULL
   // if conversion succeeded.
-  virtual void GetPage(int page_number, GetPageCallback get_page_callback) = 0;
+  virtual void GetPage(uint32_t page_number,
+                       GetPageCallback get_page_callback) = 0;
 };
 
 // Object used by tests to exercise the temporary file creation failure code
diff --git a/chrome/browser/printing/pdf_to_emf_converter_browsertest.cc b/chrome/browser/printing/pdf_to_emf_converter_browsertest.cc
index 46d81158..dd2837e 100644
--- a/chrome/browser/printing/pdf_to_emf_converter_browsertest.cc
+++ b/chrome/browser/printing/pdf_to_emf_converter_browsertest.cc
@@ -4,8 +4,11 @@
 
 #include "chrome/browser/printing/pdf_to_emf_converter.h"
 
+#include <stdint.h>
 #include <windows.h>
 
+#include <limits>
+
 #include "base/bind.h"
 #include "base/containers/span.h"
 #include "base/files/file_util.h"
@@ -32,17 +35,19 @@
 
 constexpr size_t kHeaderSize = sizeof(ENHMETAHEADER);
 
+constexpr uint32_t kInvalidPageCount = std::numeric_limits<uint32_t>::max();
+
 void StartCallbackImpl(base::OnceClosure quit_closure,
-                       int* page_count_out,
-                       int page_count_in) {
+                       uint32_t* page_count_out,
+                       uint32_t page_count_in) {
   *page_count_out = page_count_in;
   std::move(quit_closure).Run();
 }
 
 void GetPageCallbackImpl(base::OnceClosure quit_closure,
-                         int* page_number_out,
+                         uint32_t* page_number_out,
                          std::unique_ptr<MetafilePlayer>* file_out,
-                         int page_number_in,
+                         uint32_t page_number_in,
                          float scale_factor,
                          std::unique_ptr<MetafilePlayer> file_in) {
   *page_number_out = page_number_in;
@@ -133,9 +138,9 @@
   }
 
   bool StartPdfConverter(const PdfRenderSettings& pdf_settings,
-                         int expected_page_count) {
+                         uint32_t expected_page_count) {
     base::RunLoop run_loop;
-    int page_count = -1;
+    uint32_t page_count = kInvalidPageCount;
     pdf_converter_ = PdfConverter::StartPdfConverter(
         test_input_, pdf_settings,
         base::BindOnce(&StartCallbackImpl, run_loop.QuitClosure(),
@@ -144,9 +149,9 @@
     return pdf_converter_ && (expected_page_count == page_count);
   }
 
-  bool GetPage(int page_number_in) {
+  bool GetPage(uint32_t page_number_in) {
     base::RunLoop run_loop;
-    int page_number = -1;
+    uint32_t page_number = kInvalidPageCount;
     pdf_converter_->GetPage(
         page_number_in,
         base::BindRepeating(&GetPageCallbackImpl, run_loop.QuitClosure(),
@@ -227,12 +232,12 @@
   ScopedSimulateFailureCreatingTempFileForTests fail_creating_temp_file;
 
   base::RunLoop run_loop;
-  int page_count = -1;
+  uint32_t page_count = kInvalidPageCount;
   std::unique_ptr<PdfConverter> pdf_converter = PdfConverter::StartPdfConverter(
       base::MakeRefCounted<base::RefCountedStaticMemory>(), PdfRenderSettings(),
       base::BindOnce(&StartCallbackImpl, run_loop.QuitClosure(), &page_count));
   run_loop.Run();
-  EXPECT_EQ(0, page_count);
+  EXPECT_EQ(0u, page_count);
 }
 
 IN_PROC_BROWSER_TEST_F(PdfToEmfConverterBrowserTest, FailureBadPdf) {
@@ -240,12 +245,12 @@
       base::MakeRefCounted<base::RefCountedStaticMemory>("0123456789", 10);
 
   base::RunLoop run_loop;
-  int page_count = -1;
+  uint32_t page_count = kInvalidPageCount;
   std::unique_ptr<PdfConverter> pdf_converter = PdfConverter::StartPdfConverter(
       bad_pdf_data, PdfRenderSettings(),
       base::BindOnce(&StartCallbackImpl, run_loop.QuitClosure(), &page_count));
   run_loop.Run();
-  EXPECT_EQ(0, page_count);
+  EXPECT_EQ(0u, page_count);
 }
 
 IN_PROC_BROWSER_TEST_F(PdfToEmfConverterBrowserTest, EmfBasic) {
@@ -253,11 +258,11 @@
       kLetter200DpiRect, gfx::Point(0, 0), k200DpiSize,
       /*autorotate=*/false,
       /*use_color=*/true, PdfRenderSettings::Mode::NORMAL);
-  constexpr int kNumberOfPages = 3;
+  constexpr uint32_t kNumberOfPages = 3;
 
   ASSERT_TRUE(GetTestInput("pdf_converter_basic.pdf"));
   ASSERT_TRUE(StartPdfConverter(pdf_settings, kNumberOfPages));
-  for (int i = 0; i < kNumberOfPages; ++i) {
+  for (uint32_t i = 0; i < kNumberOfPages; ++i) {
     ASSERT_TRUE(GetPage(i));
     ASSERT_TRUE(GetPageExpectedEmfData(
         GetFileNameForPageNumber("pdf_converter_basic_emf_page_", i)));
diff --git a/chrome/browser/printing/print_browsertest.cc b/chrome/browser/printing/print_browsertest.cc
index aacd94c..32fc836 100644
--- a/chrome/browser/printing/print_browsertest.cc
+++ b/chrome/browser/printing/print_browsertest.cc
@@ -84,7 +84,7 @@
 
  private:
   // PrintPreviewUI::TestDelegate:
-  void DidGetPreviewPageCount(int page_count) override {
+  void DidGetPreviewPageCount(uint32_t page_count) override {
     total_page_count_ = page_count;
   }
 
@@ -109,8 +109,8 @@
   }
 
   base::Optional<content::DOMMessageQueue> queue_;
-  int total_page_count_ = 1;
-  int rendered_page_count_ = 0;
+  uint32_t total_page_count_ = 1;
+  uint32_t rendered_page_count_ = 0;
   content::WebContents* preview_dialog_ = nullptr;
   base::RunLoop* run_loop_ = nullptr;
 
diff --git a/chrome/browser/printing/print_job.cc b/chrome/browser/printing/print_job.cc
index 792f6ac..4f3b681 100644
--- a/chrome/browser/printing/print_job.cc
+++ b/chrome/browser/printing/print_job.cc
@@ -85,7 +85,7 @@
 
 void PrintJob::Initialize(std::unique_ptr<PrinterQuery> query,
                           const base::string16& name,
-                          int page_count) {
+                          uint32_t page_count) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(!worker_);
   DCHECK(!is_job_pending_);
@@ -98,7 +98,7 @@
 #if defined(OS_WIN)
   pdf_page_mapping_ = PageRange::GetPages(settings->ranges());
   if (pdf_page_mapping_.empty()) {
-    for (int i = 0; i < page_count; i++)
+    for (uint32_t i = 0; i < page_count; i++)
       pdf_page_mapping_.push_back(i);
   }
 #endif
@@ -115,12 +115,13 @@
 
 #if defined(OS_WIN)
 // static
-std::vector<int> PrintJob::GetFullPageMapping(const std::vector<int>& pages,
-                                              int total_page_count) {
-  std::vector<int> mapping(total_page_count, -1);
-  for (int page_number : pages) {
+std::vector<uint32_t> PrintJob::GetFullPageMapping(
+    const std::vector<uint32_t>& pages,
+    uint32_t total_page_count) {
+  std::vector<uint32_t> mapping(total_page_count, kInvalidPageIndex);
+  for (uint32_t page_number : pages) {
     // Make sure the page is in range.
-    if (page_number >= 0 && page_number < total_page_count)
+    if (page_number < total_page_count)
       mapping[page_number] = page_number;
   }
   return mapping;
@@ -319,13 +320,13 @@
       converter_.reset();
   }
 
-  void set_page_count(int page_count) { page_count_ = page_count; }
+  void set_page_count(uint32_t page_count) { page_count_ = page_count; }
   const gfx::Size& page_size() const { return page_size_; }
   const gfx::Rect& content_area() const { return content_area_; }
 
  private:
-  int page_count_;
-  int current_page_;
+  uint32_t page_count_;
+  uint32_t current_page_;
   int pages_in_progress_;
   gfx::Size page_size_;
   gfx::Rect content_area_;
@@ -379,7 +380,7 @@
       base::BindOnce(&PrintJob::OnPdfConversionStarted, this));
 }
 
-void PrintJob::OnPdfConversionStarted(int page_count) {
+void PrintJob::OnPdfConversionStarted(uint32_t page_count) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   if (page_count <= 0) {
@@ -394,13 +395,13 @@
       base::BindRepeating(&PrintJob::OnPdfPageConverted, this));
 }
 
-void PrintJob::OnPdfPageConverted(int page_number,
+void PrintJob::OnPdfPageConverted(uint32_t page_number,
                                   float scale_factor,
                                   std::unique_ptr<MetafilePlayer> metafile) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(pdf_conversion_state_);
-  if (!document_ || !metafile || page_number < 0 ||
-      static_cast<size_t>(page_number) >= pdf_page_mapping_.size()) {
+  if (!document_ || !metafile || page_number == kInvalidPageIndex ||
+      page_number >= pdf_page_mapping_.size()) {
     // Be sure to live long enough.
     scoped_refptr<PrintJob> handle(this);
     pdf_conversion_state_.reset();
@@ -410,7 +411,7 @@
 
   // Add the page to the document if it is one of the pages requested by the
   // user. If it is not, ignore it.
-  if (pdf_page_mapping_[page_number] != -1) {
+  if (pdf_page_mapping_[page_number] != kInvalidPageIndex) {
     // Update the rendered document. It will send notifications to the listener.
     document_->SetPage(pdf_page_mapping_[page_number], std::move(metafile),
                        scale_factor, pdf_conversion_state_->page_size(),
diff --git a/chrome/browser/printing/print_job.h b/chrome/browser/printing/print_job.h
index 0eadb45..beb577a 100644
--- a/chrome/browser/printing/print_job.h
+++ b/chrome/browser/printing/print_job.h
@@ -67,7 +67,7 @@
   // the settings.
   virtual void Initialize(std::unique_ptr<PrinterQuery> query,
                           const base::string16& name,
-                          int page_count);
+                          uint32_t page_count);
 
 #if defined(OS_WIN)
   void StartConversionToNativeFormat(
@@ -188,14 +188,15 @@
       scoped_refptr<base::RefCountedMemory> bytes,
       const gfx::Size& page_size);
 
-  void OnPdfConversionStarted(int page_count);
-  void OnPdfPageConverted(int page_number,
+  void OnPdfConversionStarted(uint32_t page_count);
+  void OnPdfPageConverted(uint32_t page_number,
                           float scale_factor,
                           std::unique_ptr<MetafilePlayer> metafile);
 
   // Helper method to do the work for ResetPageMapping(). Split for unit tests.
-  static std::vector<int> GetFullPageMapping(const std::vector<int>& pages,
-                                             int total_page_count);
+  static std::vector<uint32_t> GetFullPageMapping(
+      const std::vector<uint32_t>& pages,
+      uint32_t total_page_count);
 #endif  // defined(OS_WIN)
 
   content::NotificationRegistrar registrar_;
@@ -218,7 +219,7 @@
 #if defined(OS_WIN)
   class PdfConversionState;
   std::unique_ptr<PdfConversionState> pdf_conversion_state_;
-  std::vector<int> pdf_page_mapping_;
+  std::vector<uint32_t> pdf_page_mapping_;
 #endif  // defined(OS_WIN)
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/printing/print_job_unittest.cc b/chrome/browser/printing/print_job_unittest.cc
index 56414e8ce..1afc7e0 100644
--- a/chrome/browser/printing/print_job_unittest.cc
+++ b/chrome/browser/printing/print_job_unittest.cc
@@ -149,28 +149,33 @@
   content::BrowserTaskEnvironment task_environment;
 
   int page_count = 4;
-  std::vector<int> input_full = {0, 1, 2, 3};
-  std::vector<int> expected_output_full = {0, 1, 2, 3};
+  std::vector<uint32_t> input_full = {0, 1, 2, 3};
+  std::vector<uint32_t> expected_output_full = {0, 1, 2, 3};
   EXPECT_EQ(expected_output_full,
             PrintJob::GetFullPageMapping(input_full, page_count));
 
-  std::vector<int> input_12 = {1, 2};
-  std::vector<int> expected_output_12 = {-1, 1, 2, -1};
+  std::vector<uint32_t> input_12 = {1, 2};
+  std::vector<uint32_t> expected_output_12 = {kInvalidPageIndex, 1, 2,
+                                              kInvalidPageIndex};
   EXPECT_EQ(expected_output_12,
             PrintJob::GetFullPageMapping(input_12, page_count));
 
-  std::vector<int> input_03 = {0, 3};
-  std::vector<int> expected_output_03 = {0, -1, -1, 3};
+  std::vector<uint32_t> input_03 = {0, 3};
+  std::vector<uint32_t> expected_output_03 = {0, kInvalidPageIndex,
+                                              kInvalidPageIndex, 3};
   EXPECT_EQ(expected_output_03,
             PrintJob::GetFullPageMapping(input_03, page_count));
 
-  std::vector<int> input_0 = {0};
-  std::vector<int> expected_output_0 = {0, -1, -1, -1};
+  std::vector<uint32_t> input_0 = {0};
+  std::vector<uint32_t> expected_output_0 = {
+      0, kInvalidPageIndex, kInvalidPageIndex, kInvalidPageIndex};
   EXPECT_EQ(expected_output_0,
             PrintJob::GetFullPageMapping(input_0, page_count));
 
-  std::vector<int> input_invalid = {4, 100};
-  std::vector<int> expected_output_invalid = {-1, -1, -1, -1};
+  std::vector<uint32_t> input_invalid = {4, 100};
+  std::vector<uint32_t> expected_output_invalid = {
+      kInvalidPageIndex, kInvalidPageIndex, kInvalidPageIndex,
+      kInvalidPageIndex};
   EXPECT_EQ(expected_output_invalid,
             PrintJob::GetFullPageMapping(input_invalid, page_count));
 }
diff --git a/chrome/browser/printing/print_job_worker.cc b/chrome/browser/printing/print_job_worker.cc
index 17788cb2..49894fba 100644
--- a/chrome/browser/printing/print_job_worker.cc
+++ b/chrome/browser/printing/print_job_worker.cc
@@ -13,6 +13,7 @@
 #include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/location.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
@@ -153,7 +154,7 @@
 }
 
 void PrintJobWorker::GetSettings(bool ask_user_for_settings,
-                                 int document_page_count,
+                                 uint32_t document_page_count,
                                  bool has_selection,
                                  mojom::MarginType margin_type,
                                  bool is_scripted,
@@ -263,11 +264,12 @@
   std::move(callback).Run(printing_context_->TakeAndResetSettings(), result);
 }
 
-void PrintJobWorker::GetSettingsWithUI(int document_page_count,
+void PrintJobWorker::GetSettingsWithUI(uint32_t document_page_count,
                                        bool has_selection,
                                        bool is_scripted,
                                        SettingsCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK_LE(document_page_count, kMaxPageCount);
 
   content::WebContents* web_contents = GetWebContents();
 
@@ -297,7 +299,7 @@
     web_contents->ExitFullscreen(true);
 
   printing_context_->AskUserForSettings(
-      document_page_count, has_selection, is_scripted,
+      base::checked_cast<int>(document_page_count), has_selection, is_scripted,
       base::BindOnce(&PrintJobWorker::GetSettingsDone,
                      weak_factory_.GetWeakPtr(), std::move(callback)));
 }
@@ -417,7 +419,7 @@
   }
 
   while (true) {
-    scoped_refptr<PrintedPage> page = document_->GetPage(page_number_.ToInt());
+    scoped_refptr<PrintedPage> page = document_->GetPage(page_number_.ToUint());
     if (!page) {
       PostWaitForPage();
       return false;
diff --git a/chrome/browser/printing/print_job_worker.h b/chrome/browser/printing/print_job_worker.h
index 429c2b7..2494da2 100644
--- a/chrome/browser/printing/print_job_worker.h
+++ b/chrome/browser/printing/print_job_worker.h
@@ -51,7 +51,7 @@
   // |is_scripted| should be true for calls coming straight from window.print().
   // |is_modifiable| implies HTML and not other formats like PDF.
   void GetSettings(bool ask_user_for_settings,
-                   int document_page_count,
+                   uint32_t document_page_count,
                    bool has_selection,
                    mojom::MarginType margin_type,
                    bool is_scripted,
@@ -142,7 +142,7 @@
   // Asks the user for print settings. Must be called on the UI thread.
   // Required on Mac and Linux. Windows can display UI from non-main threads,
   // but sticks with this for consistency.
-  void GetSettingsWithUI(int document_page_count,
+  void GetSettingsWithUI(uint32_t document_page_count,
                          bool has_selection,
                          bool is_scripted,
                          SettingsCallback callback);
diff --git a/chrome/browser/printing/print_preview_message_handler.cc b/chrome/browser/printing/print_preview_message_handler.cc
index e51a057f..8d0277b 100644
--- a/chrome/browser/printing/print_preview_message_handler.cc
+++ b/chrome/browser/printing/print_preview_message_handler.cc
@@ -14,6 +14,7 @@
 #include "base/memory/read_only_shared_memory_region.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/ref_counted_memory.h"
+#include "base/numerics/safe_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/printing/pdf_nup_converter_client.h"
 #include "chrome/browser/printing/print_job_manager.h"
@@ -65,8 +66,8 @@
   return IsOopifEnabled() && print_preview_ui->source_is_modifiable();
 }
 
-bool IsValidPageNumber(int page_number, int page_count) {
-  return page_number >= 0 && page_number < page_count;
+bool IsValidPageNumber(uint32_t page_number, uint32_t page_count) {
+  return page_number < page_count;
 }
 
 }  // namespace
@@ -112,12 +113,13 @@
 void PrintPreviewMessageHandler::OnDidStartPreview(
     const mojom::DidStartPreviewParams& params,
     const mojom::PreviewIds& ids) {
-  if (params.page_count <= 0 || params.pages_to_render.empty()) {
+  if (params.page_count == 0 || params.page_count > kMaxPageCount ||
+      params.pages_to_render.empty()) {
     NOTREACHED();
     return;
   }
 
-  for (int page_number : params.pages_to_render) {
+  for (uint32_t page_number : params.pages_to_render) {
     if (!IsValidPageNumber(page_number, params.page_count)) {
       NOTREACHED();
       return;
@@ -176,10 +178,12 @@
     content::RenderFrameHost* render_frame_host,
     const mojom::DidPreviewPageParams& params,
     const mojom::PreviewIds& ids) {
-  int page_number = params.page_number;
+  uint32_t page_number = params.page_number;
   const mojom::DidPrintContentParams& content = *params.content;
-  if (page_number < FIRST_PAGE_INDEX || !content.metafile_data_region.IsValid())
+  if (page_number == kInvalidPageIndex ||
+      !content.metafile_data_region.IsValid()) {
     return;
+  }
 
   PrintPreviewUI* print_preview_ui = GetPrintPreviewUI(ids.ui_id);
   if (!print_preview_ui)
@@ -285,7 +289,7 @@
 
 void PrintPreviewMessageHandler::NotifyUIPreviewPageReady(
     PrintPreviewUI* print_preview_ui,
-    int page_number,
+    uint32_t page_number,
     const mojom::PreviewIds& ids,
     scoped_refptr<base::RefCountedMemory> data_bytes) {
   if (!data_bytes || !data_bytes->size())
@@ -315,7 +319,7 @@
 }
 
 void PrintPreviewMessageHandler::OnCompositePdfPageDone(
-    int page_number,
+    uint32_t page_number,
     int document_cookie,
     const mojom::PreviewIds& ids,
     mojom::PrintCompositor::Status status,
@@ -343,15 +347,17 @@
         base::RefCountedSharedMemoryMapping::CreateFromWholeRegion(region));
   } else {
     print_preview_ui->AddPdfPageForNupConversion(std::move(region));
-    int current_page_index =
+    uint32_t current_page_index =
         print_preview_ui->GetPageToNupConvertIndex(page_number);
-    if (current_page_index == -1) {
+    if (current_page_index == kInvalidPageIndex) {
       return;
     }
 
     if (((current_page_index + 1) % pages_per_sheet) == 0 ||
         print_preview_ui->LastPageComposited(page_number)) {
-      int new_page_number = current_page_index / pages_per_sheet;
+      uint32_t new_page_number =
+          base::checked_cast<uint32_t>(current_page_index / pages_per_sheet);
+      DCHECK_NE(new_page_number, kInvalidPageIndex);
       std::vector<base::ReadOnlySharedMemoryRegion> pdf_page_regions =
           print_preview_ui->TakePagesForNupConvert();
 
@@ -376,7 +382,7 @@
 }
 
 void PrintPreviewMessageHandler::OnNupPdfConvertDone(
-    int page_number,
+    uint32_t page_number,
     const mojom::PreviewIds& ids,
     mojom::PdfNupConverter::Status status,
     base::ReadOnlySharedMemoryRegion region) {
diff --git a/chrome/browser/printing/print_preview_message_handler.h b/chrome/browser/printing/print_preview_message_handler.h
index f0ef120..afcb879 100644
--- a/chrome/browser/printing/print_preview_message_handler.h
+++ b/chrome/browser/printing/print_preview_message_handler.h
@@ -81,7 +81,7 @@
 
   void NotifyUIPreviewPageReady(
       PrintPreviewUI* print_preview_ui,
-      int page_number,
+      uint32_t page_number,
       const mojom::PreviewIds& ids,
       scoped_refptr<base::RefCountedMemory> data_bytes);
   void NotifyUIPreviewDocumentReady(
@@ -90,7 +90,7 @@
       scoped_refptr<base::RefCountedMemory> data_bytes);
 
   // Callbacks for print compositor client.
-  void OnCompositePdfPageDone(int page_number,
+  void OnCompositePdfPageDone(uint32_t page_number,
                               int document_cookie,
                               const mojom::PreviewIds& ids,
                               mojom::PrintCompositor::Status status,
@@ -102,7 +102,7 @@
   void OnPrepareForDocumentToPdfDone(const mojom::PreviewIds& ids,
                                      mojom::PrintCompositor::Status status);
 
-  void OnNupPdfConvertDone(int page_number,
+  void OnNupPdfConvertDone(uint32_t page_number,
                            const mojom::PreviewIds& ids,
                            mojom::PdfNupConverter::Status status,
                            base::ReadOnlySharedMemoryRegion region);
diff --git a/chrome/browser/printing/print_view_manager_base.cc b/chrome/browser/printing/print_view_manager_base.cc
index 915c981..fb2a4c0 100644
--- a/chrome/browser/printing/print_view_manager_base.cc
+++ b/chrome/browser/printing/print_view_manager_base.cc
@@ -13,6 +13,7 @@
 #include "base/location.h"
 #include "base/memory/read_only_shared_memory_region.h"
 #include "base/memory/ref_counted_memory.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
@@ -187,7 +188,7 @@
 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
 void PrintViewManagerBase::OnPrintSettingsDone(
     scoped_refptr<base::RefCountedMemory> print_data,
-    int page_count,
+    uint32_t page_count,
     PrinterHandler::PrintCallback callback,
     std::unique_ptr<printing::PrinterQuery> printer_query) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -226,7 +227,7 @@
 
 void PrintViewManagerBase::StartLocalPrintJob(
     scoped_refptr<base::RefCountedMemory> print_data,
-    int page_count,
+    uint32_t page_count,
     int cookie,
     PrinterHandler::PrintCallback callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -274,7 +275,7 @@
 }
 
 void PrintViewManagerBase::DidGetPrintedPagesCount(int32_t cookie,
-                                                   int32_t number_pages) {
+                                                   uint32_t number_pages) {
   PrintManager::DidGetPrintedPagesCount(cookie, number_pages);
   OpportunisticallyCreatePrintJob(cookie);
 }
@@ -478,7 +479,8 @@
     case JobEventDetails::DOC_DONE: {
       // Don't care about the actual printing process, except on Android.
 #if defined(OS_ANDROID)
-      PdfWritingDone(number_pages_);
+      DCHECK_LE(number_pages_, kMaxPageCount);
+      PdfWritingDone(base::checked_cast<int>(number_pages_));
 #endif
       break;
     }
diff --git a/chrome/browser/printing/print_view_manager_base.h b/chrome/browser/printing/print_view_manager_base.h
index a40dfc9..3283286 100644
--- a/chrome/browser/printing/print_view_manager_base.h
+++ b/chrome/browser/printing/print_view_manager_base.h
@@ -76,7 +76,7 @@
   }
 
   // mojom::PrintManagerHost:
-  void DidGetPrintedPagesCount(int32_t cookie, int32_t number_pages) override;
+  void DidGetPrintedPagesCount(int32_t cookie, uint32_t number_pages) override;
 #if BUILDFLAG(ENABLE_TAGGED_PDF)
   void SetAccessibilityTree(
       int32_t cookie,
@@ -147,12 +147,12 @@
 // Helpers for PrintForPrintPreview();
 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
   void OnPrintSettingsDone(scoped_refptr<base::RefCountedMemory> print_data,
-                           int page_count,
+                           uint32_t page_count,
                            PrinterHandler::PrintCallback callback,
                            std::unique_ptr<PrinterQuery> printer_query);
 
   void StartLocalPrintJob(scoped_refptr<base::RefCountedMemory> print_data,
-                          int page_count,
+                          uint32_t page_count,
                           int cookie,
                           PrinterHandler::PrintCallback callback);
 #endif  // BUILDFLAG(ENABLE_PRINT_PREVIEW)
diff --git a/chrome/browser/printing/printer_query.cc b/chrome/browser/printing/printer_query.cc
index fb46f27..5c35783 100644
--- a/chrome/browser/printing/printer_query.cc
+++ b/chrome/browser/printing/printer_query.cc
@@ -87,7 +87,7 @@
 }
 
 void PrinterQuery::GetSettings(GetSettingsAskParam ask_user_for_settings,
-                               int expected_page_count,
+                               uint32_t expected_page_count,
                                bool has_selection,
                                mojom::MarginType margin_type,
                                bool is_scripted,
diff --git a/chrome/browser/printing/printer_query.h b/chrome/browser/printing/printer_query.h
index 467c1c3..a9e24a7 100644
--- a/chrome/browser/printing/printer_query.h
+++ b/chrome/browser/printing/printer_query.h
@@ -51,7 +51,7 @@
   // |ask_for_user_settings| is DEFAULTS.
   // Caller has to ensure that |this| is alive until |callback| is run.
   void GetSettings(GetSettingsAskParam ask_user_for_settings,
-                   int expected_page_count,
+                   uint32_t expected_page_count,
                    bool has_selection,
                    mojom::MarginType margin_type,
                    bool is_scripted,
diff --git a/chrome/browser/printing/test_print_job.cc b/chrome/browser/printing/test_print_job.cc
index ccf0dc10..a9a5df3 100644
--- a/chrome/browser/printing/test_print_job.cc
+++ b/chrome/browser/printing/test_print_job.cc
@@ -18,7 +18,7 @@
 
 void TestPrintJob::Initialize(std::unique_ptr<PrinterQuery> query,
                               const base::string16& name,
-                              int page_count) {
+                              uint32_t page_count) {
   // Since we do not actually print in these tests, just let this get destroyed
   // when this function exits.
   std::unique_ptr<PrintJobWorker> worker = query->DetachWorker();
diff --git a/chrome/browser/printing/test_print_job.h b/chrome/browser/printing/test_print_job.h
index 47de142..45bc203 100644
--- a/chrome/browser/printing/test_print_job.h
+++ b/chrome/browser/printing/test_print_job.h
@@ -39,7 +39,7 @@
   // All remaining functions are PrintJob implementation.
   void Initialize(std::unique_ptr<PrinterQuery> query,
                   const base::string16& name,
-                  int page_count) override;
+                  uint32_t page_count) override;
 
   // Sets |job_pending_| to true.
   void StartPrinting() override;
diff --git a/chrome/browser/profiles/profile_attributes_entry.cc b/chrome/browser/profiles/profile_attributes_entry.cc
index a25a9bdd..c18ba90 100644
--- a/chrome/browser/profiles/profile_attributes_entry.cc
+++ b/chrome/browser/profiles/profile_attributes_entry.cc
@@ -40,7 +40,7 @@
 #endif
 
 #if !defined(OS_ANDROID)
-#include "chrome/browser/themes/theme_properties.h"
+#include "chrome/browser/themes/theme_properties.h"  // nogncheck crbug.com/1125897
 #include "chrome/browser/ui/signin/profile_colors_util.h"
 #endif
 
diff --git a/chrome/browser/profiles/profile_avatar_icon_util.cc b/chrome/browser/profiles/profile_avatar_icon_util.cc
index 6d88545..27c6672 100644
--- a/chrome/browser/profiles/profile_avatar_icon_util.cc
+++ b/chrome/browser/profiles/profile_avatar_icon_util.cc
@@ -44,7 +44,7 @@
 
 #if defined(OS_WIN)
 #include "chrome/browser/profiles/profile_attributes_entry.h"
-#include "chrome/grit/chrome_unscaled_resources.h"
+#include "chrome/grit/chrome_unscaled_resources.h"  // nogncheck crbug.com/1125897
 #include "ui/gfx/icon_util.h"  // For Iconutil::kLargeIconSize.
 #endif
 
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index 9e827b4e..222d718 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -34,6 +34,7 @@
 #include "chrome/browser/apps/app_service/browser_app_launcher.h"
 #include "chrome/browser/apps/platform_apps/app_load_service.h"
 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
+#include "chrome/browser/browser_features.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
 #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h"
@@ -843,6 +844,10 @@
   if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_COPY)) {
     DCHECK(!editable);
     AppendCopyItem();
+
+    if (base::FeatureList::IsEnabled(features::kCopyLinkToText)) {
+      AppendCopyLinkToTextItem();
+    }
   }
 
   if (!content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_LINK))
@@ -1565,6 +1570,11 @@
                                   IDS_CONTENT_CONTEXT_COPY);
 }
 
+void RenderViewContextMenu::AppendCopyLinkToTextItem() {
+  menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYLINKTOTEXT,
+                                  IDS_CONTENT_CONTEXT_COPYLINKTOTEXT);
+}
+
 void RenderViewContextMenu::AppendPrintItem() {
   if (GetPrefs(browser_context_)->GetBoolean(prefs::kPrintingEnabled) &&
       (params_.media_type == ContextMenuDataMediaType::kNone ||
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.h b/chrome/browser/renderer_context_menu/render_view_context_menu.h
index 140c038..2099838 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.h
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.h
@@ -175,6 +175,7 @@
   void AppendPageItems();
   void AppendExitFullscreenItem();
   void AppendCopyItem();
+  void AppendCopyLinkToTextItem();
   void AppendPrintItem();
   void AppendMediaRouterItem();
   void AppendRotationItems();
diff --git a/chrome/browser/renderer_host/pepper/device_id_fetcher.cc b/chrome/browser/renderer_host/pepper/device_id_fetcher.cc
index 892dbd6..ca6d0ac5 100644
--- a/chrome/browser/renderer_host/pepper/device_id_fetcher.cc
+++ b/chrome/browser/renderer_host/pepper/device_id_fetcher.cc
@@ -30,7 +30,7 @@
 #endif
 
 #if BUILDFLAG(ENABLE_RLZ)
-#include "rlz/lib/machine_id.h"
+#include "rlz/lib/machine_id.h"  // nogncheck crbug.com/1125897
 #endif
 
 using content::BrowserPpapiHost;
diff --git a/chrome/browser/reputation/url_elision_policy.cc b/chrome/browser/reputation/url_elision_policy.cc
index acaa6da..4d076dc 100644
--- a/chrome/browser/reputation/url_elision_policy.cc
+++ b/chrome/browser/reputation/url_elision_policy.cc
@@ -6,7 +6,6 @@
 
 #include "base/feature_list.h"
 #include "chrome/browser/reputation/local_heuristics.h"
-#include "chrome/browser/reputation/safety_tip_test_utils.h"
 #include "chrome/browser/reputation/safety_tips_config.h"
 #include "components/lookalikes/core/lookalike_url_util.h"
 #include "components/omnibox/common/omnibox_features.h"
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/navigation_manager.js b/chrome/browser/resources/chromeos/accessibility/switch_access/navigation_manager.js
index e6f5e48..332c2d5 100644
--- a/chrome/browser/resources/chromeos/accessibility/switch_access/navigation_manager.js
+++ b/chrome/browser/resources/chromeos/accessibility/switch_access/navigation_manager.js
@@ -190,12 +190,11 @@
       return;
     }
     const navigator = NavigationManager.instance;
-    const baseNode = node.automationNode;
-    if (!(node instanceof BasicNode) || !baseNode) {
+    if (!(node instanceof BasicNode)) {
       navigator.setNode_(node);
       return;
     }
-    if (!SwitchAccessPredicate.isWindow(baseNode)) {
+    if (!SwitchAccessPredicate.isWindow(node.automationNode)) {
       navigator.setNode_(node);
       return;
     }
@@ -212,9 +211,7 @@
     // possible that other parts of the window are occluded, but in Chrome we
     // can't drag windows off the top of the screen.
     navigator.desktop_.hitTestWithReply(center.x, location.top, (hitNode) => {
-      if (AutomationUtil.isDescendantOf(
-              hitNode,
-              /** @type {!AutomationNode} */ (baseNode))) {
+      if (AutomationUtil.isDescendantOf(hitNode, node.automationNode)) {
         navigator.setNode_(node);
       } else if (node.isValidAndVisible()) {
         NavigationManager.tryMoving(getNext(node), getNext, startingNode);
@@ -241,11 +238,8 @@
     if (nodeIsValid && !(navigator.node_ instanceof BackButtonNode)) {
       // Our group has been invalidated. Move to navigator node to repair the
       // group stack.
-      const node = navigator.node_.automationNode;
-      if (node) {
-        navigator.moveTo_(node);
-        return;
-      }
+      navigator.moveTo_(navigator.node_.automationNode);
+      return;
     }
 
     // Make sure the menu isn't open.
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/back_button_node.js b/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/back_button_node.js
index 84abd34..0725173 100644
--- a/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/back_button_node.js
+++ b/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/back_button_node.js
@@ -88,13 +88,11 @@
         true /* show */, this.group_.location);
     BackButtonNode.findAutomationNode_();
 
-    if (this.group_.automationNode) {
-      this.locationChangedHandler_ = new RepeatedEventHandler(
-          this.group_.automationNode,
-          chrome.automation.EventType.LOCATION_CHANGED,
-          () => FocusRingManager.setFocusedNode(this),
-          {exactMatch: true, allAncestors: true});
-    }
+    this.locationChangedHandler_ = new RepeatedEventHandler(
+        this.group_.automationNode,
+        chrome.automation.EventType.LOCATION_CHANGED,
+        () => FocusRingManager.setFocusedNode(this),
+        {exactMatch: true, allAncestors: true});
   }
 
   /** @override */
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/basic_node.js b/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/basic_node.js
index 3c2aedb..f38112ff 100644
--- a/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/basic_node.js
+++ b/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/basic_node.js
@@ -232,10 +232,7 @@
    * @param {!AutomationNode} baseNode
    */
   constructor(baseNode) {
-    super();
-
-    /** @private {!AutomationNode} */
-    this.baseNode_ = baseNode;
+    super(baseNode);
 
     /** @private {boolean} */
     this.invalidated_ = false;
@@ -247,13 +244,8 @@
   // ================= Getters and setters =================
 
   /** @override */
-  get automationNode() {
-    return this.baseNode_;
-  }
-
-  /** @override */
   get location() {
-    return this.baseNode_.location || super.location;
+    return this.automationNode.location || super.location;
   }
 
   // ================= General methods =================
@@ -263,38 +255,37 @@
     if (!(other instanceof BasicRootNode)) {
       return false;
     }
-
-    other = /** @type {!BasicRootNode} */ (other);
-    return super.equals(other) && this.baseNode_ === other.baseNode_;
+    return super.equals(other) && this.automationNode === other.automationNode;
   }
 
   /** @override */
   isEquivalentTo(node) {
     if (node instanceof BasicRootNode || node instanceof BasicNode) {
-      return this.baseNode_ === node.baseNode_;
+      return this.automationNode === node.automationNode;
     }
 
     if (node instanceof SAChildNode) {
       return node.isEquivalentTo(this);
     }
-    return this.baseNode_ === node;
+    return this.automationNode === node;
   }
 
   /** @override */
   isValidGroup() {
-    if (!this.baseNode_.role) {
+    if (!this.automationNode.role) {
       // If the underlying automation node has been invalidated, return false.
       return false;
     }
     return !this.invalidated_ &&
-        SwitchAccessPredicate.isVisible(this.baseNode_) && super.isValidGroup();
+        SwitchAccessPredicate.isVisible(this.automationNode) &&
+        super.isValidGroup();
   }
 
   /** @override */
   onFocus() {
     super.onFocus();
     this.childrenChangedHandler_ = new RepeatedEventHandler(
-        this.baseNode_, chrome.automation.EventType.CHILDREN_CHANGED,
+        this.automationNode, chrome.automation.EventType.CHILDREN_CHANGED,
         this.refresh.bind(this));
   }
 
@@ -398,7 +389,7 @@
    */
   static getInterestingChildren(root) {
     if (root instanceof BasicRootNode) {
-      root = root.baseNode_;
+      root = root.automationNode;
     }
 
     if (root.children.length === 0) {
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/combo_box_node.js b/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/combo_box_node.js
index 7c25c03..dbed6ea 100644
--- a/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/combo_box_node.js
+++ b/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/combo_box_node.js
@@ -31,13 +31,11 @@
 
   /** @override */
   onFocus() {
-    if (this.automationNode) {
-      this.expandedChangedHandler_ = new RepeatedEventHandler(
-          this.automationNode, chrome.automation.EventType.EXPANDED_CHANGED,
-          () => this.onExpandedChanged(), {exactMatch: true});
-    }
-
     super.onFocus();
+
+    this.expandedChangedHandler_ = new RepeatedEventHandler(
+        this.automationNode, chrome.automation.EventType.EXPANDED_CHANGED,
+        () => this.onExpandedChanged(), {exactMatch: true});
     this.automationNode.focus();
   }
 
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/group_node.js b/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/group_node.js
index 4c0a498..08f67c77 100644
--- a/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/group_node.js
+++ b/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/group_node.js
@@ -12,13 +12,18 @@
   /**
    * @param {!Array<!SAChildNode>} children The nodes that this group contains.
    *     Should not include the back button.
+   * @param {!AutomationNode} containingNode The automation node most closely
+   * containing the children.
    * @private
    */
-  constructor(children) {
+  constructor(children, containingNode) {
     super();
 
-    /** @type {!Array<!SAChildNode>} */
+    /** @private {!Array<!SAChildNode>} */
     this.children_ = children;
+
+    /** @private {!AutomationNode} */
+    this.containingNode_ = containingNode;
   }
 
   // ================= Getters and setters =================
@@ -30,7 +35,7 @@
 
   /** @override */
   get automationNode() {
-    return null;
+    return this.containingNode_;
   }
 
   /** @override */
@@ -49,7 +54,7 @@
 
   /** @override */
   asRootNode() {
-    const root = new SARootNode();
+    const root = new SARootNode(this.containingNode_);
 
     // Make a copy of the children array.
     const children = [...this.children_];
@@ -122,9 +127,10 @@
   /**
    * Assumes nodes are visually in rows.
    * @param {!Array<!SAChildNode>} nodes
+   * @param {!AutomationNode} containingNode
    * @return {!Array<!GroupNode>}
    */
-  static separateByRow(nodes) {
+  static separateByRow(nodes, containingNode) {
     const result = [];
 
     for (let i = 0; i < nodes.length;) {
@@ -138,7 +144,7 @@
         i++;
       }
 
-      result.push(new GroupNode(children));
+      result.push(new GroupNode(children, containingNode));
     }
 
     return result;
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/keyboard_node.js b/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/keyboard_node.js
index 8e4958d..9798788 100644
--- a/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/keyboard_node.js
+++ b/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/keyboard_node.js
@@ -177,8 +177,8 @@
     const interestingChildren =
         root.automationNode.findAll({role: chrome.automation.RoleType.BUTTON});
     /** @type {!Array<!SAChildNode>} */
-    const children =
-        GroupNode.separateByRow(interestingChildren.map(childConstructor));
+    const children = GroupNode.separateByRow(
+        interestingChildren.map(childConstructor), root.automationNode);
 
     children.push(new BackButtonNode(root));
     root.children = children;
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/switch_access_node.js b/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/switch_access_node.js
index 0fde0798..fdea5a0 100644
--- a/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/switch_access_node.js
+++ b/chrome/browser/resources/chromeos/accessibility/switch_access/nodes/switch_access_node.js
@@ -37,8 +37,8 @@
   get actions() {}
 
   /**
-   * Returns the underlying automation node, if one exists.
-   * @return {AutomationNode}
+   * The automation node that most closely contains this node.
+   * @return {!AutomationNode}
    * @abstract
    */
   get automationNode() {}
@@ -217,9 +217,8 @@
 
     let str = this.role + ' ';
 
-    const autoNode = this.automationNode;
-    if (autoNode && autoNode.name) {
-      str += 'name(' + autoNode.name + ') ';
+    if (this.automationNode.name) {
+      str += 'name(' + this.automationNode.name + ') ';
     }
 
     const loc = this.location;
@@ -251,15 +250,27 @@
  * This class represents the root node of a Switch Access traversal group.
  */
 class SARootNode {
-  constructor() {
+  /**
+   * @param {!AutomationNode} autoNode The automation node that most closely
+   *     contains all of this node's children.
+   */
+  constructor(autoNode) {
     /** @private {!Array<!SAChildNode>} */
     this.children_ = [];
+
+    /** @private {!AutomationNode} */
+    this.automationNode_ = autoNode;
   }
 
   // ================= Getters and setters =================
 
-  /** @return {AutomationNode} */
-  get automationNode() {}
+  /**
+   * @return {!AutomationNode} The automation node that most closely
+   *     contains all of this node's children.
+   */
+  get automationNode() {
+    return this.automationNode_;
+  }
 
   /** @param {!Array<!SAChildNode>} newVal */
   set children(newVal) {
@@ -402,13 +413,9 @@
    * @return {string}
    */
   debugString(wholeTree = false, prefix = '', currentNode = null) {
-    const autoNode = this.automationNode;
-    let str = 'Root: ';
-    if (autoNode && autoNode.role) {
-      str += autoNode.role + ' ';
-    }
-    if (autoNode && autoNode.name) {
-      str += 'name(' + autoNode.name + ') ';
+    let str = 'Root: ' + this.automationNode.role + ' ';
+    if (this.automationNode.name) {
+      str += 'name(' + this.automationNode.name + ') ';
     }
 
     const loc = this.location;
@@ -416,7 +423,6 @@
       str += 'loc(' + RectUtil.toString(loc) + ') ';
     }
 
-
     for (const child of this.children) {
       str += '\n' + prefix + ((child.equals(currentNode)) ? ' * ' : ' - ');
       str += child.debugString(wholeTree, prefix, currentNode);
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/switch_access_predicate_test.js b/chrome/browser/resources/chromeos/accessibility/switch_access/switch_access_predicate_test.js
index 3ff64d7..7015510 100644
--- a/chrome/browser/resources/chromeos/accessibility/switch_access/switch_access_predicate_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/switch_access/switch_access_predicate_test.js
@@ -448,7 +448,7 @@
         return null;
       }
     }
-    const group = new TestRoot();
+    const group = new TestRoot(t.root);
 
     assertTrue(
         SwitchAccessPredicate.isGroup(t.root, group, cache),
diff --git a/chrome/browser/resources/chromeos/crostini_installer/app.js b/chrome/browser/resources/chromeos/crostini_installer/app.js
index ff3c5108..c92b178f 100644
--- a/chrome/browser/resources/chromeos/crostini_installer/app.js
+++ b/chrome/browser/resources/chromeos/crostini_installer/app.js
@@ -412,9 +412,6 @@
       case InstallerState.kInstallImageLoader:
         messageId = 'loadTerminaMessage';
         break;
-      case InstallerState.kStartConcierge:
-        messageId = 'startConciergeMessage';
-        break;
       case InstallerState.kCreateDiskImage:
         messageId = 'createDiskImageMessage';
         break;
@@ -461,9 +458,6 @@
       case InstallerError.kErrorLoadingTermina:
         messageId = 'loadTerminaError';
         break;
-      case InstallerError.kErrorStartingConcierge:
-        messageId = 'startConciergeError';
-        break;
       case InstallerError.kErrorCreatingDiskImage:
         messageId = 'createDiskImageError';
         break;
diff --git a/chrome/browser/resources/chromeos/multidevice_internals/BUILD.gn b/chrome/browser/resources/chromeos/multidevice_internals/BUILD.gn
index c86697f7..052dbe92 100644
--- a/chrome/browser/resources/chromeos/multidevice_internals/BUILD.gn
+++ b/chrome/browser/resources/chromeos/multidevice_internals/BUILD.gn
@@ -15,6 +15,8 @@
     ":multidevice_logs_browser_proxy",
     ":multidevice_phonehub_browser_proxy",
     ":multidevice_phonehub_browser_proxy",
+    ":notification_form",
+    ":notification_manager",
     ":phone_name_form",
     ":phone_status_model_form",
     ":phonehub_tab",
@@ -22,6 +24,20 @@
   ]
 }
 
+js_library("notification_manager") {
+  deps = [
+    ":notification_form",
+    ":types",
+  ]
+}
+
+js_library("notification_form") {
+  deps = [
+    ":multidevice_phonehub_browser_proxy",
+    ":types",
+  ]
+}
+
 js_library("browser_tabs_model_form") {
   deps = [
     ":multidevice_phonehub_browser_proxy",
@@ -96,6 +112,7 @@
     ":browser_tabs_model_form",
     ":i18n_setup",
     ":multidevice_phonehub_browser_proxy",
+    ":notification_manager",
     ":phone_status_model_form",
     ":types",
     "//ui/webui/resources/js:load_time_data.m",
@@ -119,5 +136,7 @@
     "shared_style.js",
     "browser_tabs_metadata_form.js",
     "browser_tabs_model_form.js",
+    "notification_form.js",
+    "notification_manager.js",
   ]
 }
diff --git a/chrome/browser/resources/chromeos/multidevice_internals/browser_tabs_metadata_form.html b/chrome/browser/resources/chromeos/multidevice_internals/browser_tabs_metadata_form.html
index 11888de..ee75acd 100644
--- a/chrome/browser/resources/chromeos/multidevice_internals/browser_tabs_metadata_form.html
+++ b/chrome/browser/resources/chromeos/multidevice_internals/browser_tabs_metadata_form.html
@@ -10,31 +10,30 @@
 </style>
 
 <div class="column">
-  <div class="label">URL: </div>
-  <cr-input value="{{url_}}" id="urlInput" auto-validate required
+  <cr-input value="{{url_}}" id="urlInput" auto-validate required label="URL: "
       error-message="This browser tab will be a nullopt if no url input">
   </cr-input>
 </div>
 <div class="column">
-  <div class="label">Title: </div>
-  <cr-input value="{{title_}}" id="titleInput" auto-validate required
+  <cr-input value="{{title_}}" label="Title:" auto-validate required
       error-message="This browser tab will be a nullopt if no title input">
   </cr-input>
 </div>
 <div class="column">
-  <div class="label">Last Accessed (ms): </div>
-  <cr-input value="{{lastAccessedTimeStamp_}}"
+  <cr-input value="{{lastAccessedTimeStamp_}}" label="Last Accessed (ms):"
       id="lastAccessedTimeStampInput" type="number" min="0"
       on-change="onLastAccessTimeStampChanged_"
       auto-validate error-message="Must be greater than 0" required>
   </cr-input>
 </div>
 <div class="column" id="faviconSelector">
-  <div class="label">Favicon selector: </div>
+  <label>Favicon Image Type</label>
   <select id="faviconList" class="md-select"
-    on-change="onFaviconSelected_">
+      on-change="onFaviconSelected_">
     <template is="dom-repeat" items="[[faviconList_]]">
-      <option>[[getFaviconTypeName_(item)]]</option>
+      <option selected="[[isEqual_(item, favicon_)]]">
+        [[getImageTypeName_(item)]]
+      </option>
     </template>
   </select>
 </div>
diff --git a/chrome/browser/resources/chromeos/multidevice_internals/browser_tabs_metadata_form.js b/chrome/browser/resources/chromeos/multidevice_internals/browser_tabs_metadata_form.js
index 25daee2..0565087 100644
--- a/chrome/browser/resources/chromeos/multidevice_internals/browser_tabs_metadata_form.js
+++ b/chrome/browser/resources/chromeos/multidevice_internals/browser_tabs_metadata_form.js
@@ -8,19 +8,7 @@
 import './shared_style.js';
 
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {BrowserTabsMetadataModel, FaviconType} from './types.js';
-
-/**
- * Maps a FaviconType to its title label in the dropdown.
- * @type {!Map<FaviconType, String>}
- */
-const faviconTypeToStringMap = new Map([
-  [FaviconType.PINK, 'Pink'],
-  [FaviconType.RED, 'Red'],
-  [FaviconType.GREEN, 'Green'],
-  [FaviconType.BLUE, 'Blue'],
-  [FaviconType.YELLOW, 'Yellow'],
-]);
+import {BrowserTabsMetadataModel, ImageType, imageTypeToStringMap} from './types.js';
 
 Polymer({
   is: 'browser-tabs-metadata-form',
@@ -53,10 +41,10 @@
       value: Date.now(),
     },
 
-    /** @private{FaviconType} */
+    /** @private{ImageType} */
     favicon_: {
       type: Number,
-      value: FaviconType.PINK,
+      value: ImageType.PINK,
     },
 
     /** @private */
@@ -64,11 +52,12 @@
       type: Array,
       value: () => {
         return [
-          FaviconType.PINK,
-          FaviconType.RED,
-          FaviconType.GREEN,
-          FaviconType.BLUE,
-          FaviconType.YELLOW,
+          ImageType.NONE,
+          ImageType.PINK,
+          ImageType.RED,
+          ImageType.GREEN,
+          ImageType.BLUE,
+          ImageType.YELLOW,
         ];
       },
       readonly: true,
@@ -76,12 +65,12 @@
   },
 
   /**
-   * @param {FaviconType} faviconType
+   * @param {ImageType} faviconType
    * @return {String}
    * @private
    */
-  getFaviconTypeName_(faviconType) {
-    return faviconTypeToStringMap.get(faviconType);
+  getImageTypeName_(faviconType) {
+    return imageTypeToStringMap.get(faviconType);
   },
 
   /** @private */
@@ -114,4 +103,14 @@
 
     this.lastAccessedTimeStamp_ = Number(inputValue);
   },
+
+  /**
+   * @param {*} lhs
+   * @param {*} rhs
+   * @return {boolean}
+   * @private
+   */
+  isEqual_(lhs, rhs) {
+    return lhs === rhs;
+  },
 });
diff --git a/chrome/browser/resources/chromeos/multidevice_internals/multidevice_internals_resources.grd b/chrome/browser/resources/chromeos/multidevice_internals/multidevice_internals_resources.grd
index cf530b5..f94b8eee 100644
--- a/chrome/browser/resources/chromeos/multidevice_internals/multidevice_internals_resources.grd
+++ b/chrome/browser/resources/chromeos/multidevice_internals/multidevice_internals_resources.grd
@@ -20,6 +20,14 @@
                file="${root_gen_dir}\chrome\browser\resources\chromeos\multidevice_internals\browser_tabs_model_form.js"
                use_base_dir="false"
                type="BINDATA"/>
+      <include name="IDR_MULTIDEVICE_INTERNALS_BROWSER_NOTIFICATION_MANAGER_JS"
+               file="${root_gen_dir}\chrome\browser\resources\chromeos\multidevice_internals\notification_manager.js"
+               use_base_dir="false"
+               type="BINDATA"/>
+      <include name="IDR_MULTIDEVICE_INTERNALS_BROWSER_NOTIFICATION_FORM_JS"
+               file="${root_gen_dir}\chrome\browser\resources\chromeos\multidevice_internals\notification_form.js"
+               use_base_dir="false"
+               type="BINDATA"/>
       <include name="IDR_MULTIDEVICE_INTERNALS_INDEX_HTML"
                file="index.html"
                type="BINDATA"/>
diff --git a/chrome/browser/resources/chromeos/multidevice_internals/multidevice_phonehub_browser_proxy.js b/chrome/browser/resources/chromeos/multidevice_internals/multidevice_phonehub_browser_proxy.js
index 646bde7..6d70823 100644
--- a/chrome/browser/resources/chromeos/multidevice_internals/multidevice_phonehub_browser_proxy.js
+++ b/chrome/browser/resources/chromeos/multidevice_internals/multidevice_phonehub_browser_proxy.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import {addSingletonGetter} from 'chrome://resources/js/cr.m.js';
-import {BrowserTabsModel, FeatureStatus, PhoneStatusModel} from './types.js';
+import {BrowserTabsModel, FeatureStatus, Notification, PhoneStatusModel} from './types.js';
 
 /**
  * JavaScript hooks into the native WebUI handler for Phonehub tab.
@@ -50,6 +50,22 @@
   setBrowserTabs(browserTabsModel) {
     chrome.send('setBrowserTabs', [browserTabsModel]);
   }
+
+  /**
+   * Sets a notification.
+   * @param {!Notification} notification
+   */
+  setNotification(notification) {
+    chrome.send('setNotification', [notification]);
+  }
+
+  /**
+   * Removes a notification with the id |notificationId|
+   * @param {number} notificationId
+   */
+  removeNotification(notificationId) {
+    chrome.send('removeNotification', [notificationId]);
+  }
 }
 
 addSingletonGetter(MultidevicePhoneHubBrowserProxy);
diff --git a/chrome/browser/resources/chromeos/multidevice_internals/notification_form.html b/chrome/browser/resources/chromeos/multidevice_internals/notification_form.html
new file mode 100644
index 0000000..84545ce
--- /dev/null
+++ b/chrome/browser/resources/chromeos/multidevice_internals/notification_form.html
@@ -0,0 +1,128 @@
+<style include="cr-shared-style shared-style">
+  :host {
+    display: flex;
+    flex: 1 0 100%;
+    padding: 10px;
+    width: 100%;
+  }
+
+  :host([is-sent_]) #notificationContainer {
+    background-color: LightGreen;
+  }
+
+  :host(:not([is-sent_])) #notificationContainer {
+    box-shadow: var(--cr-elevation-3);
+  }
+
+  #notificationContainer {
+    display: flex;
+    flex: 1 0 100%;
+  }
+
+  #fields {
+    flex: 4;
+  }
+
+  .dropdown {
+    display: flex;
+    flex-direction: column;
+    padding: 5px;
+  }
+
+  cr-input {
+    padding: 5px;
+  }
+</style>
+<div id="notificationContainer">
+  <div class="column">
+    <cr-button hidden="[[notification.sent]]" id="sendBtn"
+        disabled="[[!isNotificationDataValid_]]"
+        on-click="onSetNotification_" class="internals-button">
+      <span class="emphasize">Send this notification</span>
+    </cr-button>
+    <cr-button hidden="[[!notification.sent]]" id="editBtn"
+        disabled="[[!isNotificationDataValid_]]"
+        on-click="onUpdateNotification_" class="internals-button">
+      <span class="emphasize">[[updateNotificationText_]]</span>
+    </cr-button>
+    <cr-button hidden="[[!notification.sent]]" id="removeBtn"
+        on-click="onRemoveButtonClick_" class="internals-button">
+      <span class="emphasize">Remove this notification</span>
+    </cr-button>
+  </div>
+  <div class="column" id="fields">
+    <cr-input value="{{notification.id}}" label="notification ID"
+        type="number" invalid="[[!isValidId_]]"
+        on-change="onNotificationIdChanged_"
+        auto-validate error-message="ID already used" required
+        disabled="[[notification.sent]]">
+    </cr-input>
+    <cr-input label="Visible App Name"
+        value="{{notification.appMetadata.visibleAppName}}" id="urlInput">
+    </cr-input>
+    <cr-input label="Package Name"
+        value="{{notification.appMetadata.packageName}}" id="packageName">
+    </cr-input>
+    <div class="dropdown">
+      <label>Icon Image Type</label>
+      <select id="iconImageTypeSelector" class="md-select"
+          on-change="onIconImageTypeSelected_">
+        <template is="dom-repeat" items="[[imageList_]]">
+          <option selected="[[isEqual_(item, notification.appMetadata.icon)]]">
+            [[getImageTypeName_(item)]]
+          </option>
+        </template>
+      </select>
+    </div>
+    <div class="dropdown">
+      <label>Importance</label>
+      <select id="importanceSelector" class="md-select"
+          on-change="onImportanceSelected_">
+        <template is="dom-repeat" items="[[importanceList_]]">
+          <option selected="[[isEqual_(item, notification.importance)]]">
+            [[getImportanceName_(item)]]
+          </option>
+        </template>
+      </select>
+    </div>
+    <cr-input value="{{notification.inlineReplyId}}" label="Inline reply id"
+        type="number" error-message="Inline reply ID already used"
+        on-change="onInlineReplyIdChanged_" auto-validate required
+        disabled="[[notification.sent]]" invalid="[[!isValidInlineReplyId_]]">
+    </cr-input>
+    <cr-input value="{{notification.timestamp}}" label="Timestamp (ms)" min="0"
+        id="timestampInput" type="number" on-change="onTimeStampChanged_"
+        auto-validate error-message="Must be greater than 0" required>
+    </cr-input>
+    <cr-input label="Title (Optional)" value="{{notification.title}}">
+    </cr-input>
+    <cr-input label="Text Content (Optional)"
+        value="{{notification.textContent}}" id="textContent">
+    </cr-input>
+    <div class="dropdown">
+      <label>
+        Shared Image Type (Optional)
+      </label>
+      <select id="sharedImageTypeSelector" class="md-select"
+        on-change="onSharedImageTypeSelected_">
+        <template is="dom-repeat" items="[[imageList_]]">
+          <option selected="[[isEqual_(item, notification.sharedImage)]]">
+            [[getImageTypeName_(item)]]
+          </option>
+        </template>
+      </select>
+    </div>
+    <div class="dropdown">
+      <label>Contact Image Type (Optional)</label>
+      <select id="contactImageSelector" class="md-select"
+        on-change="onContactImageTypeSelected_">
+        <template is="dom-repeat" items="[[imageList_]]">
+          <option  selected="[[isEqual_(item, notification.contactImage)]]">
+            [[getImageTypeName_(item)]]
+          </option>
+        </template>
+      </select>
+    </div>
+  </div>
+</div>
+
diff --git a/chrome/browser/resources/chromeos/multidevice_internals/notification_form.js b/chrome/browser/resources/chromeos/multidevice_internals/notification_form.js
new file mode 100644
index 0000000..e5a40e6
--- /dev/null
+++ b/chrome/browser/resources/chromeos/multidevice_internals/notification_form.js
@@ -0,0 +1,255 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'chrome://resources/cr_elements/shared_style_css.m.js';
+import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
+import 'chrome://resources/cr_elements/cr_input/cr_input.m.js';
+import './shared_style.js';
+
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {MultidevicePhoneHubBrowserProxy} from './multidevice_phonehub_browser_proxy.js';
+import {ImageType, imageTypeToStringMap, Importance, importanceToString, Notification} from './types.js';
+
+Polymer({
+  is: 'notification-form',
+
+  _template: html`{__html_template__}`,
+
+  properties: {
+    /** @type{!Notification} */
+    notification: Object,
+
+    /** @private */
+    isNotificationDataValid_: {
+      type: Boolean,
+      computed: 'computeIsNotificationDataValid_(notification.*)',
+    },
+
+    /** @private */
+    isSent_: {
+      type: Boolean,
+      computed: 'computeIsSent_(notification.*)',
+      reflectToAttribute: true,
+    },
+
+    /** @private */
+    isValidId_: {
+      type: Boolean,
+      computed: 'computeIsValidId_(forbiddenIds)',
+    },
+
+    /** @private */
+    isValidInlineReplyId_: {
+      type: Boolean,
+      computed: 'computeIsValidInlineReplyId_(forbiddenInlineReplyIds)',
+    },
+
+    /** @type{!Array<number>} */
+    forbiddenIds: {
+      type: Array,
+      value: [],
+    },
+
+    /** @type{!Array<number>} */
+    forbiddenInlineReplyIds: {
+      type: Array,
+      value: [],
+    },
+
+    /** @private */
+    imageList_: {
+      type: Array,
+      value: () => {
+        return [
+          ImageType.NONE,
+          ImageType.PINK,
+          ImageType.RED,
+          ImageType.GREEN,
+          ImageType.BLUE,
+          ImageType.YELLOW,
+        ];
+      },
+      readonly: true,
+    },
+
+    /** @private */
+    importanceList_: {
+      type: Array,
+      value: () => {
+        return [
+          Importance.UNSPECIFIED,
+          Importance.NONE,
+          Importance.MIN,
+          Importance.LOW,
+          Importance.DEFAULT,
+          Importance.HIGH,
+        ];
+      },
+      readonly: true,
+    },
+
+    /** @private */
+    updateNotificationText_: {
+      type: String,
+      value: 'Update this notification',
+    },
+  },
+
+  /** @private{?MultidevicePhoneHubBrowserProxy}*/
+  browserProxy_: null,
+
+  /** @override */
+  created() {
+    this.browserProxy_ = MultidevicePhoneHubBrowserProxy.getInstance();
+  },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  computeIsValidId_() {
+    return this.notification.sent ||
+        !this.forbiddenIds.includes(Number(this.notification.id));
+  },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  computeIsValidInlineReplyId_() {
+    return this.notification.sent ||
+        !this.forbiddenInlineReplyIds.includes(
+            Number(this.notification.inlineReplyId));
+  },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  computeIsNotificationDataValid_() {
+    // If either the notification ID or inline reply id is invalid,
+    // the notification is invalid.
+    if (!this.isValidId_ || !this.isValidInlineReplyId_) {
+      return false;
+    }
+
+    // Other required fields that need to be formatted correctly.
+    if (!this.notification.appMetadata.visibleAppName ||
+        this.notification.icon === ImageType.NONE ||
+        Number(this.notification.timestamp) < 0) {
+      return false;
+    }
+
+    // At least the title, text content, or shared image must be populated.
+    return !!this.notification.title || !!this.notification.textContent ||
+        this.notification.sharedImage !== ImageType.NONE;
+  },
+
+  /** @private */
+  computeIsSent_() {
+    return this.notification.sent;
+  },
+
+  /** @private */
+  onSetNotification_() {
+    this.browserProxy_.setNotification(this.notification);
+    this.notification.sent = true;
+    this.notifyPath('notification.sent');
+  },
+
+  /** @private */
+  onUpdateNotification_() {
+    this.onSetNotification_();
+    this.updateNotificationText_ = 'Update Sent!';
+    setTimeout(() => {
+      this.updateNotificationText_ = 'Update this notification';
+    }, 1000);
+  },
+
+  /** @private */
+  onRemoveButtonClick_() {
+    this.browserProxy_.removeNotification(this.notification.id);
+    this.fire('remove-notification');
+  },
+
+  /**
+   * @param {ImageType} imageType
+   * @return {String}
+   * @private
+   */
+  getImageTypeName_(imageType) {
+    return imageTypeToStringMap.get(imageType);
+  },
+
+  /**
+   * @param {Importance} importance
+   * @return {String}
+   * @private
+   */
+  getImportanceName_(importance) {
+    return importanceToString.get(importance);
+  },
+
+  /** @private */
+  onInlineReplyIdChanged_() {
+    //<cr-input> does not save value numerically.
+    this.notification.inlineReplyId = Number(this.notification.inlineReplyId);
+    this.notifyPath('notification.inlineReplyId');
+  },
+
+  /** @private */
+  onNotificationIdChanged_() {
+    //<cr-input> does not save value numerically.
+    this.notification.id = Number(this.notification.id);
+    this.notifyPath('notification.id');
+  },
+
+  /** @private */
+  onTimeStampChanged_() {
+    //<cr-input> does not save value numerically.
+    this.notification.timestamp = Number(this.notification.timestamp);
+    this.notifyPath('notification.timestamp');
+  },
+
+  /** @private */
+  onIconImageTypeSelected_() {
+    const select = /** @type {!HTMLSelectElement} */
+        (this.$$('#iconImageTypeSelector'));
+    this.notification.appMetadata.icon = this.imageList_[select.selectedIndex];
+  },
+
+  /** @private */
+  onSharedImageTypeSelected_() {
+    const select = /** @type {!HTMLSelectElement} */
+        (this.$$('#sharedImageTypeSelector'));
+    this.notification.sharedImage = this.imageList_[select.selectedIndex];
+    this.notifyPath('notification.sharedImage');
+  },
+
+  /** @private */
+  onContactImageTypeSelected_() {
+    const select = /** @type {!HTMLSelectElement} */
+        (this.$$('#contactImageSelector'));
+    this.notification.contactImage = this.imageList_[select.selectedIndex];
+    this.notifyPath('notification.contactImage');
+  },
+
+  /** @private */
+  onImportanceSelected_() {
+    const select = /** @type {!HTMLSelectElement} */
+        (this.$$('#importanceSelector'));
+    this.notification.importance = this.importanceList_[select.selectedIndex];
+    this.notifyPath('notification.importance');
+  },
+
+  /**
+   * @param {*} lhs
+   * @param {*} rhs
+   * @return {boolean}
+   * @private
+   */
+  isEqual_(lhs, rhs) {
+    return lhs === rhs;
+  },
+});
diff --git a/chrome/browser/resources/chromeos/multidevice_internals/notification_manager.html b/chrome/browser/resources/chromeos/multidevice_internals/notification_manager.html
new file mode 100644
index 0000000..f500cc0
--- /dev/null
+++ b/chrome/browser/resources/chromeos/multidevice_internals/notification_manager.html
@@ -0,0 +1,35 @@
+<style include="cr-shared-style shared-style">
+  :host {
+    display: flex;
+    flex: 1 0 100%;
+  }
+
+  #listContainer {
+    flex: 3;
+    height: 40vh;
+  }
+</style>
+
+<div class="column">
+  <cr-button on-click="onAddNotificationClick_" class="internals-button">
+    Add Notification
+  </cr-button>
+  <div class="label">
+    <span class="emphasize">Note:</span> A notification should include at least
+    one of Title, Text Content, and Shared Image so that it can be
+    rendered in the UI. When the notification is first sent, the notification
+    ID and Inline Reply ID will not be editable anymore. Sent notifications will
+    have a green background. To update a notification, change the fields and
+    click the Update button. To remove a notification, click the Remove button.
+  </div>
+</div>
+<div class="column" id="listContainer">
+  <template id="notificationList" is="dom-repeat"
+      items="{{notificationList_}}">
+    <notification-form class="notification" notification="{{item}}"
+        forbidden-ids="[[sentNotificationIds_]]"
+        forbidden-inline-reply-ids="[[sentInlineReplyIds_]]"
+        on-remove-notification="onRemoveNotification_">
+    </notification-form>
+  </template>
+</div>
diff --git a/chrome/browser/resources/chromeos/multidevice_internals/notification_manager.js b/chrome/browser/resources/chromeos/multidevice_internals/notification_manager.js
new file mode 100644
index 0000000..2514969
--- /dev/null
+++ b/chrome/browser/resources/chromeos/multidevice_internals/notification_manager.js
@@ -0,0 +1,114 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'chrome://resources/cr_elements/shared_style_css.m.js';
+import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
+import 'chrome://resources/cr_elements/cr_input/cr_input.m.js';
+import './shared_style.js';
+import './notification_form.js';
+
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {ImageType, Importance, Notification} from './types.js';
+
+/**
+ * @param {number} notificationId
+ * @param {number} nextNotificationInlineReplyId
+ * @return {!Notification}
+ */
+function newNotification(notificationId, nextNotificationInlineReplyId) {
+  return {
+    sent: false,
+    id: notificationId,
+    appMetadata: {
+      visibleAppName: 'Fake visible app name',
+      packageName: 'Fake package name',
+      icon: ImageType.RED,
+    },
+    timestamp: Date.now(),
+    importance: Importance.DEFAULT,
+    inlineReplyId: nextNotificationInlineReplyId,
+    title: null,
+    textContent: null,
+    sharedImage: ImageType.NONE,
+    contactImage: ImageType.NONE,
+  };
+}
+
+Polymer({
+  is: 'notification-manager',
+
+  _template: html`{__html_template__}`,
+
+  properties: {
+    /** @private */
+    idLatest_: {
+      type: Number,
+      value: 0,
+    },
+
+    /** @private */
+    inlineReplyIdLatest_: {
+      type: Number,
+      value: 0,
+    },
+
+    /**
+     * @type {!Array<!Notification>}
+     */
+    notificationList_: {
+      type: Array,
+      value: [],
+    },
+
+    /**
+     * @type {!Array<number>}
+     */
+    sentNotificationIds_: {
+      type: Array,
+      computed: 'computeSentNotificationIds_(notificationList_.*)',
+    },
+
+    /**
+     * @type {!Array<number>}
+     */
+    sentInlineReplyIds_: {
+      type: Array,
+      computed: 'computeSentInlineReplyIds_(notificationList_.*)',
+    },
+  },
+
+  /** @private */
+  onAddNotificationClick_() {
+    this.notificationList_.unshift(
+        newNotification(this.idLatest_, this.inlineReplyIdLatest_));
+    this.idLatest_++;
+    this.inlineReplyIdLatest_++;
+    this.$.notificationList.render();
+  },
+
+  /**
+   * @param {!Event} e
+   * @private
+   */
+  onRemoveNotification_(e) {
+    const notificationEl = e.path[0];
+    const notificationIndex =
+        this.$.notificationList.indexForElement(notificationEl);
+    this.notificationList_.splice(notificationIndex, 1);
+    this.$.notificationList.render();
+  },
+
+  /** @return {!Array<number>} */
+  computeSentNotificationIds_() {
+    return this.notificationList_.filter(item => item.sent)
+        .map(item => item.id);
+  },
+
+  /** @return  {!Array<number>}*/
+  computeSentInlineReplyIds_() {
+    return this.notificationList_.filter(item => item.sent)
+        .map(item => item.inlineReplyId);
+  },
+});
diff --git a/chrome/browser/resources/chromeos/multidevice_internals/phonehub_tab.html b/chrome/browser/resources/chromeos/multidevice_internals/phonehub_tab.html
index 067b541..7aedf6f 100644
--- a/chrome/browser/resources/chromeos/multidevice_internals/phonehub_tab.html
+++ b/chrome/browser/resources/chromeos/multidevice_internals/phonehub_tab.html
@@ -6,7 +6,7 @@
 
   .cr-row {
     display: flex;
-    flex: 0 0 100%;
+    flex: 0 1 100%;
   }
 
   #flagDisabledContainer {
@@ -32,7 +32,9 @@
       <select id="featureStatusList" class="md-select"
           on-change="onFeatureStatusSelected_">
         <template is="dom-repeat" items="[[featureStatusList_]]">
-          <option>[[getFeatureStatusName_(item)]]</option>
+          <option selected="[[isEqual_(item, featureStatus_)]]">
+            [[getFeatureStatusName_(item)]]
+          </option>
         </template>
       </select>
       <div class="cr-padded-text" hidden="[[isFeatureEnabledAndConnected_]]">
@@ -52,6 +54,9 @@
       <div class="cr-row">
         <browser-tabs-model-form></browser-tabs-model-form>
       </div>
+      <div class="cr-row">
+        <notification-manager></notification-manager>
+      </div>
     </template>
   </template>
 </template>
diff --git a/chrome/browser/resources/chromeos/multidevice_internals/phonehub_tab.js b/chrome/browser/resources/chromeos/multidevice_internals/phonehub_tab.js
index b13e519..af341e9 100644
--- a/chrome/browser/resources/chromeos/multidevice_internals/phonehub_tab.js
+++ b/chrome/browser/resources/chromeos/multidevice_internals/phonehub_tab.js
@@ -10,6 +10,7 @@
 import './i18n_setup.js';
 import './phone_name_form.js';
 import './phone_status_model_form.js';
+import './notification_manager.js';
 import './shared_style.js';
 
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
@@ -82,7 +83,7 @@
     /** @private {!FeatureStatus} */
     featureStatus_: {
       type: Number,
-      value: FeatureStatus.NOT_ELIGIBLE_FOR_FEATURE,
+      value: FeatureStatus.ENABLED_AND_CONNECTED,
     },
 
     /** @private */
@@ -161,4 +162,14 @@
   onPhoneHubFlagButtonClick_() {
     window.open('chrome://flags/#enable-phone-hub');
   },
+
+  /**
+   * @param {*} lhs
+   * @param {*} rhs
+   * @return {boolean}
+   * @private
+   */
+  isEqual_(lhs, rhs) {
+    return lhs === rhs;
+  },
 });
diff --git a/chrome/browser/resources/chromeos/multidevice_internals/shared_style.html b/chrome/browser/resources/chromeos/multidevice_internals/shared_style.html
index 4974ced..19a2d715 100644
--- a/chrome/browser/resources/chromeos/multidevice_internals/shared_style.html
+++ b/chrome/browser/resources/chromeos/multidevice_internals/shared_style.html
@@ -13,6 +13,11 @@
       margin: 5px;
     }
 
+    .internals-button[disabled] {
+      background-color: LightGray;
+      color: gray;
+    }
+
     .label {
       width: 100%;
     }
diff --git a/chrome/browser/resources/chromeos/multidevice_internals/types.js b/chrome/browser/resources/chromeos/multidevice_internals/types.js
index 5f77dfa..535c945 100644
--- a/chrome/browser/resources/chromeos/multidevice_internals/types.js
+++ b/chrome/browser/resources/chromeos/multidevice_internals/types.js
@@ -88,19 +88,34 @@
 };
 
 /**
- * Numerical values should not be changed because they must stay in sync with
- * FaviconType in chromeos/components/phonehub/phone_status_model.cc.
+ * With the exception of NONE, numerical values should not be changed because
+ * they must stay in sync with ImageType in
+ * chromeos/multidevice_internals/multidevice_internals_phone_hub_handler.cc.
  * @enum{number}
  */
-export const FaviconType = {
-  PINK: 0,
-  RED: 1,
-  GREEN: 2,
-  BLUE: 3,
-  YELLOW: 4,
+export const ImageType = {
+  NONE: 0,
+  PINK: 1,
+  RED: 2,
+  GREEN: 3,
+  BLUE: 4,
+  YELLOW: 5,
 };
 
 /**
+ * Maps a ImageType to its title label in the dropdown.
+ * @type {!Map<ImageType, String>}
+ */
+export const imageTypeToStringMap = new Map([
+  [ImageType.NONE, 'None'],
+  [ImageType.PINK, 'Pink'],
+  [ImageType.RED, 'Red'],
+  [ImageType.GREEN, 'Green'],
+  [ImageType.BLUE, 'Blue'],
+  [ImageType.YELLOW, 'Yellow'],
+]);
+
+/**
  * @typedef {{
  *   mobileStatus: !MobileStatus,
  *   signalStrength: !SignalStrength,
@@ -117,7 +132,7 @@
  *   url: string,
  *   title: string,
  *   lastAccessedTimeStamp: number,
- *   favicon: !FaviconType,
+ *   favicon: !ImageType,
  * }}
  */
 export let BrowserTabsMetadataModel;
@@ -130,3 +145,57 @@
  * }}
  */
 export let BrowserTabsModel;
+
+/**
+ * Numerical values should not be changed because they must stay in sync with
+ * Importance in chromeos/components/phonehub/notification.h.
+ * @enum{number}
+ */
+export const Importance = {
+  UNSPECIFIED: 0,
+  NONE: 1,
+  MIN: 2,
+  LOW: 3,
+  DEFAULT: 4,
+  HIGH: 5,
+};
+
+/**
+ * Maps an Importance to its title label in the dropdown.
+ * @type {!Map<Importance, String>}
+ */
+export const importanceToString = new Map([
+  [Importance.UNSPECIFIED, 'Unspecified'],
+  [Importance.NONE, 'None'],
+  [Importance.MIN, 'Min'],
+  [Importance.LOW, 'Low'],
+  [Importance.DEFAULT, 'Default'],
+  [Importance.HIGH, 'High'],
+]);
+
+/**
+ * @typedef {{
+ *   visibleAppName: string,
+ *   packageName: string,
+ *   icon: !ImageType,
+ * }}
+ */
+export let AppMetadata;
+
+/**
+ * With the exception of the sent property, values match with Notifications in
+ * chromeos/components/phonehub/notification.h
+ * @typedef {{
+ *   sent: boolean,
+ *   id: number,
+ *   appMetadata: !AppMetadata,
+ *   timestamp: number,
+ *   importance: !Importance,
+ *   inlineReplyId: number,
+ *   title: ?string,
+ *   textContent: ?string,
+ *   sharedImage: !ImageType,
+ *   contactImage: !ImageType,
+ * }}
+ */
+export let Notification;
diff --git a/chrome/browser/resources/extensions/BUILD.gn b/chrome/browser/resources/extensions/BUILD.gn
index c7563df..b68df10 100644
--- a/chrome/browser/resources/extensions/BUILD.gn
+++ b/chrome/browser/resources/extensions/BUILD.gn
@@ -4,85 +4,51 @@
 
 import("//chrome/common/features.gni")
 import("//third_party/closure_compiler/compile_js.gni")
-import("//tools/grit/preprocess_grit.gni")
+import("//tools/grit/grit_rule.gni")
 import("//tools/polymer/html_to_js.gni")
 import("../optimize_webui.gni")
 
 if (optimize_webui) {
-  preprocess_folder = "preprocessed"
+  extensions_pak_file = "extensions_resources.pak"
+  unpak_folder = "extensions_resources.unpak"
 
   optimize_webui("build") {
     host = "extensions"
-    input = rebase_path("$target_gen_dir/$preprocess_folder", root_build_dir)
+    input = rebase_path("$target_gen_dir/$unpak_folder", root_build_dir)
     js_out_files = [ "extensions.rollup.js" ]
     js_module_in_files = [ "extensions.js" ]
 
     deps = [
-      ":preprocess",
-      ":preprocess_generated",
+      ":unpak",
       "../../../../ui/webui/resources:preprocess",
     ]
     excludes = [ "chrome://resources/js/cr.m.js" ]
   }
 
-  preprocess_grit("preprocess") {
-    in_folder = "./"
-    out_folder = "$target_gen_dir/$preprocess_folder"
-    in_files = [
-      "drag_and_drop_handler.js",
-      "extensions.js",
-      "item_behavior.js",
-      "item_util.js",
-      "keyboard_shortcut_delegate.js",
-      "navigation_helper.js",
-      "service.js",
-      "shortcut_util.js",
-    ]
+  unpak("unpak") {
+    pak_file = extensions_pak_file
+    out_folder = unpak_folder
 
-    if (is_chromeos) {
-      in_files += [ "kiosk_browser_proxy.js" ]
-    }
+    deps = [ ":flattened_resources" ]
   }
 
-  preprocess_grit("preprocess_generated") {
-    deps = [ ":web_components" ]
-    in_folder = target_gen_dir
-    out_folder = "$target_gen_dir/$preprocess_folder"
-    in_files = [
-      "checkup.js",
-      "code_section.js",
-      "activity_log/activity_log_history_item.js",
-      "activity_log/activity_log_history.js",
-      "activity_log/activity_log.js",
-      "activity_log/activity_log_stream_item.js",
-      "activity_log/activity_log_stream.js",
-      "detail_view.js",
-      "drop_overlay.js",
-      "error_page.js",
-      "host_permissions_toggle_list.js",
-      "icons.js",
-      "install_warnings_dialog.js",
-      "item.js",
-      "item_list.js",
-      "keyboard_shortcuts.js",
-      "load_error.js",
-      "manager.js",
-      "options_dialog.js",
-      "pack_dialog_alert.js",
-      "pack_dialog.js",
-      "runtime_host_permissions.js",
-      "runtime_hosts_dialog.js",
-      "shared_style.js",
-      "shared_vars.js",
-      "shortcut_input.js",
-      "sidebar.js",
-      "toggle_row.js",
-      "toolbar.js",
+  grit("flattened_resources") {
+    source = "extensions_resources.grd"
+
+    grit_flags = [
+      "-E",
+      "root_gen_dir=" + rebase_path(root_gen_dir, root_build_dir),
     ]
 
-    if (is_chromeos) {
-      in_files += [ "kiosk_dialog.js" ]
-    }
+    deps = [ ":web_components" ]
+    defines = chrome_grit_defines
+    outputs = [
+      "grit/extensions_resources.h",
+      "grit/extensions_resources_map.cc",
+      "grit/extensions_resources_map.h",
+      extensions_pak_file,
+    ]
+    output_dir = "$root_gen_dir/chrome/browser/resources/extensions"
   }
 }
 
diff --git a/chrome/browser/resources/extensions/extensions_resources.grd b/chrome/browser/resources/extensions/extensions_resources.grd
index d09f1912..f149dd7 100644
--- a/chrome/browser/resources/extensions/extensions_resources.grd
+++ b/chrome/browser/resources/extensions/extensions_resources.grd
@@ -14,133 +14,144 @@
     <includes>
       <include name="IDR_EXTENSIONS_CODE_SECTION_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/code_section.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/activity_log/activity_log.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_HISTORY_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/activity_log/activity_log_history.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_HISTORY_ITEM_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/activity_log/activity_log_history_item.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_STREAM_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/activity_log/activity_log_stream.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_STREAM_ITEM_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/activity_log/activity_log_stream_item.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_CHECKUP_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/checkup.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_DETAIL_VIEW_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/detail_view.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_DROP_OVERLAY_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/drop_overlay.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_ERROR_PAGE_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/error_page.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_KEYBOARD_SHORTCUTS_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/keyboard_shortcuts.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
     <if expr="chromeos">
       <include name="IDR_EXTENSIONS_KIOSK_DIALOG_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/kiosk_dialog.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
     </if>
       <include name="IDR_EXTENSIONS_MANAGER_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/manager.js"
-               preprocess="true" use_base_dir="false" type="BINDATA" />
+               preprocess="true" use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_ICONS_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/icons.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_INSTALL_WARNINGS_DIALOG_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/install_warnings_dialog.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_ITEM_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/item.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_ITEM_LIST_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/item_list.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_LOAD_ERROR_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/load_error.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_HOST_PERMISSIONS_TOGGLE_LIST_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/host_permissions_toggle_list.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_OPTIONS_DIALOG_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/options_dialog.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_PACK_DIALOG_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/pack_dialog.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_PACK_DIALOG_ALERT_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/pack_dialog_alert.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_RUNTIME_HOST_PERMISSIONS_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/runtime_host_permissions.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_RUNTIME_HOSTS_DIALOG_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/runtime_hosts_dialog.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_SHARED_STYLE_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/shared_style.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_SHARED_VARS_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/shared_vars.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_SHORTCUT_INPUT_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/shortcut_input.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_SIDEBAR_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/sidebar.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_TOGGLE_ROW_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/toggle_row.js"
-               use_base_dir="false" type="BINDATA" />
+               use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_TOOLBAR_JS"
                file="${root_gen_dir}/chrome/browser/resources/extensions/toolbar.js"
-               preprocess="true" use_base_dir="false" type="BINDATA" />
+               preprocess="true" use_base_dir="false" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_CHECKUP_IMAGE"
-               file="checkup_image.svg" type="BINDATA" />
+               file="checkup_image.svg" compress="false" type="BINDATA" />
       <include name="IDR_EXTENSIONS_CHECKUP_IMAGE_DARK"
-               file="checkup_image_dark.svg" type="BINDATA" />
+               file="checkup_image_dark.svg" compress="false" type="BINDATA" />
     </includes>
     <structures>
       <structure name="IDR_EXTENSIONS_ITEM_BEHAVIOR_JS"
                  file="item_behavior.js"
+                 compress="false"
                  type="chrome_html" />
       <structure name="IDR_EXTENSIONS_EXTENSIONS_HTML"
                  file="extensions.html"
+                 compress="false"
                  type="chrome_html" />
       <structure name="IDR_EXTENSIONS_DRAG_AND_DROP_HANDLER_JS"
                  file="drag_and_drop_handler.js"
+                 compress="false"
                  type="chrome_html" />
       <structure name="IDR_EXTENSIONS_EXTENSIONS_JS"
                  file="extensions.js"
+                 preprocess="true"
+                 compress="false"
                  type="chrome_html" />
       <structure name="IDR_EXTENSIONS_KEYBOARD_SHORTCUT_DELEGATE_JS"
                  file="keyboard_shortcut_delegate.js"
+                 compress="false"
                  type="chrome_html" />
     <if expr="chromeos">
       <structure name="IDR_EXTENSIONS_KIOSK_BROWSER_PROXY_JS"
                  file="kiosk_browser_proxy.js"
+                 compress="false"
                  type="chrome_html" />
     </if>
       <structure name="IDR_EXTENSIONS_ITEM_UTIL_JS"
                  file="item_util.js"
+                 compress="false"
                  type="chrome_html" />
       <structure name="IDR_EXTENSIONS_NAVIGATION_HELPER_JS"
                  file="navigation_helper.js"
+                 compress="false"
                  type="chrome_html" />
       <structure name="IDR_EXTENSIONS_SERVICE_JS"
                  file="service.js"
+                 compress="false"
                  type="chrome_html" />
       <structure name="IDR_EXTENSIONS_SHORTCUT_UTIL_JS"
                  file="shortcut_util.js"
+                 compress="false"
                  type="chrome_html" />
     </structures>
   </release>
diff --git a/chrome/browser/safe_browsing/BUILD.gn b/chrome/browser/safe_browsing/BUILD.gn
index 7f54cac..f4491f0 100644
--- a/chrome/browser/safe_browsing/BUILD.gn
+++ b/chrome/browser/safe_browsing/BUILD.gn
@@ -15,6 +15,8 @@
     "url_checker_delegate_impl.h",
   ]
 
+  public_deps = []
+
   deps = [
     "//chrome/app:generated_resources",
     "//chrome/common",
@@ -241,10 +243,12 @@
         "signature_evaluator_mac.h",
         "signature_evaluator_mac.mm",
       ]
-      deps += [
-        ":advanced_protection",
+      public_deps += [
         ":chrome_enterprise_url_lookup_service",
         ":chrome_enterprise_url_lookup_service_factory",
+      ]
+      deps += [
+        ":advanced_protection",
         "//chrome/common/safe_browsing:archive_analyzer_results",
         "//chrome/common/safe_browsing:binary_feature_extractor",
         "//chrome/common/safe_browsing:disk_image_type_sniffer_mac",
@@ -280,37 +284,43 @@
   }
 }
 
-source_set("chrome_enterprise_url_lookup_service_factory") {
-  sources = [
-    "chrome_enterprise_url_lookup_service_factory.cc",
-    "chrome_enterprise_url_lookup_service_factory.h",
-  ]
+if (safe_browsing_mode == 1) {
+  source_set("chrome_enterprise_url_lookup_service_factory") {
+    visibility = [ ":*" ]
 
-  deps = [
-    ":chrome_enterprise_url_lookup_service",
-    ":verdict_cache_manager_factory",
-    "//chrome/common",
-    "//components/keyed_service/content",
-    "//content/public/browser",
-  ]
-}
+    sources = [
+      "chrome_enterprise_url_lookup_service_factory.cc",
+      "chrome_enterprise_url_lookup_service_factory.h",
+    ]
 
-source_set("chrome_enterprise_url_lookup_service") {
-  sources = [
-    "chrome_enterprise_url_lookup_service.cc",
-    "chrome_enterprise_url_lookup_service.h",
-  ]
+    deps = [
+      ":chrome_enterprise_url_lookup_service",
+      ":verdict_cache_manager_factory",
+      "//chrome/common",
+      "//components/keyed_service/content",
+      "//content/public/browser",
+    ]
+  }
 
-  deps = [
-    "//components/prefs",
-    "//components/safe_browsing/core:csd_proto",
-    "//components/safe_browsing/core:realtimeapi_proto",
-    "//components/safe_browsing/core:verdict_cache_manager",
-    "//components/safe_browsing/core/realtime:policy_engine",
-    "//components/safe_browsing/core/realtime:url_lookup_service_base",
-    "//components/sync",
-    "//services/network/public/cpp:cpp",
-  ]
+  source_set("chrome_enterprise_url_lookup_service") {
+    visibility = [ ":*" ]
+
+    sources = [
+      "chrome_enterprise_url_lookup_service.cc",
+      "chrome_enterprise_url_lookup_service.h",
+    ]
+
+    deps = [
+      "//components/prefs",
+      "//components/safe_browsing/core:csd_proto",
+      "//components/safe_browsing/core:realtimeapi_proto",
+      "//components/safe_browsing/core:verdict_cache_manager",
+      "//components/safe_browsing/core/realtime:policy_engine",
+      "//components/safe_browsing/core/realtime:url_lookup_service_base",
+      "//components/sync",
+      "//services/network/public/cpp:cpp",
+    ]
+  }
 }
 
 source_set("url_lookup_service_factory") {
diff --git a/chrome/browser/search_engines/template_url_service_factory.cc b/chrome/browser/search_engines/template_url_service_factory.cc
index 7cd204e..b3f207c 100644
--- a/chrome/browser/search_engines/template_url_service_factory.cc
+++ b/chrome/browser/search_engines/template_url_service_factory.cc
@@ -24,7 +24,7 @@
 #include "rlz/buildflags/buildflags.h"
 
 #if BUILDFLAG(ENABLE_RLZ)
-#include "components/rlz/rlz_tracker.h"
+#include "components/rlz/rlz_tracker.h"  // nogncheck crbug.com/1125897
 #endif
 
 // static
diff --git a/chrome/browser/search_engines/ui_thread_search_terms_data.cc b/chrome/browser/search_engines/ui_thread_search_terms_data.cc
index 5553566..bcf5c7c2 100644
--- a/chrome/browser/search_engines/ui_thread_search_terms_data.cc
+++ b/chrome/browser/search_engines/ui_thread_search_terms_data.cc
@@ -20,7 +20,7 @@
 #include "url/gurl.h"
 
 #if BUILDFLAG(ENABLE_RLZ)
-#include "components/rlz/rlz_tracker.h"
+#include "components/rlz/rlz_tracker.h"  // nogncheck crbug.com/1125897
 #endif
 
 using content::BrowserThread;
diff --git a/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc b/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc
index ffdb052..ca81ec5 100644
--- a/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc
+++ b/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc
@@ -40,7 +40,7 @@
 
 #if !defined(OS_ANDROID)
 #include "base/files/memory_mapped_file.h"
-#include "third_party/hunspell/google/bdict.h"
+#include "third_party/hunspell/google/bdict.h"  // nogncheck crbug.com/1125897
 #endif
 
 using content::BrowserThread;
diff --git a/chrome/browser/storage/storage_notification_service_impl.cc b/chrome/browser/storage/storage_notification_service_impl.cc
index c5255b2..f8b38745 100644
--- a/chrome/browser/storage/storage_notification_service_impl.cc
+++ b/chrome/browser/storage/storage_notification_service_impl.cc
@@ -38,8 +38,9 @@
 
 void StorageNotificationServiceImpl::MaybeShowStoragePressureNotification(
     const url::Origin origin) {
-  if (base::TimeTicks::Now() - disk_pressure_notification_last_sent_at_ <
-      GetThrottlingInterval()) {
+  if (!disk_pressure_notification_last_sent_at_.is_null() &&
+      base::TimeTicks::Now() - disk_pressure_notification_last_sent_at_ <
+          GetThrottlingInterval()) {
     return;
   }
 
diff --git a/chrome/browser/task_manager/providers/browser_process_task.cc b/chrome/browser/task_manager/providers/browser_process_task.cc
index b4d1229..630d190 100644
--- a/chrome/browser/task_manager/providers/browser_process_task.cc
+++ b/chrome/browser/task_manager/providers/browser_process_task.cc
@@ -7,7 +7,7 @@
 #include "chrome/browser/task_manager/task_manager_observer.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
-#include "third_party/sqlite/sqlite3.h"
+#include "third_party/sqlite/sqlite3.h"  // nogncheck crbug.com/1126800
 #include "ui/base/l10n/l10n_util.h"
 
 namespace task_manager {
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 3768988..90579987 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1541,6 +1541,7 @@
       "//components/network_session_configurator/common",
       "//components/page_load_metrics/browser",
       "//components/performance_manager:site_data_proto",
+      "//components/printing/browser",
       "//components/profile_metrics",
       "//components/safety_check",
       "//components/search_provider_logos",
@@ -1747,6 +1748,8 @@
       "app_list/search/drive_quick_access_result.h",
       "app_list/search/file_chip_result.cc",
       "app_list/search/file_chip_result.h",
+      "app_list/search/files/drive_zero_state_provider.cc",
+      "app_list/search/files/drive_zero_state_provider.h",
       "app_list/search/files/file_result.cc",
       "app_list/search/files/file_result.h",
       "app_list/search/launcher_search/launcher_search_icon_image_loader.cc",
diff --git a/chrome/browser/ui/app_list/search/files/drive_zero_state_provider.cc b/chrome/browser/ui/app_list/search/files/drive_zero_state_provider.cc
new file mode 100644
index 0000000..a85dd90
--- /dev/null
+++ b/chrome/browser/ui/app_list/search/files/drive_zero_state_provider.cc
@@ -0,0 +1,73 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/app_list/search/files/drive_zero_state_provider.h"
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+
+#include "ash/public/cpp/app_list/app_list_features.h"
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "base/task_runner_util.h"
+#include "chrome/browser/chromeos/drive/drive_integration_service.h"
+#include "chrome/browser/ui/app_list/search/drive_quick_access_chip_result.h"
+#include "chrome/browser/ui/app_list/search/drive_quick_access_result.h"
+#include "chrome/browser/ui/app_list/search/search_controller.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace app_list {
+
+DriveZeroStateProvider::DriveZeroStateProvider(
+    Profile* profile,
+    SearchController* search_controller)
+    : profile_(profile),
+      drive_service_(
+          drive::DriveIntegrationServiceFactory::GetForProfile(profile)),
+      suggested_files_enabled_(app_list_features::IsSuggestedFilesEnabled()) {
+  DCHECK(profile_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  task_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
+      {base::TaskPriority::BEST_EFFORT, base::MayBlock(),
+       base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
+}
+
+DriveZeroStateProvider::~DriveZeroStateProvider() = default;
+
+void DriveZeroStateProvider::OnFileSystemMounted() {
+  if (have_warmed_up_cache_)
+    return;
+  have_warmed_up_cache_ = true;
+
+  // TODO(crbug.com/1034842): Query ItemSuggest. We may need to call
+  // SearchController::Start afterwards, or preferably could just publish the
+  // results for this search provider.
+}
+
+ash::AppListSearchResultType DriveZeroStateProvider::ResultType() {
+  return ash::AppListSearchResultType::kDriveQuickAccess;
+}
+
+void DriveZeroStateProvider::Start(const base::string16& query) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  ClearResultsSilently();
+  if (!query.empty())
+    return;
+
+  // TODO(crbug.com/1034842): Convert results cache into search results.
+}
+
+void DriveZeroStateProvider::AppListShown() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  // TODO(crbug.com/1034842): Query ItemSuggest, consider rate-limiting.
+}
+
+}  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/files/drive_zero_state_provider.h b/chrome/browser/ui/app_list/search/files/drive_zero_state_provider.h
new file mode 100644
index 0000000..56437a9
--- /dev/null
+++ b/chrome/browser/ui/app_list/search/files/drive_zero_state_provider.h
@@ -0,0 +1,68 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_APP_LIST_SEARCH_FILES_DRIVE_ZERO_STATE_PROVIDER_H_
+#define CHROME_BROWSER_UI_APP_LIST_SEARCH_FILES_DRIVE_ZERO_STATE_PROVIDER_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "base/sequenced_task_runner.h"
+#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "chrome/browser/chromeos/drive/drive_integration_service.h"
+#include "chrome/browser/chromeos/file_manager/file_tasks_notifier.h"
+#include "chrome/browser/ui/app_list/search/search_provider.h"
+
+class Profile;
+
+namespace app_list {
+
+class SearchController;
+
+class DriveZeroStateProvider : public SearchProvider,
+                               public drive::DriveIntegrationServiceObserver {
+ public:
+  DriveZeroStateProvider(Profile* profile, SearchController* search_controller);
+  ~DriveZeroStateProvider() override;
+
+  DriveZeroStateProvider(const DriveZeroStateProvider&) = delete;
+  DriveZeroStateProvider& operator=(const DriveZeroStateProvider&) = delete;
+
+  // SearchProvider:
+  void Start(const base::string16& query) override;
+  void AppListShown() override;
+  ash::AppListSearchResultType ResultType() override;
+
+  // drive::DriveIntegrationServiceObserver:
+  void OnFileSystemMounted() override;
+
+ private:
+  Profile* const profile_;
+  drive::DriveIntegrationService* const drive_service_;
+
+  // Whether the suggested files experiment is enabled.
+  const bool suggested_files_enabled_;
+
+  // Whether we have sent at least one request to ItemSuggest to warm up the
+  // results cache.
+  bool have_warmed_up_cache_ = false;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  scoped_refptr<base::SequencedTaskRunner> task_runner_;
+  // Factory for general use.
+  base::WeakPtrFactory<DriveZeroStateProvider> weak_ptr_factory_{this};
+  // Factory only for weak pointers for ItemSuggest API calls. Using two
+  // factories allows in-flight API calls to be cancelled independently of other
+  // tasks by invalidating only this factory's weak pointers.
+  base::WeakPtrFactory<DriveZeroStateProvider> item_suggest_weak_ptr_factory_{
+      this};
+};
+
+}  // namespace app_list
+
+#endif  // CHROME_BROWSER_UI_APP_LIST_SEARCH_FILES_DRIVE_ZERO_STATE_PROVIDER_H_
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_client_impl.cc b/chrome/browser/ui/ash/holding_space/holding_space_client_impl.cc
index c7ae485..94fe74d4 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_client_impl.cc
+++ b/chrome/browser/ui/ash/holding_space/holding_space_client_impl.cc
@@ -90,11 +90,12 @@
 }
 
 void HoldingSpaceClientImpl::UnpinItem(const HoldingSpaceItem& item) {
-  DCHECK_EQ(item.type(), HoldingSpaceItem::Type::kPinnedFile);
   const storage::FileSystemURL& file_system_url =
       file_manager::util::GetFileSystemContextForExtensionId(
           profile_, file_manager::kFileManagerAppId)
           ->CrackURL(item.file_system_url());
+  DCHECK(GetHoldingSpaceKeyedService(profile_)->ContainsPinnedFile(
+      file_system_url));
   GetHoldingSpaceKeyedService(profile_)->RemovePinnedFile(file_system_url);
 }
 
diff --git a/chrome/browser/ui/find_bar/find_backend_unittest.cc b/chrome/browser/ui/find_bar/find_backend_unittest.cc
index 94dc660..d9ba183 100644
--- a/chrome/browser/ui/find_bar/find_backend_unittest.cc
+++ b/chrome/browser/ui/find_bar/find_backend_unittest.cc
@@ -64,7 +64,7 @@
   // Start searching in the first WebContents.
   find_tab_helper->StartFinding(search_term1, true /* forward_direction */,
                                 false /* case_sensitive */,
-                                true /* find_next_if_selection_matches */);
+                                true /* find_match */);
 
   // Pre-populate string should always match between the two, but find_text
   // should not.
@@ -76,7 +76,7 @@
   // Now search in the other WebContents.
   find_tab_helper2->StartFinding(search_term2, true /* forward_direction */,
                                  false /* case_sensitive */,
-                                 true /* find_next_if_selection_matches */);
+                                 true /* find_match */);
 
   // Again, pre-populate string should always match between the two, but
   // find_text should not.
@@ -88,7 +88,7 @@
   // Search again in the first WebContents
   find_tab_helper->StartFinding(search_term3, true /* forward_direction */,
                                 false /* case_sensitive */,
-                                true /* find_next_if_selection_matches */);
+                                true /* find_match */);
 
   // The fallback search term for the first WebContents will be the original
   // search.
diff --git a/chrome/browser/ui/find_bar/find_bar_controller.cc b/chrome/browser/ui/find_bar/find_bar_controller.cc
index ed1de9e..dc255e8 100644
--- a/chrome/browser/ui/find_bar/find_bar_controller.cc
+++ b/chrome/browser/ui/find_bar/find_bar_controller.cc
@@ -51,35 +51,31 @@
   find_bar_->SetFocusAndSelection();
 
   if (find_next) {
-    base::string16 find_text;
-
-#if defined(OS_MAC)
-    // For macOS, we always want to search for the current contents of the
-    // find bar on OS X, rather than the behavior we'd get with empty
-    // find_text (see FindBarState::GetSearchPrepopulateText).
-    find_text = find_bar_->GetFindText();
-#endif
-
-    find_tab_helper->StartFinding(find_text, forward_direction,
+    find_tab_helper->StartFinding(find_bar_->GetFindText(), forward_direction,
                                   false /* case_sensitive */,
-                                  true /* find_next_if_selection_matches */);
+                                  true /* find_match */);
     return;
   }
 
-  if (!has_user_modified_text_) {
-    base::string16 selected_text = GetSelectedText();
-    auto selected_length = selected_text.length();
-    if (selected_length > 0 && selected_length <= 250) {
-      find_bar_->SetFindTextAndSelectedRange(
-          selected_text, gfx::Range(0, selected_text.length()));
-      // Start a new find based on the selection.
-      // |find_next_if_selection_matches| is set to false so that the initial
-      // result will be the selection itself.
-      find_tab_helper->StartFinding(selected_text, true /* forward_direction */,
-                                    false /* case_sensitive */,
-                                    false /* find_next_if_selection_matches */);
-    }
+  if (has_user_modified_text_)
+    return;
+
+  base::string16 selected_text = GetSelectedText();
+  auto selected_length = selected_text.length();
+  if (selected_length > 0 && selected_length <= 250) {
+    find_bar_->SetFindTextAndSelectedRange(
+        selected_text, gfx::Range(0, selected_text.length()));
   }
+  // Since this isn't a find-next operation, we don't want to jump to any
+  // matches. Doing so could cause the page to scroll when a user is just
+  // trying to pull up the find bar — they might not even want to search for
+  // whatever is prefilled (e.g. the selected text or the global pasteboard).
+  // So we set |find_match| to false, which will set up match counts and
+  // highlighting, but not jump to any matches.
+  find_tab_helper->StartFinding(find_bar_->GetFindText(),
+                                true /* forward_direction */,
+                                false /* case_sensitive */,
+                                false /* find_match */);
 }
 
 void FindBarController::EndFindSession(
@@ -246,7 +242,8 @@
 void FindBarController::MaybeSetPrepopulateText() {
   // Having a per-tab find_string is not compatible with a global find
   // pasteboard, so we always have the same find text in all find bars. This is
-  // done through the find pasteboard mechanism, so don't set the text here.
+  // done through the find pasteboard mechanism (see FindBarPlatformHelperMac),
+  // so don't set the text here.
   if (find_bar_->HasGlobalFindPasteboard())
     return;
 
diff --git a/chrome/browser/ui/ui_features.cc b/chrome/browser/ui/ui_features.cc
index 435307a0..a2dd01e4 100644
--- a/chrome/browser/ui/ui_features.cc
+++ b/chrome/browser/ui/ui_features.cc
@@ -63,6 +63,11 @@
 // Enables grouping tabs together in the tab strip. https://crbug.com/905491
 const base::Feature kTabGroups{"TabGroups", base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Automatically create groups for users based on domain.
+// https://crbug.com/1128703
+const base::Feature kTabGroupsAutoCreate{"TabGroupsAutoCreate",
+                                         base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables tab groups to be collapsed and expanded. https://crbug.com/1018230
 const base::Feature kTabGroupsCollapse{"TabGroupsCollapse",
                                        base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/browser/ui/ui_features.h b/chrome/browser/ui/ui_features.h
index 7cb29c7..b87fd36 100644
--- a/chrome/browser/ui/ui_features.h
+++ b/chrome/browser/ui/ui_features.h
@@ -44,6 +44,8 @@
 
 extern const base::Feature kTabGroups;
 
+extern const base::Feature kTabGroupsAutoCreate;
+
 extern const base::Feature kTabGroupsCollapse;
 
 extern const base::Feature kTabGroupsCollapseFreezing;
diff --git a/chrome/browser/ui/views/find_bar_view.cc b/chrome/browser/ui/views/find_bar_view.cc
index 9c0851b..c763a33 100644
--- a/chrome/browser/ui/views/find_bar_view.cc
+++ b/chrome/browser/ui/views/find_bar_view.cc
@@ -344,7 +344,7 @@
             sender->GetID() ==
                 VIEW_ID_FIND_IN_PAGE_NEXT_BUTTON, /* forward_direction */
             false /* case_sensitive */,
-            true /* find_next_if_selection_matches */);
+            true /* find_match */);
       }
       break;
     case VIEW_ID_FIND_IN_PAGE_CLOSE_BUTTON:
@@ -383,7 +383,7 @@
       find_tab_helper->StartFinding(
           find_string, !key_event.IsShiftDown() /* forward_direction */,
           false /* case_sensitive */,
-          true /* find_next_if_selection_matches */);
+          true /* find_match */);
     }
     return true;
   }
@@ -427,7 +427,7 @@
   if (!search_text.empty()) {
     find_tab_helper->StartFinding(search_text, true /* forward_direction */,
                                   false /* case_sensitive */,
-                                  true /* find_next_if_selection_matches */);
+                                  true /* find_match */);
   } else {
     find_tab_helper->StopFinding(find_in_page::SelectionAction::kClear);
     UpdateForResult(find_tab_helper->find_result(), base::string16());
diff --git a/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc b/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc
index 15ea139..4cd64ee 100644
--- a/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc
+++ b/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc
@@ -626,6 +626,8 @@
 
   WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
+  auto* host_view = web_contents->GetRenderWidgetHostView();
+  auto* host = host_view->GetRenderWidgetHost();
 
   WebContentsFocusChangedWatcher watcher(web_contents);
 
@@ -635,16 +637,48 @@
 
   watcher.Wait();
 
-  browser()->GetFindBarController()->Show();
+  auto* find_bar_controller = browser()->GetFindBarController();
+  find_bar_controller->Show();
   EXPECT_TRUE(IsViewFocused(browser(), VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
 
   // Verify the text matches the selection
   EXPECT_EQ(ASCIIToUTF16("text"), GetFindBarText());
   find_in_page::FindNotificationDetails details = WaitForFindResult();
-  // Verify the correct match is highlighted (the one corresponding to the
-  // text that was selected). See http://crbug.com/1043550
-  EXPECT_EQ(2, details.active_match_ordinal());
+  // We don't ever want the page to (potentially) scroll just from opening the
+  // find bar, so the active match should always be 0 at this point.
+  // See http://crbug.com/1043550
+  EXPECT_EQ(0, details.active_match_ordinal());
   EXPECT_EQ(5, details.number_of_matches());
+
+  // Find the next match and verify the correct match is highlighted (the
+  // one after text that was selected).
+  find_bar_controller->Show(true /*find_next*/);
+  details = WaitForFindResult();
+  EXPECT_EQ(3, details.active_match_ordinal());
+  EXPECT_EQ(5, details.number_of_matches());
+
+  // Start a new find without a selection and verify we still get find results.
+  // See https://crbug.com/1124605
+  ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_ESCAPE, false,
+                                              false, false, false));
+  // Wait until the focus settles.
+  content::RunUntilInputProcessed(host);
+
+  // Shift-tab back to the input box, then clear the text (and selection).
+  // Doing it this way in part because there's a bug with non-input-based
+  // selection changes not affecting GetSelectedText().
+  ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_TAB, false,
+                                              true, false, false));
+  ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_DELETE, false,
+                                              false, false, false));
+  content::RunUntilInputProcessed(host);
+  EXPECT_EQ(base::string16(), host_view->GetSelectedText());
+
+  find_bar_controller->Show();
+  details = WaitForFindResult();
+  EXPECT_EQ(0, details.active_match_ordinal());
+  // One less than before because we deleted the text in the input box.
+  EXPECT_EQ(4, details.number_of_matches());
 }
 
 IN_PROC_BROWSER_TEST_F(FindInPageTest, GlobalEscapeClosesFind) {
diff --git a/chrome/browser/ui/views/javascript_tab_modal_dialog_view_views.cc b/chrome/browser/ui/views/javascript_tab_modal_dialog_view_views.cc
index 2fb34f4..58af1cb0 100644
--- a/chrome/browser/ui/views/javascript_tab_modal_dialog_view_views.cc
+++ b/chrome/browser/ui/views/javascript_tab_modal_dialog_view_views.cc
@@ -37,7 +37,7 @@
 }
 
 views::View* JavaScriptTabModalDialogViewViews::GetInitiallyFocusedView() {
-  auto* text_box = message_box_view_->text_box();
+  auto* text_box = message_box_view_->GetVisiblePromptField();
   return text_box ? text_box : views::DialogDelegate::GetInitiallyFocusedView();
 }
 
diff --git a/chrome/browser/ui/views/tab_search/tab_search_bubble_view.cc b/chrome/browser/ui/views/tab_search/tab_search_bubble_view.cc
index cf28639..c14cfa0 100644
--- a/chrome/browser/ui/views/tab_search/tab_search_bubble_view.cc
+++ b/chrome/browser/ui/views/tab_search/tab_search_bubble_view.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/ui/views/tab_search/tab_search_bubble_view.h"
 
 #include "base/metrics/histogram_functions.h"
-#include "base/timer/elapsed_timer.h"
 #include "chrome/browser/ui/webui/tab_search/tab_search_ui.h"
 #include "chrome/common/webui_url_constants.h"
 #include "ui/gfx/geometry/rounded_corners_f.h"
@@ -28,12 +27,7 @@
                    TabSearchBubbleView* parent)
       : WebView(browser_context), parent_(parent) {}
 
-  ~TabSearchWebView() override {
-    if (timer_.has_value()) {
-      UmaHistogramMediumTimes("Tabs.TabSearch.WindowDisplayedDuration",
-                              timer_->Elapsed());
-    }
-  }
+  ~TabSearchWebView() override = default;
 
   // views::WebView:
   void PreferredSizeChanged() override {
@@ -41,44 +35,8 @@
     parent_->OnWebViewSizeChanged();
   }
 
-  void OnWebContentsAttached() override { SetVisible(false); }
-
-  void ResizeDueToAutoResize(content::WebContents* web_contents,
-                             const gfx::Size& new_size) override {
-    // Don't actually do anything with this information until we have been
-    // shown. Size changes will not be honored by lower layers while we are
-    // hidden.
-    if (!GetVisible()) {
-      pending_preferred_size_ = new_size;
-      return;
-    }
-    WebView::ResizeDueToAutoResize(web_contents, new_size);
-  }
-
-  void DocumentOnLoadCompletedInMainFrame() override {
-    GetWidget()->Show();
-    GetWebContents()->Focus();
-
-    // Track window open times from when the bubble is first shown.
-    timer_ = base::ElapsedTimer();
-  }
-
-  void DidStopLoading() override {
-    if (GetVisible())
-      return;
-
-    SetVisible(true);
-    ResizeDueToAutoResize(web_contents(), pending_preferred_size_);
-  }
-
  private:
   TabSearchBubbleView* parent_;
-
-  // What we should set the preferred width to once TabSearch has loaded.
-  gfx::Size pending_preferred_size_;
-
-  // Time the Tab Search window has been open.
-  base::Optional<base::ElapsedTimer> timer_;
 };
 
 }  // namespace
@@ -103,6 +61,18 @@
   SetLayoutManager(std::make_unique<views::FillLayout>());
   web_view_->EnableSizingFromWebContents(kMinSize, kMaxSize);
   web_view_->LoadInitialURL(GURL(chrome::kChromeUITabSearchURL));
+
+  TabSearchUI* const tab_search_ui = static_cast<TabSearchUI*>(
+      web_view_->GetWebContents()->GetWebUI()->GetController());
+  tab_search_ui->AddShowUICallback(
+      base::BindOnce(&TabSearchBubbleView::ShowBubble, base::Unretained(this)));
+}
+
+TabSearchBubbleView::~TabSearchBubbleView() {
+  if (timer_.has_value()) {
+    UmaHistogramMediumTimes("Tabs.TabSearch.WindowDisplayedDuration2",
+                            timer_->Elapsed());
+  }
 }
 
 gfx::Size TabSearchBubbleView::CalculatePreferredSize() const {
@@ -121,3 +91,10 @@
 void TabSearchBubbleView::OnWebViewSizeChanged() {
   SizeToContents();
 }
+
+void TabSearchBubbleView::ShowBubble() {
+  DCHECK(GetWidget());
+  GetWidget()->Show();
+  web_view_->GetWebContents()->Focus();
+  timer_ = base::ElapsedTimer();
+}
diff --git a/chrome/browser/ui/views/tab_search/tab_search_bubble_view.h b/chrome/browser/ui/views/tab_search/tab_search_bubble_view.h
index dfb0f98..44c5edf 100644
--- a/chrome/browser/ui/views/tab_search/tab_search_bubble_view.h
+++ b/chrome/browser/ui/views/tab_search/tab_search_bubble_view.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_VIEWS_TAB_SEARCH_TAB_SEARCH_BUBBLE_VIEW_H_
 
 #include "base/scoped_observer.h"
+#include "base/timer/elapsed_timer.h"
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
 
 namespace views {
@@ -37,7 +38,7 @@
 
   TabSearchBubbleView(content::BrowserContext* browser_context,
                       views::View* anchor_view);
-  ~TabSearchBubbleView() override = default;
+  ~TabSearchBubbleView() override;
 
   // views::BubbleDialogDelegateView:
   gfx::Size CalculatePreferredSize() const override;
@@ -46,8 +47,13 @@
   void OnWebViewSizeChanged();
 
  private:
+  void ShowBubble();
+
   views::WebView* web_view_;
 
+  // Time the Tab Search window has been open.
+  base::Optional<base::ElapsedTimer> timer_;
+
   DISALLOW_COPY_AND_ASSIGN(TabSearchBubbleView);
 };
 
diff --git a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_ui.cc b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_ui.cc
index c5c2c9b..9a46512 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_ui.cc
@@ -49,7 +49,6 @@
       {"errorTitle", IDS_CROSTINI_INSTALLER_ERROR_TITLE},
 
       {"loadTerminaError", IDS_CROSTINI_INSTALLER_LOAD_TERMINA_ERROR},
-      {"startConciergeError", IDS_CROSTINI_INSTALLER_START_CONCIERGE_ERROR},
       {"createDiskImageError", IDS_CROSTINI_INSTALLER_CREATE_DISK_IMAGE_ERROR},
       {"startTerminaVmError", IDS_CROSTINI_INSTALLER_START_TERMINA_VM_ERROR},
       {"startContainerError", IDS_CROSTINI_INSTALLER_START_CONTAINER_ERROR},
@@ -61,7 +60,6 @@
       {"unknownError", IDS_CROSTINI_INSTALLER_UNKNOWN_ERROR},
 
       {"loadTerminaMessage", IDS_CROSTINI_INSTALLER_LOAD_TERMINA_MESSAGE},
-      {"startConciergeMessage", IDS_CROSTINI_INSTALLER_START_CONCIERGE_MESSAGE},
       {"createDiskImageMessage",
        IDS_CROSTINI_INSTALLER_CREATE_DISK_IMAGE_MESSAGE},
       {"startTerminaVmMessage",
diff --git a/chrome/browser/ui/webui/chromeos/multidevice_internals/multidevice_internals_phone_hub_handler.cc b/chrome/browser/ui/webui/chromeos/multidevice_internals/multidevice_internals_phone_hub_handler.cc
index 45ca05fd..3c77e79 100644
--- a/chrome/browser/ui/webui/chromeos/multidevice_internals/multidevice_internals_phone_hub_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/multidevice_internals/multidevice_internals_phone_hub_handler.cc
@@ -19,32 +19,32 @@
 
 namespace {
 
-// Fake Favicon colors used for coloring the fake favicon bitmaps.
-enum class FaviconType {
-  kPink = 0,
-  kRed = 1,
-  kGreen = 2,
-  kBlue = 3,
-  kYellow = 4,
+// Fake image types used for fields that require gfx::Image().
+enum class ImageType {
+  kPink = 1,
+  kRed = 2,
+  kGreen = 3,
+  kBlue = 4,
+  kYellow = 5,
 };
 
-const SkBitmap FaviconNumToBitmap(FaviconType favicon_num) {
+const SkBitmap ImageTypeToBitmap(ImageType image_type_num) {
   SkBitmap bitmap;
   bitmap.allocN32Pixels(16, 16);
-  switch (favicon_num) {
-    case FaviconType::kPink:
+  switch (image_type_num) {
+    case ImageType::kPink:
       bitmap.eraseARGB(0, 255, 192, 203);
       break;
-    case FaviconType::kRed:
+    case ImageType::kRed:
       bitmap.eraseARGB(0, 255, 0, 0);
       break;
-    case FaviconType::kGreen:
+    case ImageType::kGreen:
       bitmap.eraseARGB(0, 0, 255, 0);
       break;
-    case FaviconType::kBlue:
+    case ImageType::kBlue:
       bitmap.eraseARGB(0, 0, 0, 255);
       break;
-    case FaviconType::kYellow:
+    case ImageType::kYellow:
       bitmap.eraseARGB(0, 255, 255, 0);
       break;
     default:
@@ -53,6 +53,24 @@
   return bitmap;
 }
 
+phonehub::Notification::AppMetadata DictToAppMetadata(
+    const base::DictionaryValue* app_metadata_dict) {
+  base::string16 visible_app_name;
+  CHECK(app_metadata_dict->GetString("visibleAppName", &visible_app_name));
+
+  std::string package_name;
+  CHECK(app_metadata_dict->GetString("packageName", &package_name));
+
+  int icon_image_type_as_int;
+  CHECK(app_metadata_dict->GetInteger("icon", &icon_image_type_as_int));
+
+  auto icon_image_type = static_cast<ImageType>(icon_image_type_as_int);
+  gfx::Image icon =
+      gfx::Image::CreateFrom1xBitmap(ImageTypeToBitmap(icon_image_type));
+  return phonehub::Notification::AppMetadata(visible_app_name, package_name,
+                                             icon);
+}
+
 base::Optional<phonehub::BrowserTabsModel::BrowserTabMetadata>
 DictToBrowserTabMetadataModel(
     const base::DictionaryValue* browser_tab_metadata) {
@@ -73,14 +91,15 @@
     return base::nullopt;
   }
 
-  int favicon_type_as_int;
-  if (!browser_tab_metadata->GetInteger("favicon", &favicon_type_as_int)) {
+  int favicon_image_type_as_int;
+  if (!browser_tab_metadata->GetInteger("favicon",
+                                        &favicon_image_type_as_int)) {
     return base::nullopt;
   }
 
-  auto favicon_type = static_cast<FaviconType>(favicon_type_as_int);
+  auto favicon_image_type = static_cast<ImageType>(favicon_image_type_as_int);
   gfx::Image favicon =
-      gfx::Image::CreateFrom1xBitmap(FaviconNumToBitmap(favicon_type));
+      gfx::Image::CreateFrom1xBitmap(ImageTypeToBitmap(favicon_image_type));
   return phonehub::BrowserTabsModel::BrowserTabMetadata(
       GURL(url), title, base::Time::FromJsTime(last_accessed_timestamp),
       favicon);
@@ -121,6 +140,16 @@
       "setBrowserTabs",
       base::BindRepeating(&MultidevicePhoneHubHandler::HandleSetBrowserTabs,
                           base::Unretained(this)));
+
+  web_ui()->RegisterMessageCallback(
+      "setNotification",
+      base::BindRepeating(&MultidevicePhoneHubHandler::HandleSetNotification,
+                          base::Unretained(this)));
+
+  web_ui()->RegisterMessageCallback(
+      "removeNotification",
+      base::BindRepeating(&MultidevicePhoneHubHandler::HandleRemoveNotification,
+                          base::Unretained(this)));
 }
 
 void MultidevicePhoneHubHandler::EnableRealPhoneHubManager() {
@@ -278,5 +307,84 @@
     PA_LOG(VERBOSE) << "Set second most recent browser tab to" << *metadatas[0];
 }
 
+void MultidevicePhoneHubHandler::HandleSetNotification(
+    const base::ListValue* args) {
+  const base::DictionaryValue* notification_data_dict = nullptr;
+  CHECK(args->GetDictionary(0, &notification_data_dict));
+
+  int id;
+  CHECK(notification_data_dict->GetInteger("id", &id));
+
+  const base::DictionaryValue* app_metadata_dict = nullptr;
+  CHECK(
+      notification_data_dict->GetDictionary("appMetadata", &app_metadata_dict));
+  phonehub::Notification::AppMetadata app_metadata =
+      DictToAppMetadata(app_metadata_dict);
+
+  // JavaScript time stamps don't fit in int.
+  double js_timestamp;
+  CHECK(notification_data_dict->GetDouble("timestamp", &js_timestamp));
+  auto timestamp = base::Time::FromJsTime(js_timestamp);
+
+  int importance_as_int;
+  CHECK(notification_data_dict->GetInteger("importance", &importance_as_int));
+  auto importance =
+      static_cast<phonehub::Notification::Importance>(importance_as_int);
+
+  int inline_reply_id;
+  CHECK(notification_data_dict->GetInteger("inlineReplyId", &inline_reply_id));
+
+  base::Optional<base::string16> opt_title;
+  base::string16 title;
+  if (notification_data_dict->GetString("title", &title) && !title.empty()) {
+    opt_title = title;
+  }
+
+  base::Optional<base::string16> opt_text_content;
+  base::string16 text_content;
+  if (notification_data_dict->GetString("textContent", &text_content) &&
+      !text_content.empty()) {
+    opt_text_content = text_content;
+  }
+
+  base::Optional<gfx::Image> opt_shared_image;
+  int shared_image_type_as_int;
+  if (notification_data_dict->GetInteger("sharedImage",
+                                         &shared_image_type_as_int) &&
+      shared_image_type_as_int) {
+    auto shared_image_type = static_cast<ImageType>(shared_image_type_as_int);
+    opt_shared_image =
+        gfx::Image::CreateFrom1xBitmap(ImageTypeToBitmap(shared_image_type));
+  }
+
+  base::Optional<gfx::Image> opt_contact_image;
+  int contact_image_type_as_int;
+  if (notification_data_dict->GetInteger("contactImage",
+                                         &contact_image_type_as_int) &&
+      contact_image_type_as_int) {
+    auto shared_contact_image_type =
+        static_cast<ImageType>(contact_image_type_as_int);
+    opt_contact_image = gfx::Image::CreateFrom1xBitmap(
+        ImageTypeToBitmap(shared_contact_image_type));
+  }
+
+  auto notification = phonehub::Notification(
+      id, app_metadata, timestamp, importance, inline_reply_id, opt_title,
+      opt_text_content, opt_shared_image, opt_contact_image);
+
+  PA_LOG(VERBOSE) << "Set notification" << notification;
+  fake_phone_hub_manager_->fake_notification_manager()->SetNotification(
+      std::move(notification));
+}
+
+void MultidevicePhoneHubHandler::HandleRemoveNotification(
+    const base::ListValue* args) {
+  int notification_id = 0;
+  CHECK(args->GetInteger(0, &notification_id));
+  fake_phone_hub_manager_->fake_notification_manager()->RemoveNotification(
+      notification_id);
+  PA_LOG(VERBOSE) << "Removed notification with id " << notification_id;
+}
+
 }  // namespace multidevice
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/multidevice_internals/multidevice_internals_phone_hub_handler.h b/chrome/browser/ui/webui/chromeos/multidevice_internals/multidevice_internals_phone_hub_handler.h
index 1ed7729..cd5aceaa 100644
--- a/chrome/browser/ui/webui/chromeos/multidevice_internals/multidevice_internals_phone_hub_handler.h
+++ b/chrome/browser/ui/webui/chromeos/multidevice_internals/multidevice_internals_phone_hub_handler.h
@@ -37,6 +37,8 @@
   void HandleSetFakePhoneName(const base::ListValue* args);
   void HandleSetFakePhoneStatus(const base::ListValue* args);
   void HandleSetBrowserTabs(const base::ListValue* args);
+  void HandleSetNotification(const base::ListValue* args);
+  void HandleRemoveNotification(const base::ListValue* args);
 
   std::unique_ptr<phonehub::FakePhoneHubManager> fake_phone_hub_manager_;
 };
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
index cc4d6e8..cf431e2 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
@@ -18,6 +18,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/path_service.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
@@ -611,19 +612,19 @@
   initiator_title_ = job_title;
 }
 
-bool PrintPreviewUI::LastPageComposited(int page_number) const {
+bool PrintPreviewUI::LastPageComposited(uint32_t page_number) const {
   if (pages_to_render_.empty())
     return false;
 
   return page_number == pages_to_render_.back();
 }
 
-int PrintPreviewUI::GetPageToNupConvertIndex(int page_number) const {
+uint32_t PrintPreviewUI::GetPageToNupConvertIndex(uint32_t page_number) const {
   for (size_t index = 0; index < pages_to_render_.size(); ++index) {
     if (page_number == pages_to_render_[index])
       return index;
   }
-  return -1;
+  return kInvalidPageIndex;
 }
 
 std::vector<base::ReadOnlySharedMemoryRegion>
@@ -701,7 +702,8 @@
 void PrintPreviewUI::OnDidStartPreview(
     const mojom::DidStartPreviewParams& params,
     int request_id) {
-  DCHECK_GT(params.page_count, 0);
+  DCHECK_GT(params.page_count, 0u);
+  DCHECK_LE(params.page_count, kMaxPageCount);
   DCHECK(!params.pages_to_render.empty());
 
   pages_to_render_ = params.pages_to_render;
@@ -712,8 +714,8 @@
 
   if (g_test_delegate)
     g_test_delegate->DidGetPreviewPageCount(params.page_count);
-  handler_->SendPageCountReady(params.page_count, params.fit_to_page_scaling,
-                               request_id);
+  handler_->SendPageCountReady(base::checked_cast<int>(params.page_count),
+                               params.fit_to_page_scaling, request_id);
 }
 
 void PrintPreviewUI::OnDidGetDefaultPageLayout(
@@ -745,7 +747,7 @@
   handler_->SendPageLayoutReady(layout, has_custom_page_size_style, request_id);
 }
 
-bool PrintPreviewUI::OnPendingPreviewPage(int page_number) {
+bool PrintPreviewUI::OnPendingPreviewPage(uint32_t page_number) {
   if (pages_to_render_index_ >= pages_to_render_.size())
     return false;
 
@@ -755,16 +757,18 @@
 }
 
 void PrintPreviewUI::OnDidPreviewPage(
-    int page_number,
+    uint32_t page_number,
     scoped_refptr<base::RefCountedMemory> data,
     int preview_request_id) {
-  DCHECK_GE(page_number, 0);
+  DCHECK_NE(page_number, kInvalidPageIndex);
 
-  SetPrintPreviewDataForIndex(page_number, std::move(data));
+  SetPrintPreviewDataForIndex(base::checked_cast<int>(page_number),
+                              std::move(data));
 
   if (g_test_delegate)
     g_test_delegate->DidRenderPreviewPage(web_ui()->GetWebContents());
-  handler_->SendPagePreviewReady(page_number, *id_, preview_request_id);
+  handler_->SendPagePreviewReady(base::checked_cast<int>(page_number), *id_,
+                                 preview_request_id);
 }
 
 void PrintPreviewUI::OnPreviewDataIsAvailable(
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.h b/chrome/browser/ui/webui/print_preview/print_preview_ui.h
index cbe9622..d0e9b1f 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui.h
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.h
@@ -90,11 +90,11 @@
 
   // Returns true if |page_number| is the last page in |pages_to_render_|.
   // |page_number| is a 0-based number.
-  bool LastPageComposited(int page_number) const;
+  bool LastPageComposited(uint32_t page_number) const;
 
   // Get the 0-based index of the |page_number| in |pages_to_render_|.
   // Same as above, |page_number| is a 0-based number.
-  int GetPageToNupConvertIndex(int page_number) const;
+  uint32_t GetPageToNupConvertIndex(uint32_t page_number) const;
 
   std::vector<base::ReadOnlySharedMemoryRegion> TakePagesForNupConvert();
 
@@ -153,11 +153,11 @@
   // Notifies the Web UI that the 0-based page |page_number| rendering is being
   // processed and an OnPendingPreviewPage() call is imminent. Returns whether
   // |page_number| is the expected page.
-  bool OnPendingPreviewPage(int page_number);
+  bool OnPendingPreviewPage(uint32_t page_number);
 
   // Notifies the Web UI that the 0-based page |page_number| has been rendered.
   // |preview_request_id| indicates which request resulted in this response.
-  void OnDidPreviewPage(int page_number,
+  void OnDidPreviewPage(uint32_t page_number,
                         scoped_refptr<base::RefCountedMemory> data,
                         int preview_request_id);
 
@@ -190,7 +190,7 @@
   // Allows tests to wait until the print preview dialog is loaded.
   class TestDelegate {
    public:
-    virtual void DidGetPreviewPageCount(int page_count) = 0;
+    virtual void DidGetPreviewPageCount(uint32_t page_count) = 0;
     virtual void DidRenderPreviewPage(content::WebContents* preview_dialog) = 0;
 
    protected:
@@ -279,7 +279,7 @@
   base::string16 initiator_title_;
 
   // The list of 0-based page numbers that will be rendered.
-  std::vector<int> pages_to_render_;
+  std::vector<uint32_t> pages_to_render_;
 
   // The list of pages to be converted.
   std::vector<base::ReadOnlySharedMemoryRegion> pages_for_nup_convert_;
diff --git a/chrome/browser/video_tutorials/internal/BUILD.gn b/chrome/browser/video_tutorials/internal/BUILD.gn
index 85a7fdd..b7ff98b 100644
--- a/chrome/browser/video_tutorials/internal/BUILD.gn
+++ b/chrome/browser/video_tutorials/internal/BUILD.gn
@@ -68,7 +68,10 @@
   }
 
   generate_jni("jni_headers") {
-    visibility = [ ":*" ]
+    visibility = [
+      ":*",
+      "//chrome/browser",
+    ]
 
     sources = [
       "android/java/src/org/chromium/chrome/browser/video_tutorials/VideoTutorialServiceFactory.java",
diff --git a/chrome/browser/web_applications/components/external_install_options.cc b/chrome/browser/web_applications/components/external_install_options.cc
index 6777c57..3adde60 100644
--- a/chrome/browser/web_applications/components/external_install_options.cc
+++ b/chrome/browser/web_applications/components/external_install_options.cc
@@ -40,7 +40,9 @@
                   is_disabled, override_previous_user_uninstall,
                   bypass_service_worker_check, require_manifest,
                   force_reinstall, wait_for_windows_closed, install_placeholder,
-                  reinstall_placeholder, uninstall_and_replace,
+                  reinstall_placeholder,
+                  load_and_await_service_worker_registration,
+                  service_worker_registration_url, uninstall_and_replace,
                   additional_search_terms) ==
          std::tie(other.install_url, other.user_display_mode,
                   other.install_source, other.add_to_applications_menu,
@@ -50,6 +52,8 @@
                   other.bypass_service_worker_check, other.require_manifest,
                   other.force_reinstall, other.wait_for_windows_closed,
                   other.install_placeholder, other.reinstall_placeholder,
+                  other.load_and_await_service_worker_registration,
+                  other.service_worker_registration_url,
                   other.uninstall_and_replace, other.additional_search_terms);
 }
 
@@ -80,6 +84,10 @@
              << install_options.install_placeholder
              << "\n reinstall_placeholder: "
              << install_options.reinstall_placeholder
+             << "\n load_and_await_service_worker_registration: "
+             << install_options.load_and_await_service_worker_registration
+             << "\n service_worker_registration_url: "
+             << install_options.service_worker_registration_url.value_or(GURL())
              << "\n uninstall_and_replace:\n  "
              << base::JoinString(install_options.uninstall_and_replace, "\n  ")
              << "\n additional_search_terms:\n "
diff --git a/chrome/browser/web_applications/components/external_install_options.h b/chrome/browser/web_applications/components/external_install_options.h
index 97172ac..b8ddf2e 100644
--- a/chrome/browser/web_applications/components/external_install_options.h
+++ b/chrome/browser/web_applications/components/external_install_options.h
@@ -103,6 +103,17 @@
   // it.
   bool reinstall_placeholder = false;
 
+  // Whether we should load |service_worker_registration_url| after successful
+  // installation to allow the site to install its service worker and set up
+  // offline caching.
+  bool load_and_await_service_worker_registration = true;
+
+  // The URL to use for service worker registration. This is
+  // configurable by sites that wish to be able to track install metrics of the
+  // install_url separate from the service worker registration step. Defaults to
+  // install_url if unset.
+  base::Optional<GURL> service_worker_registration_url;
+
   // A list of app_ids that the Web App System should attempt to uninstall and
   // replace with this app (e.g maintain shelf pins, app list positions).
   std::vector<AppId> uninstall_and_replace;
diff --git a/chrome/browser/web_applications/components/pending_app_manager.cc b/chrome/browser/web_applications/components/pending_app_manager.cc
index 4434e50..d90b2a0 100644
--- a/chrome/browser/web_applications/components/pending_app_manager.cc
+++ b/chrome/browser/web_applications/components/pending_app_manager.cc
@@ -113,6 +113,11 @@
   registration_callback_ = RegistrationCallback();
 }
 
+void PendingAppManager::SetRegistrationsCompleteCallbackForTesting(
+    base::OnceClosure callback) {
+  registrations_complete_callback_ = std::move(callback);
+}
+
 void PendingAppManager::OnRegistrationFinished(const GURL& install_url,
                                                RegistrationResultCode result) {
   if (registration_callback_)
diff --git a/chrome/browser/web_applications/components/pending_app_manager.h b/chrome/browser/web_applications/components/pending_app_manager.h
index d8e724dc..accdc57 100644
--- a/chrome/browser/web_applications/components/pending_app_manager.h
+++ b/chrome/browser/web_applications/components/pending_app_manager.h
@@ -112,6 +112,7 @@
 
   void SetRegistrationCallbackForTesting(RegistrationCallback callback);
   void ClearRegistrationCallbackForTesting();
+  void SetRegistrationsCompleteCallbackForTesting(base::OnceClosure callback);
   void ClearSynchronizeRequestsForTesting();
 
   virtual void Shutdown() = 0;
@@ -128,6 +129,8 @@
   virtual void OnRegistrationFinished(const GURL& launch_url,
                                       RegistrationResultCode result);
 
+  base::OnceClosure registrations_complete_callback_;
+
  private:
   struct SynchronizeRequest {
     SynchronizeRequest(SynchronizeCallback callback, int remaining_requests);
diff --git a/chrome/browser/web_applications/external_web_app_utils.cc b/chrome/browser/web_applications/external_web_app_utils.cc
index a77e513e..64d74e3 100644
--- a/chrome/browser/web_applications/external_web_app_utils.cc
+++ b/chrome/browser/web_applications/external_web_app_utils.cc
@@ -51,6 +51,22 @@
 constexpr char kLaunchContainerTab[] = "tab";
 constexpr char kLaunchContainerWindow[] = "window";
 
+// kLoadAndAwaitServiceWorkerRegistration is an optional bool that specifies
+// whether to fetch the |kServiceWorkerRegistrationUrl| after installation to
+// allow time for the app to register its service worker. This is done as a
+// second pass after install in order to not block the installation of other
+// background installed apps. No fetch is made if the service worker has already
+// been registered by the |kAppUrl|.
+// Defaults to true.
+constexpr char kLoadAndAwaitServiceWorkerRegistration[] =
+    "load_and_await_service_worker_registration";
+
+// kServiceWorkerRegistrationUrl is an optional string specifying the URL to use
+// for the above |kLoadAndAwaitServiceWorkerRegistration|.
+// Defaults to the |kAppUrl|.
+constexpr char kServiceWorkerRegistrationUrl[] =
+    "service_worker_registration_url";
+
 // kUninstallAndReplace is an optional array of strings which specifies App IDs
 // which the app is replacing. This will transfer OS attributes (e.g the source
 // app's shelf and app list positions on ChromeOS) and then uninstall the source
@@ -176,6 +192,36 @@
     return base::nullopt;
   }
 
+  bool load_and_await_service_worker_registration = true;
+  value = app_config.FindKey(kLoadAndAwaitServiceWorkerRegistration);
+  if (value) {
+    if (!value->is_bool()) {
+      LOG(ERROR) << file << " had an invalid "
+                 << kLoadAndAwaitServiceWorkerRegistration;
+      return base::nullopt;
+    }
+    load_and_await_service_worker_registration = value->GetBool();
+  }
+
+  base::Optional<GURL> service_worker_registration_url;
+  value = app_config.FindKey(kServiceWorkerRegistrationUrl);
+  if (value) {
+    if (!load_and_await_service_worker_registration) {
+      LOG(ERROR) << file << " should not specify a "
+                 << kServiceWorkerRegistrationUrl << " while "
+                 << kLoadAndAwaitServiceWorkerRegistration << " is disabled";
+    }
+    if (!value->is_string()) {
+      LOG(ERROR) << file << " had an invalid " << kServiceWorkerRegistrationUrl;
+      return base::nullopt;
+    }
+    service_worker_registration_url.emplace(value->GetString());
+    if (!service_worker_registration_url->is_valid()) {
+      LOG(ERROR) << file << " had an invalid " << kServiceWorkerRegistrationUrl;
+      return base::nullopt;
+    }
+  }
+
   value = app_config.FindKey(kUninstallAndReplace);
   std::vector<AppId> uninstall_and_replace_ids;
   if (value) {
@@ -214,6 +260,10 @@
   install_options.add_to_quick_launch_bar = create_shortcuts;
   install_options.require_manifest = true;
   install_options.uninstall_and_replace = std::move(uninstall_and_replace_ids);
+  install_options.load_and_await_service_worker_registration =
+      load_and_await_service_worker_registration;
+  install_options.service_worker_registration_url =
+      service_worker_registration_url;
   install_options.app_info_factory = std::move(app_info_factory);
 
   return install_options;
diff --git a/chrome/browser/web_applications/pending_app_manager_impl.cc b/chrome/browser/web_applications/pending_app_manager_impl.cc
index 36b8ac99..e0322c6 100644
--- a/chrome/browser/web_applications/pending_app_manager_impl.cc
+++ b/chrome/browser/web_applications/pending_app_manager_impl.cc
@@ -243,8 +243,11 @@
 }
 
 bool PendingAppManagerImpl::RunNextRegistration() {
-  if (pending_registrations_.empty())
+  if (pending_registrations_.empty()) {
+    if (registrations_complete_callback_)
+      std::move(registrations_complete_callback_).Run();
     return false;
+  }
 
   GURL url_to_check = std::move(pending_registrations_.front());
   pending_registrations_.pop_front();
@@ -275,22 +278,9 @@
 void PendingAppManagerImpl::CurrentInstallationFinished(
     const base::Optional<AppId>& app_id,
     InstallResultCode code) {
-  if (app_id && code == InstallResultCode::kSuccessNewInstall &&
-      base::FeatureList::IsEnabled(
-          features::kDesktopPWAsCacheDuringDefaultInstall)) {
-    const GURL& install_url =
-        current_install_->task->install_options().install_url;
-    bool is_local_resource =
-        install_url.scheme() == content::kChromeUIScheme ||
-        install_url.scheme() == content::kChromeUIUntrustedScheme;
-    // TODO(crbug.com/809304): Call CreateWebContentsIfNecessary() instead of
-    // checking web_contents_ once major migration of default hosted apps to web
-    // apps has completed.
-    // Temporarily using offline manifest migrations (in which |web_contents_|
-    // is nullptr) in order to avoid overwhelming migrated-to web apps with hits
-    // for service worker registrations.
-    if (!install_url.is_empty() && !is_local_resource && web_contents_)
-      pending_registrations_.push_back(install_url);
+  if (app_id && code == InstallResultCode::kSuccessNewInstall) {
+    MaybeEnqueueServiceWorkerRegistration(
+        current_install_->task->install_options());
   }
 
   // Post a task to avoid InstallableManager crashing and do so before
@@ -304,4 +294,35 @@
       .Run(task_and_callback->task->install_options().install_url, code);
 }
 
+void PendingAppManagerImpl::MaybeEnqueueServiceWorkerRegistration(
+    const ExternalInstallOptions& install_options) {
+  if (!base::FeatureList::IsEnabled(
+          features::kDesktopPWAsCacheDuringDefaultInstall)) {
+    return;
+  }
+
+  if (!install_options.load_and_await_service_worker_registration)
+    return;
+
+  // TODO(crbug.com/809304): Call CreateWebContentsIfNecessary() instead of
+  // checking web_contents_ once major migration of default hosted apps to web
+  // apps has completed.
+  // Temporarily using offline manifest migrations (in which |web_contents_|
+  // is nullptr) in order to avoid overwhelming migrated-to web apps with hits
+  // for service worker registrations.
+  if (!web_contents_)
+    return;
+
+  GURL url = install_options.service_worker_registration_url.value_or(
+      install_options.install_url);
+  if (url.is_empty())
+    return;
+  if (url.scheme() == content::kChromeUIScheme)
+    return;
+  if (url.scheme() == content::kChromeUIUntrustedScheme)
+    return;
+
+  pending_registrations_.push_back(url);
+}
+
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/pending_app_manager_impl.h b/chrome/browser/web_applications/pending_app_manager_impl.h
index 6b68851..1041f3e 100644
--- a/chrome/browser/web_applications/pending_app_manager_impl.h
+++ b/chrome/browser/web_applications/pending_app_manager_impl.h
@@ -87,6 +87,9 @@
   void CurrentInstallationFinished(const base::Optional<std::string>& app_id,
                                    InstallResultCode code);
 
+  void MaybeEnqueueServiceWorkerRegistration(
+      const ExternalInstallOptions& install_options);
+
   Profile* const profile_;
   ExternallyInstalledWebAppPrefs externally_installed_app_prefs_;
 
diff --git a/chrome/browser/web_applications/pending_app_manager_impl_browsertest.cc b/chrome/browser/web_applications/pending_app_manager_impl_browsertest.cc
index 8c0929c..6ea5758 100644
--- a/chrome/browser/web_applications/pending_app_manager_impl_browsertest.cc
+++ b/chrome/browser/web_applications/pending_app_manager_impl_browsertest.cc
@@ -317,6 +317,48 @@
       content::ServiceWorkerCapability::SERVICE_WORKER_WITH_FETCH_HANDLER);
 }
 
+IN_PROC_BROWSER_TEST_P(PendingAppManagerImplBrowserTest,
+                       RegistrationAlternateUrlSucceeds) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  GURL install_url(
+      embedded_test_server()->GetURL("/web_apps/no_service_worker.html"));
+  GURL registration_url =
+      embedded_test_server()->GetURL("/web_apps/basic.html");
+
+  ExternalInstallOptions install_options = CreateInstallOptions(install_url);
+  install_options.bypass_service_worker_check = true;
+  install_options.service_worker_registration_url = registration_url;
+  InstallApp(std::move(install_options));
+  EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result_code_.value());
+  WebAppRegistrationWaiter(&pending_app_manager())
+      .AwaitNextRegistration(registration_url,
+                             RegistrationResultCode::kSuccess);
+  CheckServiceWorkerStatus(
+      install_url,
+      content::ServiceWorkerCapability::SERVICE_WORKER_WITH_FETCH_HANDLER);
+}
+
+IN_PROC_BROWSER_TEST_P(PendingAppManagerImplBrowserTest, RegistrationSkipped) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  // Delay service worker registration to second load to simulate it not loading
+  // during the initial install pass.
+  GURL install_url(embedded_test_server()->GetURL(
+      "/web_apps/service_worker_on_second_load.html"));
+
+  ExternalInstallOptions install_options = CreateInstallOptions(install_url);
+  install_options.bypass_service_worker_check = true;
+  install_options.load_and_await_service_worker_registration = false;
+  WebAppRegistrationWaiter waiter(&pending_app_manager());
+  InstallApp(std::move(install_options));
+  waiter.AwaitRegistrationsComplete();
+
+  EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result_code_.value());
+  CheckServiceWorkerStatus(install_url,
+                           content::ServiceWorkerCapability::NO_SERVICE_WORKER);
+}
+
 IN_PROC_BROWSER_TEST_P(PendingAppManagerImplBrowserTest, AlreadyRegistered) {
   ASSERT_TRUE(embedded_test_server()->Start());
   {
diff --git a/chrome/browser/web_applications/test/web_app_registration_waiter.cc b/chrome/browser/web_applications/test/web_app_registration_waiter.cc
index 1911161..251b4ed 100644
--- a/chrome/browser/web_applications/test/web_app_registration_waiter.cc
+++ b/chrome/browser/web_applications/test/web_app_registration_waiter.cc
@@ -16,6 +16,8 @@
         CHECK_EQ(code_, code);
         run_loop_.Quit();
       }));
+  manager_->SetRegistrationsCompleteCallbackForTesting(
+      complete_run_loop_.QuitClosure());
 }
 
 WebAppRegistrationWaiter::~WebAppRegistrationWaiter() {
@@ -30,4 +32,8 @@
   run_loop_.Run();
 }
 
+void WebAppRegistrationWaiter::AwaitRegistrationsComplete() {
+  complete_run_loop_.Run();
+}
+
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/test/web_app_registration_waiter.h b/chrome/browser/web_applications/test/web_app_registration_waiter.h
index dab0dad..f22d452 100644
--- a/chrome/browser/web_applications/test/web_app_registration_waiter.h
+++ b/chrome/browser/web_applications/test/web_app_registration_waiter.h
@@ -19,11 +19,15 @@
   void AwaitNextRegistration(const GURL& install_url,
                              RegistrationResultCode code);
 
+  void AwaitRegistrationsComplete();
+
  private:
   PendingAppManager* const manager_;
   base::RunLoop run_loop_;
   GURL install_url_;
   RegistrationResultCode code_;
+
+  base::RunLoop complete_run_loop_;
 };
 
 }  // namespace web_app
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 5b295b3..5d81075 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-master-1600148958-91c0cd454c0f8748eee83f19943ecba0f6b92ac0.profdata
+chrome-win64-master-1600192792-f4ca908cacd319b04516240c34a315b960a046b2.profdata
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index 3d1e299e..16fe306a 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -774,6 +774,21 @@
   ]
 
   component_deps = [ "//content/public/common" ]
+
+  cpp_typemaps = [
+    {
+      types = [
+        {
+          mojom = "chrome.mojom.WebApplicationInfo"
+          cpp = "::WebApplicationInfo"
+        },
+      ]
+      traits_headers = [ "web_application_info.h" ]
+      traits_private_headers =
+          [ "web_application_info_provider_param_traits.h" ]
+      traits_deps = [ "//ipc" ]
+    },
+  ]
 }
 
 if (enable_print_preview && !is_chromeos) {
diff --git a/chrome/common/OWNERS b/chrome/common/OWNERS
index ecf27f1..5210b93 100644
--- a/chrome/common/OWNERS
+++ b/chrome/common/OWNERS
@@ -20,15 +20,9 @@
 per-file *_param_traits*.*=set noparent
 per-file *_param_traits*.*=file://ipc/SECURITY_OWNERS
 
-per-file *_type_converter*.*=set noparent
-per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
-
 per-file *_mojom_traits*.*=set noparent
 per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
 
-per-file *.typemap=set noparent
-per-file *.typemap=file://ipc/SECURITY_OWNERS
-
 # Changes to Mojo interfaces require a security review to avoid
 # introducing new sandbox escapes.
 per-file *.mojom=set noparent
diff --git a/chrome/common/search/BUILD.gn b/chrome/common/search/BUILD.gn
index d9844e7..8423b27 100644
--- a/chrome/common/search/BUILD.gn
+++ b/chrome/common/search/BUILD.gn
@@ -38,4 +38,56 @@
     "//mojo/public/mojom/base",
     "//url/mojom:url_mojom_gurl",
   ]
+
+  cpp_typemaps = [
+    {
+      types = [
+        # TODO(dbeam): NTP -> Ntp.
+        {
+          mojom = "search.mojom.NTPLoggingEventType"
+          cpp = "::NTPLoggingEventType"
+        },
+        {
+          mojom = "search.mojom.NTPSuggestionsLoggingEventType"
+          cpp = "::NTPSuggestionsLoggingEventType"
+        },
+        {
+          mojom = "search.mojom.NTPTileImpression"
+          cpp = "::ntp_tiles::NTPTileImpression"
+        },
+        {
+          mojom = "search.mojom.OmniboxFocusState"
+          cpp = "::OmniboxFocusState"
+        },
+        {
+          mojom = "search.mojom.OmniboxFocusChangeReason"
+          cpp = "::OmniboxFocusChangeReason"
+        },
+        {
+          mojom = "search.mojom.InstantMostVisitedInfo"
+          cpp = "::InstantMostVisitedInfo"
+        },
+        {
+          mojom = "search.mojom.NtpTheme"
+          cpp = "::NtpTheme"
+        },
+        {
+          mojom = "search.mojom.SearchBoxTheme"
+          cpp = "::SearchBoxTheme"
+        },
+      ]
+      traits_headers = [
+        "//chrome/common/search/instant_types.h",
+        "//chrome/common/search/ntp_logging_events.h",
+        "//components/ntp_tiles/ntp_tile_impression.h",
+        "//components/omnibox/common/omnibox_focus_state.h",
+      ]
+      traits_private_headers =
+          [ "//chrome/common/search/instant_mojom_traits.h" ]
+      traits_deps = [
+        "//ipc",
+        "//skia",
+      ]
+    },
+  ]
 }
diff --git a/chrome/common/search/OWNERS b/chrome/common/search/OWNERS
index e62efe51..170eaf8a 100644
--- a/chrome/common/search/OWNERS
+++ b/chrome/common/search/OWNERS
@@ -5,5 +5,3 @@
 per-file *.mojom=file://ipc/SECURITY_OWNERS
 per-file *_mojom_traits*.*=set noparent
 per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
-per-file *.typemap=set noparent
-per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/chrome/common/search/search.typemap b/chrome/common/search/search.typemap
deleted file mode 100644
index 1a19f84..0000000
--- a/chrome/common/search/search.typemap
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-mojom = "//chrome/common/search/search.mojom"
-public_headers = [
-  "//chrome/common/search/instant_types.h",
-  "//chrome/common/search/ntp_logging_events.h",
-  "//components/ntp_tiles/ntp_tile_impression.h",
-  "//components/omnibox/common/omnibox_focus_state.h",
-]
-traits_headers = [ "//chrome/common/search/instant_mojom_traits.h" ]
-deps = [
-  "//ipc",
-  "//skia",
-]
-type_mappings = [
-  # TODO(dbeam): NTP -> Ntp.
-  "search.mojom.NTPLoggingEventType=::NTPLoggingEventType",
-  "search.mojom.NTPSuggestionsLoggingEventType=::NTPSuggestionsLoggingEventType",
-  "search.mojom.NTPTileImpression=::ntp_tiles::NTPTileImpression",
-  "search.mojom.OmniboxFocusState=::OmniboxFocusState",
-  "search.mojom.OmniboxFocusChangeReason=::OmniboxFocusChangeReason",
-  "search.mojom.InstantMostVisitedInfo=::InstantMostVisitedInfo",
-  "search.mojom.NtpTheme=::NtpTheme",
-  "search.mojom.SearchBoxTheme=::SearchBoxTheme",
-]
diff --git a/chrome/common/web_application_info_provider.typemap b/chrome/common/web_application_info_provider.typemap
deleted file mode 100644
index 45d4ee3..0000000
--- a/chrome/common/web_application_info_provider.typemap
+++ /dev/null
@@ -1,13 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-mojom = "//chrome/common/chrome_render_frame.mojom"
-public_headers = [ "//chrome/common/web_application_info.h" ]
-traits_headers =
-    [ "//chrome/common/web_application_info_provider_param_traits.h" ]
-public_deps = [
-  "//ipc",
-]
-
-type_mappings = [ "chrome.mojom.WebApplicationInfo=::WebApplicationInfo" ]
diff --git a/chrome/installer/util/BUILD.gn b/chrome/installer/util/BUILD.gn
index 88cc5d8..2ea95551d 100644
--- a/chrome/installer/util/BUILD.gn
+++ b/chrome/installer/util/BUILD.gn
@@ -86,14 +86,17 @@
       "shell_util.h",
     ]
 
-    public_deps += [ ":did_run_support" ]
+    public_deps += [
+      ":did_run_support",
 
-    deps += [
       # Need to depend on the generated strings target since files here
       # depend on the generated header, but only depend on the ":strings"
       # target (which actually compiles and causes the generated code to be
       # linked) from the ":util" target.
       ":generate_strings",
+    ]
+
+    deps += [
       "//base:i18n",
       "//base/third_party/dynamic_annotations",
       "//build:branding_buildflags",
diff --git a/chrome/renderer/v8_unwinder_unittest.cc b/chrome/renderer/v8_unwinder_unittest.cc
index 6764e87..04fef32e 100644
--- a/chrome/renderer/v8_unwinder_unittest.cc
+++ b/chrome/renderer/v8_unwinder_unittest.cc
@@ -435,8 +435,9 @@
 }
 
 // Checks that unwinding from C++ through JavaScript and back into C++ succeeds.
-// NB: unwinding is only supported for 64 bit Windows and OS X.
-#if (defined(OS_WIN) && defined(ARCH_CPU_64_BITS)) || defined(OS_MAC)
+// NB: unwinding is only supported for 64 bit Windows and Intel macOS.
+#if (defined(OS_WIN) && defined(ARCH_CPU_64_BITS)) || \
+    (defined(OS_MAC) && defined(ARCH_CPU_X86_64))
 #define MAYBE_UnwindThroughV8Frames UnwindThroughV8Frames
 #else
 #define MAYBE_UnwindThroughV8Frames DISABLED_UnwindThroughV8Frames
diff --git a/chrome/services/cups_proxy/public/mojom/BUILD.gn b/chrome/services/cups_proxy/public/mojom/BUILD.gn
index be7b494..ee767135 100644
--- a/chrome/services/cups_proxy/public/mojom/BUILD.gn
+++ b/chrome/services/cups_proxy/public/mojom/BUILD.gn
@@ -7,6 +7,18 @@
 
 mojom("mojom") {
   sources = [ "proxy.mojom" ]
-
   public_deps = [ "//mojo/public/mojom/base" ]
+  cpp_typemaps = [
+    {
+      types = [
+        {
+          mojom = "cups_proxy.mojom.HttpHeader"
+          cpp = "ipp_converter::HttpHeader"
+        },
+      ]
+      traits_headers = [ "proxy_mojom_traits.h" ]
+      traits_sources = [ "proxy_mojom_traits.cc" ]
+      traits_public_deps = [ "//chrome/services/ipp_parser/public/cpp" ]
+    },
+  ]
 }
diff --git a/chrome/services/cups_proxy/public/mojom/OWNERS b/chrome/services/cups_proxy/public/mojom/OWNERS
index ae29a36aa..1feb514 100644
--- a/chrome/services/cups_proxy/public/mojom/OWNERS
+++ b/chrome/services/cups_proxy/public/mojom/OWNERS
@@ -2,5 +2,3 @@
 per-file *.mojom=file://ipc/SECURITY_OWNERS
 per-file *_mojom_traits*.*=set noparent
 per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
-per-file *.typemap=set noparent
-per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/chrome/services/cups_proxy/public/mojom/proxy.typemap b/chrome/services/cups_proxy/public/mojom/proxy.typemap
deleted file mode 100644
index ebb9f53..0000000
--- a/chrome/services/cups_proxy/public/mojom/proxy.typemap
+++ /dev/null
@@ -1,16 +0,0 @@
-mojom = "//chrome/services/cups_proxy/public/mojom/proxy.mojom"
-
-public_headers = [ "//chrome/services/ipp_parser/public/cpp/ipp_converter.h" ]
-
-traits_headers =
-    [ "//chrome/services/cups_proxy/public/mojom/proxy_mojom_traits.h" ]
-
-sources = [
-  "//chrome/services/cups_proxy/public/mojom/proxy_mojom_traits.cc",
-]
-
-public_deps = [
-  "//printing",
-]
-
-type_mappings = [ "cups_proxy.mojom.HttpHeader=ipp_converter::HttpHeader" ]
diff --git a/chrome/services/cups_proxy/public/mojom/proxy_mojom_traits.h b/chrome/services/cups_proxy/public/mojom/proxy_mojom_traits.h
index bf7a4a0..a28eeb9d 100644
--- a/chrome/services/cups_proxy/public/mojom/proxy_mojom_traits.h
+++ b/chrome/services/cups_proxy/public/mojom/proxy_mojom_traits.h
@@ -5,8 +5,7 @@
 #ifndef CHROME_SERVICES_CUPS_PROXY_PUBLIC_MOJOM_PROXY_MOJOM_TRAITS_H_
 #define CHROME_SERVICES_CUPS_PROXY_PUBLIC_MOJOM_PROXY_MOJOM_TRAITS_H_
 
-#include "build/build_config.h"
-#include "chrome/services/cups_proxy/public/mojom/proxy.mojom.h"
+#include "chrome/services/cups_proxy/public/mojom/proxy.mojom-shared.h"
 #include "chrome/services/ipp_parser/public/cpp/ipp_converter.h"
 
 namespace mojo {
diff --git a/chrome/services/cups_proxy/public/mojom/typemaps.gni b/chrome/services/cups_proxy/public/mojom/typemaps.gni
deleted file mode 100644
index c9ed6967..0000000
--- a/chrome/services/cups_proxy/public/mojom/typemaps.gni
+++ /dev/null
@@ -1,5 +0,0 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-typemaps = [ "//chrome/services/cups_proxy/public/mojom/proxy.typemap" ]
diff --git a/chrome/services/file_util/public/mojom/BUILD.gn b/chrome/services/file_util/public/mojom/BUILD.gn
index cf5ab6d..7520d220 100644
--- a/chrome/services/file_util/public/mojom/BUILD.gn
+++ b/chrome/services/file_util/public/mojom/BUILD.gn
@@ -20,4 +20,22 @@
     sources += [ "zip_file_creator.mojom" ]
     public_deps += [ "//components/services/filesystem/public/mojom" ]
   }
+
+  cpp_typemaps = [
+    {
+      types = [
+        {
+          mojom = "chrome.mojom.SafeArchiveAnalyzerResults"
+          cpp = "::safe_browsing::ArchiveAnalyzerResults"
+        },
+      ]
+      traits_headers = [ "//chrome/common/safe_browsing/zip_analyzer.h" ]
+      traits_private_headers = [ "safe_archive_analyzer_param_traits.h" ]
+      traits_public_deps = [
+        "//chrome/common/safe_browsing:proto",
+        "//components/safe_browsing:buildflags",
+        "//components/safe_browsing/core:csd_proto",
+      ]
+    },
+  ]
 }
diff --git a/chrome/services/file_util/public/mojom/OWNERS b/chrome/services/file_util/public/mojom/OWNERS
index 1497acb..43d18b5 100644
--- a/chrome/services/file_util/public/mojom/OWNERS
+++ b/chrome/services/file_util/public/mojom/OWNERS
@@ -3,6 +3,3 @@
 
 per-file *_param_traits*.*=set noparent
 per-file *_param_traits*.*=file://ipc/SECURITY_OWNERS
-
-per-file *.typemap=set noparent
-per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/chrome/services/file_util/public/mojom/safe_archive_analyzer.typemap b/chrome/services/file_util/public/mojom/safe_archive_analyzer.typemap
deleted file mode 100644
index 640310f3..0000000
--- a/chrome/services/file_util/public/mojom/safe_archive_analyzer.typemap
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-mojom = "//chrome/services/file_util/public/mojom/safe_archive_analyzer.mojom"
-
-public_headers = [ "//chrome/common/safe_browsing/zip_analyzer.h" ]
-
-traits_headers = [ "//chrome/services/file_util/public/mojom/safe_archive_analyzer_param_traits.h" ]
-
-public_deps = [
-  "//chrome/common/safe_browsing:proto",
-  "//components/safe_browsing:buildflags",
-  "//components/safe_browsing/core:csd_proto",
-]
-
-type_mappings = [ "chrome.mojom.SafeArchiveAnalyzerResults=::safe_browsing::ArchiveAnalyzerResults" ]
diff --git a/chrome/services/media_gallery_util/public/mojom/BUILD.gn b/chrome/services/media_gallery_util/public/mojom/BUILD.gn
index 6c32e6e..26d061c 100644
--- a/chrome/services/media_gallery_util/public/mojom/BUILD.gn
+++ b/chrome/services/media_gallery_util/public/mojom/BUILD.gn
@@ -11,4 +11,17 @@
     "//media/mojo/mojom",
     "//mojo/public/mojom/base",
   ]
+
+  cpp_typemaps = [
+    {
+      types = [
+        {
+          mojom = "chrome.mojom.AttachedImage"
+          cpp = "::metadata::AttachedImage"
+        },
+      ]
+      traits_headers = [ "media_parser_mojom_traits.h" ]
+      traits_sources = [ "media_parser_mojom_traits.cc" ]
+    },
+  ]
 }
diff --git a/chrome/services/media_gallery_util/public/mojom/OWNERS b/chrome/services/media_gallery_util/public/mojom/OWNERS
index ab87d1e..f486cf5 100644
--- a/chrome/services/media_gallery_util/public/mojom/OWNERS
+++ b/chrome/services/media_gallery_util/public/mojom/OWNERS
@@ -3,6 +3,3 @@
 
 per-file *_mojom_traits*.*=set noparent
 per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
-
-per-file *.typemap=set noparent
-per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/chrome/services/media_gallery_util/public/mojom/media_parser.typemap b/chrome/services/media_gallery_util/public/mojom/media_parser.typemap
deleted file mode 100644
index 4f8de01..0000000
--- a/chrome/services/media_gallery_util/public/mojom/media_parser.typemap
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-mojom = "//chrome/services/media_gallery_util/public/mojom/media_parser.mojom"
-
-public_headers = [ "//chrome/common/media_galleries/metadata_types.h" ]
-
-traits_headers = [ "//chrome/services/media_gallery_util/public/mojom/media_parser_mojom_traits.h" ]
-
-sources = [
-  "//chrome/services/media_gallery_util/public/mojom/media_parser_mojom_traits.cc",
-]
-
-type_mappings = [ "chrome.mojom.AttachedImage=::metadata::AttachedImage" ]
diff --git a/chrome/services/media_gallery_util/public/mojom/media_parser_mojom_traits.h b/chrome/services/media_gallery_util/public/mojom/media_parser_mojom_traits.h
index 4be7de0..957e68d 100644
--- a/chrome/services/media_gallery_util/public/mojom/media_parser_mojom_traits.h
+++ b/chrome/services/media_gallery_util/public/mojom/media_parser_mojom_traits.h
@@ -9,7 +9,7 @@
 
 #include "base/containers/span.h"
 #include "chrome/common/media_galleries/metadata_types.h"
-#include "chrome/services/media_gallery_util/public/mojom/media_parser.mojom.h"
+#include "chrome/services/media_gallery_util/public/mojom/media_parser.mojom-shared.h"
 #include "mojo/public/cpp/bindings/array_traits_span.h"
 
 namespace mojo {
diff --git a/chrome/services/printing/public/mojom/BUILD.gn b/chrome/services/printing/public/mojom/BUILD.gn
index 15adb9a..2e0b57cf 100644
--- a/chrome/services/printing/public/mojom/BUILD.gn
+++ b/chrome/services/printing/public/mojom/BUILD.gn
@@ -33,4 +33,40 @@
   if (is_win) {
     sources += [ "pdf_to_emf_converter.mojom" ]
   }
+
+  cpp_typemaps = [
+    {
+      types = [
+        {
+          mojom = "printing.mojom.PdfRenderSettings"
+          cpp = "::printing::PdfRenderSettings"
+        },
+        {
+          mojom = "printing.mojom.PdfRenderSettings::Mode"
+          cpp = "::printing::PdfRenderSettings::Mode"
+        },
+      ]
+      traits_headers = [ "pdf_render_settings_mojom_traits.h" ]
+      traits_sources = [ "pdf_render_settings_mojom_traits.cc" ]
+      traits_public_deps = [ "//printing" ]
+    },
+    {
+      types = [
+        {
+          mojom = "printing.mojom.PwgRasterSettings::TransformType"
+          cpp = "::printing::PwgRasterTransformType"
+        },
+        {
+          mojom = "printing.mojom.PwgRasterSettings"
+          cpp = "::printing::PwgRasterSettings"
+        },
+      ]
+      traits_headers = [ "pdf_to_pwg_raster_converter_mojom_traits.h" ]
+      traits_sources = [ "pdf_to_pwg_raster_converter_mojom_traits.cc" ]
+      traits_public_deps = [
+        "//printing",
+        "//printing/mojom",
+      ]
+    },
+  ]
 }
diff --git a/chrome/services/printing/public/mojom/OWNERS b/chrome/services/printing/public/mojom/OWNERS
index ae29a36aa..1feb514 100644
--- a/chrome/services/printing/public/mojom/OWNERS
+++ b/chrome/services/printing/public/mojom/OWNERS
@@ -2,5 +2,3 @@
 per-file *.mojom=file://ipc/SECURITY_OWNERS
 per-file *_mojom_traits*.*=set noparent
 per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
-per-file *.typemap=set noparent
-per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/chrome/services/printing/public/mojom/pdf_render_settings.typemap b/chrome/services/printing/public/mojom/pdf_render_settings.typemap
deleted file mode 100644
index 76cd87a..0000000
--- a/chrome/services/printing/public/mojom/pdf_render_settings.typemap
+++ /dev/null
@@ -1,23 +0,0 @@
-mojom = "//chrome/services/printing/public/mojom/pdf_render_settings.mojom"
-
-public_headers = [
-  "//printing/pdf_render_settings.h",
-  "//ui/gfx/geometry/rect.h",
-]
-
-traits_headers = [
-  "//chrome/services/printing/public/mojom/pdf_render_settings_mojom_traits.h",
-]
-
-sources = [
-  "//chrome/services/printing/public/mojom/pdf_render_settings_mojom_traits.cc",
-]
-
-public_deps = [
-  "//ui/gfx/geometry",
-]
-
-type_mappings = [
-  "printing.mojom.PdfRenderSettings=::printing::PdfRenderSettings",
-  "printing.mojom.PdfRenderSettings::Mode=::printing::PdfRenderSettings::Mode",
-]
diff --git a/chrome/services/printing/public/mojom/pdf_render_settings_mojom_traits.h b/chrome/services/printing/public/mojom/pdf_render_settings_mojom_traits.h
index 86652e1c..630f7d6 100644
--- a/chrome/services/printing/public/mojom/pdf_render_settings_mojom_traits.h
+++ b/chrome/services/printing/public/mojom/pdf_render_settings_mojom_traits.h
@@ -6,17 +6,17 @@
 #define CHROME_SERVICES_PRINTING_PUBLIC_MOJOM_PDF_RENDER_SETTINGS_MOJOM_TRAITS_H_
 
 #include "build/build_config.h"
-#include "chrome/services/printing/public/mojom/pdf_render_settings.mojom.h"
+#include "chrome/services/printing/public/mojom/pdf_render_settings.mojom-shared.h"
 #include "printing/pdf_render_settings.h"
 
 namespace mojo {
 
 template <>
-struct EnumTraits<printing::mojom::PdfRenderSettings::Mode,
+struct EnumTraits<printing::mojom::PdfRenderSettings_Mode,
                   printing::PdfRenderSettings::Mode> {
-  static printing::mojom::PdfRenderSettings::Mode ToMojom(
+  static printing::mojom::PdfRenderSettings_Mode ToMojom(
       printing::PdfRenderSettings::Mode mode) {
-    using MojomMode = printing::mojom::PdfRenderSettings::Mode;
+    using MojomMode = printing::mojom::PdfRenderSettings_Mode;
     using PrintMode = printing::PdfRenderSettings::Mode;
     switch (mode) {
       case PrintMode::NORMAL:
@@ -37,12 +37,12 @@
 #endif
     }
     NOTREACHED() << "Unknown mode " << static_cast<int>(mode);
-    return printing::mojom::PdfRenderSettings::Mode::NORMAL;
+    return printing::mojom::PdfRenderSettings_Mode::NORMAL;
   }
 
-  static bool FromMojom(printing::mojom::PdfRenderSettings::Mode input,
+  static bool FromMojom(printing::mojom::PdfRenderSettings_Mode input,
                         printing::PdfRenderSettings::Mode* output) {
-    using MojomMode = printing::mojom::PdfRenderSettings::Mode;
+    using MojomMode = printing::mojom::PdfRenderSettings_Mode;
     using PrintMode = printing::PdfRenderSettings::Mode;
     switch (input) {
       case MojomMode::NORMAL:
diff --git a/chrome/services/printing/public/mojom/pdf_to_pwg_raster_converter.typemap b/chrome/services/printing/public/mojom/pdf_to_pwg_raster_converter.typemap
deleted file mode 100644
index 561d841..0000000
--- a/chrome/services/printing/public/mojom/pdf_to_pwg_raster_converter.typemap
+++ /dev/null
@@ -1,17 +0,0 @@
-mojom =
-    "//chrome/services/printing/public/mojom/pdf_to_pwg_raster_converter.mojom"
-
-public_headers = [ "//printing/pwg_raster_settings.h" ]
-
-traits_headers = [ "//chrome/services/printing/public/mojom/pdf_to_pwg_raster_converter_mojom_traits.h" ]
-
-sources = [
-  "//chrome/services/printing/public/mojom/pdf_to_pwg_raster_converter_mojom_traits.cc",
-]
-
-public_deps = []
-
-type_mappings = [
-  "printing.mojom.PwgRasterTransformType=::printing::PwgRasterTransformType",
-  "printing.mojom.PwgRasterSettings=::printing::PwgRasterSettings",
-]
diff --git a/chrome/services/printing/public/mojom/pdf_to_pwg_raster_converter_mojom_traits.h b/chrome/services/printing/public/mojom/pdf_to_pwg_raster_converter_mojom_traits.h
index c409da3..84c40cc 100644
--- a/chrome/services/printing/public/mojom/pdf_to_pwg_raster_converter_mojom_traits.h
+++ b/chrome/services/printing/public/mojom/pdf_to_pwg_raster_converter_mojom_traits.h
@@ -6,51 +6,51 @@
 #define CHROME_SERVICES_PRINTING_PUBLIC_MOJOM_PDF_TO_PWG_RASTER_CONVERTER_MOJOM_TRAITS_H_
 
 #include "build/build_config.h"
-#include "chrome/services/printing/public/mojom/pdf_to_pwg_raster_converter.mojom.h"
+#include "chrome/services/printing/public/mojom/pdf_to_pwg_raster_converter.mojom-shared.h"
 #include "printing/mojom/print.mojom.h"
 #include "printing/pwg_raster_settings.h"
 
 namespace mojo {
 
 template <>
-struct EnumTraits<printing::mojom::PwgRasterSettings::TransformType,
+struct EnumTraits<printing::mojom::PwgRasterSettings_TransformType,
                   printing::PwgRasterTransformType> {
-  static printing::mojom::PwgRasterSettings::TransformType ToMojom(
+  static printing::mojom::PwgRasterSettings_TransformType ToMojom(
       printing::PwgRasterTransformType transform_type) {
     switch (transform_type) {
       case printing::PwgRasterTransformType::TRANSFORM_NORMAL:
-        return printing::mojom::PwgRasterSettings::TransformType::
+        return printing::mojom::PwgRasterSettings_TransformType::
             TRANSFORM_NORMAL;
       case printing::PwgRasterTransformType::TRANSFORM_ROTATE_180:
-        return printing::mojom::PwgRasterSettings::TransformType::
+        return printing::mojom::PwgRasterSettings_TransformType::
             TRANSFORM_ROTATE_180;
       case printing::PwgRasterTransformType::TRANSFORM_FLIP_HORIZONTAL:
-        return printing::mojom::PwgRasterSettings::TransformType::
+        return printing::mojom::PwgRasterSettings_TransformType::
             TRANSFORM_FLIP_HORIZONTAL;
       case printing::PwgRasterTransformType::TRANSFORM_FLIP_VERTICAL:
-        return printing::mojom::PwgRasterSettings::TransformType::
+        return printing::mojom::PwgRasterSettings_TransformType::
             TRANSFORM_FLIP_VERTICAL;
     }
     NOTREACHED() << "Unknown transform type "
                  << static_cast<int>(transform_type);
-    return printing::mojom::PwgRasterSettings::TransformType::TRANSFORM_NORMAL;
+    return printing::mojom::PwgRasterSettings_TransformType::TRANSFORM_NORMAL;
   }
 
-  static bool FromMojom(printing::mojom::PwgRasterSettings::TransformType input,
+  static bool FromMojom(printing::mojom::PwgRasterSettings_TransformType input,
                         printing::PwgRasterTransformType* output) {
     switch (input) {
-      case printing::mojom::PwgRasterSettings::TransformType::TRANSFORM_NORMAL:
+      case printing::mojom::PwgRasterSettings_TransformType::TRANSFORM_NORMAL:
         *output = printing::PwgRasterTransformType::TRANSFORM_NORMAL;
         return true;
-      case printing::mojom::PwgRasterSettings::TransformType::
+      case printing::mojom::PwgRasterSettings_TransformType::
           TRANSFORM_ROTATE_180:
         *output = printing::PwgRasterTransformType::TRANSFORM_ROTATE_180;
         return true;
-      case printing::mojom::PwgRasterSettings::TransformType::
+      case printing::mojom::PwgRasterSettings_TransformType::
           TRANSFORM_FLIP_HORIZONTAL:
         *output = printing::PwgRasterTransformType::TRANSFORM_FLIP_HORIZONTAL;
         return true;
-      case printing::mojom::PwgRasterSettings::TransformType::
+      case printing::mojom::PwgRasterSettings_TransformType::
           TRANSFORM_FLIP_VERTICAL:
         *output = printing::PwgRasterTransformType::TRANSFORM_FLIP_VERTICAL;
         return true;
@@ -61,34 +61,34 @@
 };
 
 template <>
-struct EnumTraits<printing::mojom::PwgRasterSettings::DuplexMode,
+struct EnumTraits<printing::mojom::PwgRasterSettings_DuplexMode,
                   printing::mojom::DuplexMode> {
-  static printing::mojom::PwgRasterSettings::DuplexMode ToMojom(
+  static printing::mojom::PwgRasterSettings_DuplexMode ToMojom(
       printing::mojom::DuplexMode duplex_mode) {
     switch (duplex_mode) {
       case printing::mojom::DuplexMode::kUnknownDuplexMode:
         break;
       case printing::mojom::DuplexMode::kSimplex:
-        return printing::mojom::PwgRasterSettings::DuplexMode::SIMPLEX;
+        return printing::mojom::PwgRasterSettings_DuplexMode::SIMPLEX;
       case printing::mojom::DuplexMode::kLongEdge:
-        return printing::mojom::PwgRasterSettings::DuplexMode::LONG_EDGE;
+        return printing::mojom::PwgRasterSettings_DuplexMode::LONG_EDGE;
       case printing::mojom::DuplexMode::kShortEdge:
-        return printing::mojom::PwgRasterSettings::DuplexMode::SHORT_EDGE;
+        return printing::mojom::PwgRasterSettings_DuplexMode::SHORT_EDGE;
     }
     NOTREACHED() << "Unknown duplex mode " << static_cast<int>(duplex_mode);
-    return printing::mojom::PwgRasterSettings::DuplexMode::SIMPLEX;
+    return printing::mojom::PwgRasterSettings_DuplexMode::SIMPLEX;
   }
 
-  static bool FromMojom(printing::mojom::PwgRasterSettings::DuplexMode input,
+  static bool FromMojom(printing::mojom::PwgRasterSettings_DuplexMode input,
                         printing::mojom::DuplexMode* output) {
     switch (input) {
-      case printing::mojom::PwgRasterSettings::DuplexMode::SIMPLEX:
+      case printing::mojom::PwgRasterSettings_DuplexMode::SIMPLEX:
         *output = printing::mojom::DuplexMode::kSimplex;
         return true;
-      case printing::mojom::PwgRasterSettings::DuplexMode::LONG_EDGE:
+      case printing::mojom::PwgRasterSettings_DuplexMode::LONG_EDGE:
         *output = printing::mojom::DuplexMode::kLongEdge;
         return true;
-      case printing::mojom::PwgRasterSettings::DuplexMode::SHORT_EDGE:
+      case printing::mojom::PwgRasterSettings_DuplexMode::SHORT_EDGE:
         *output = printing::mojom::DuplexMode::kShortEdge;
         return true;
     }
diff --git a/chrome/services/printing/public/mojom/typemaps.gni b/chrome/services/printing/public/mojom/typemaps.gni
deleted file mode 100644
index 4216d974..0000000
--- a/chrome/services/printing/public/mojom/typemaps.gni
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-typemaps = [
-  "//chrome/services/printing/public/mojom/pdf_render_settings.typemap",
-  "//chrome/services/printing/public/mojom/pdf_to_pwg_raster_converter.typemap",
-]
diff --git a/chrome/services/util_win/public/mojom/BUILD.gn b/chrome/services/util_win/public/mojom/BUILD.gn
index 1f34f8b..3afefe2 100644
--- a/chrome/services/util_win/public/mojom/BUILD.gn
+++ b/chrome/services/util_win/public/mojom/BUILD.gn
@@ -14,4 +14,40 @@
     "//mojo/public/mojom/base",
     "//ui/gfx/image/mojom",
   ]
+
+  cpp_typemaps = [
+    {
+      types = [
+        {
+          mojom = "chrome.mojom.AntiVirusProduct"
+          cpp = "::metrics::SystemProfileProto_AntiVirusProduct"
+        },
+        {
+          mojom = "chrome.mojom.CertificateType"
+          cpp = "::CertificateInfo::Type"
+        },
+        {
+          mojom = "chrome.mojom.FileFilterSpec"
+          cpp = "::ui::FileFilterSpec"
+        },
+        {
+          mojom = "chrome.mojom.InspectionResult"
+          cpp = "::ModuleInspectionResult"
+          move_only = true
+        },
+        {
+          mojom = "chrome.mojom.SelectFileDialogType"
+          cpp = "::ui::SelectFileDialog::Type"
+        },
+      ]
+      traits_headers = [ "util_win_mojom_traits.h" ]
+      traits_sources = [ "util_win_mojom_traits.cc" ]
+      traits_public_deps = [
+        "//base",
+        "//chrome/browser/win/conflicts:module_info",
+        "//third_party/metrics_proto",
+        "//ui/shell_dialogs",
+      ]
+    },
+  ]
 }
diff --git a/chrome/services/util_win/public/mojom/OWNERS b/chrome/services/util_win/public/mojom/OWNERS
index 743855d..1feb514 100644
--- a/chrome/services/util_win/public/mojom/OWNERS
+++ b/chrome/services/util_win/public/mojom/OWNERS
@@ -1,8 +1,4 @@
 per-file *.mojom=set noparent
 per-file *.mojom=file://ipc/SECURITY_OWNERS
-
-per-file *.typemap=set noparent
-per-file *.typemap=file://ipc/SECURITY_OWNERS
-
 per-file *_mojom_traits*.*=set noparent
 per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/chrome/services/util_win/public/mojom/util_win.typemap b/chrome/services/util_win/public/mojom/util_win.typemap
deleted file mode 100644
index a4d414b..0000000
--- a/chrome/services/util_win/public/mojom/util_win.typemap
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-mojom = "//chrome/services/util_win/public/mojom/util_win.mojom"
-
-public_headers = [
-  "//base/files/file_path.h",
-  "//base/strings/string16.h",
-  "//chrome/browser/win/conflicts/module_info_util.h",
-  "//chrome/browser/win/conflicts/module_info.h",
-  "//third_party/metrics_proto/system_profile.pb.h",
-  "//ui/shell_dialogs/execute_select_file_win.h",
-  "//ui/shell_dialogs/select_file_dialog.h",
-]
-traits_headers = [
-  "//ipc/ipc_message_utils.h",
-  "//chrome/services/util_win/public/mojom/util_win_mojom_traits.h",
-]
-sources = [
-  "//chrome/services/util_win/public/mojom/util_win_mojom_traits.cc",
-]
-
-deps = [
-  "//base",
-  "//chrome/browser/win/conflicts:module_info",
-  "//third_party/metrics_proto",
-  "//ui/shell_dialogs",
-]
-
-type_mappings = [
-  "chrome.mojom.AntiVirusProduct=::metrics::SystemProfileProto_AntiVirusProduct",
-  "chrome.mojom.CertificateType=::CertificateInfo::Type",
-  "chrome.mojom.FileFilterSpec=::ui::FileFilterSpec",
-  "chrome.mojom.InspectionResult=::ModuleInspectionResult[move_only]",
-  "chrome.mojom.SelectFileDialogType=::ui::SelectFileDialog::Type",
-]
diff --git a/chrome/services/util_win/public/mojom/util_win_mojom_traits.h b/chrome/services/util_win/public/mojom/util_win_mojom_traits.h
index f870522..db723c3 100644
--- a/chrome/services/util_win/public/mojom/util_win_mojom_traits.h
+++ b/chrome/services/util_win/public/mojom/util_win_mojom_traits.h
@@ -11,7 +11,7 @@
 #include "base/strings/string16.h"
 #include "chrome/browser/win/conflicts/module_info.h"
 #include "chrome/browser/win/conflicts/module_info_util.h"
-#include "chrome/services/util_win/public/mojom/util_win.mojom.h"
+#include "chrome/services/util_win/public/mojom/util_win.mojom-shared.h"
 #include "third_party/metrics_proto/system_profile.pb.h"
 #include "ui/shell_dialogs/execute_select_file_win.h"
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index b15108f7..0bcf9cc 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -113,8 +113,16 @@
   sources = [
     "../browser/autofill/automated_tests/cache_replayer.cc",
     "../browser/autofill/automated_tests/cache_replayer.h",
+    "../browser/notifications/notification_display_service_tester.cc",
+    "../browser/notifications/notification_display_service_tester.h",
     "../browser/permissions/crowd_deny_fake_safe_browsing_database_manager.cc",
     "../browser/permissions/crowd_deny_fake_safe_browsing_database_manager.h",
+    "../browser/search_engines/template_url_service_factory_test_util.cc",
+    "../browser/search_engines/template_url_service_factory_test_util.h",
+    "../browser/search_engines/template_url_service_test_util.cc",
+    "../browser/search_engines/template_url_service_test_util.h",
+    "../browser/signin/identity_test_environment_profile_adaptor.cc",
+    "../browser/signin/identity_test_environment_profile_adaptor.h",
     "base/chrome_render_view_host_test_harness.cc",
     "base/chrome_render_view_host_test_harness.h",
     "base/chrome_test_launcher.cc",
@@ -318,8 +326,12 @@
       "../browser/chromeos/arc/tracing/arc_app_performance_tracing_test_helper.h",
       "../browser/chromeos/file_manager/file_manager_test_util.cc",
       "../browser/chromeos/file_manager/file_manager_test_util.h",
+      "../browser/chromeos/login/users/fake_chrome_user_manager.cc",
+      "../browser/chromeos/login/users/fake_chrome_user_manager.h",
       "../browser/chromeos/ownership/fake_owner_settings_service.cc",
       "../browser/chromeos/ownership/fake_owner_settings_service.h",
+      "../browser/chromeos/settings/device_settings_test_helper.cc",
+      "../browser/chromeos/settings/device_settings_test_helper.h",
       "../browser/chromeos/settings/scoped_cros_settings_test_helper.cc",
       "../browser/chromeos/settings/scoped_cros_settings_test_helper.h",
       "../browser/component_updater/fake_cros_component_manager.cc",
@@ -348,6 +360,11 @@
       "//ui/aura:test_support",
       "//ui/base/ime/init",
     ]
+    deps += [
+      "//chromeos/cryptohome",
+      "//chromeos/dbus",
+      "//chromeos/dbus/power",
+    ]
   }
 
   if (is_win || is_mac || (is_linux && !is_chromeos)) {
@@ -398,6 +415,10 @@
       "../browser/extensions/extension_browsertest.h",
       "../browser/extensions/permissions_test_util.cc",
       "../browser/extensions/permissions_test_util.h",
+      "../browser/extensions/test_extension_environment.cc",
+      "../browser/extensions/test_extension_environment.h",
+      "../browser/extensions/test_extension_prefs.cc",
+      "../browser/extensions/test_extension_prefs.h",
       "../browser/ui/web_applications/test/ssl_test_utils.cc",
       "../browser/ui/web_applications/test/ssl_test_utils.h",
       "../browser/ui/web_applications/test/web_app_browsertest_util.cc",
@@ -3455,6 +3476,7 @@
     "../browser/page_load_metrics/observers/signed_exchange_page_load_metrics_observer_unittest.cc",
     "../browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer_unittest.cc",
     "../browser/page_load_metrics/observers/third_party_metrics_observer_unittest.cc",
+    "../browser/page_load_metrics/observers/translate_page_load_metrics_observer_unittest.cc",
     "../browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc",
     "../browser/paint_preview/services/paint_preview_demo_service_unittest.cc",
     "../browser/paint_preview/services/paint_preview_tab_service_unittest.cc",
@@ -5886,12 +5908,20 @@
     testonly = true
 
     sources = [
+      "../browser/interstitials/security_interstitial_idn_test.cc",
+      "../browser/interstitials/security_interstitial_idn_test.h",
+      "../browser/password_manager/password_manager_test_base.cc",
+      "../browser/password_manager/password_manager_test_base.h",
       "../browser/ssl/cert_verifier_browser_test.cc",
       "../browser/ssl/cert_verifier_browser_test.h",
+      "../browser/ssl/cert_verifier_platform_browser_test.cc",
+      "../browser/ssl/cert_verifier_platform_browser_test.h",
       "../browser/ui/search/instant_test_utils.cc",
       "../browser/ui/search/instant_test_utils.h",
       "../browser/ui/search/local_ntp_test_utils.cc",
       "../browser/ui/search/local_ntp_test_utils.h",
+      "../browser/ui/webui/signin/login_ui_test_utils.cc",
+      "../browser/ui/webui/signin/login_ui_test_utils.h",
       "../browser/web_applications/test/profile_test_helper.cc",
       "../browser/web_applications/test/profile_test_helper.h",
       "base/in_process_browser_test.cc",
diff --git a/chrome/test/android/test_support/src/org/chromium/chrome/test_support/PaymentRequestTestBridge.java b/chrome/test/android/test_support/src/org/chromium/chrome/test_support/PaymentRequestTestBridge.java
index d71f758..b1c99d1 100644
--- a/chrome/test/android/test_support/src/org/chromium/chrome/test_support/PaymentRequestTestBridge.java
+++ b/chrome/test/android/test_support/src/org/chromium/chrome/test_support/PaymentRequestTestBridge.java
@@ -7,12 +7,10 @@
 import android.os.Build;
 import android.text.TextUtils;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
-import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.payments.PaymentRequestFactory;
 import org.chromium.chrome.browser.payments.PaymentRequestImpl;
 import org.chromium.components.autofill.EditableOption;
@@ -33,7 +31,8 @@
      * about the state of the system, in order to control which paths should be tested in the
      * PaymentRequestImpl.
      */
-    private static class PaymentRequestDelegateForTest implements PaymentRequestImpl.Delegate {
+    private static class PaymentRequestDelegateForTest
+            implements ComponentPaymentRequestImpl.Delegate {
         private final boolean mIsOffTheRecord;
         private final boolean mIsValidSsl;
         private final boolean mIsWebContentsActive;
@@ -50,7 +49,7 @@
         }
 
         @Override
-        public boolean isOffTheRecord(WebContents webContents) {
+        public boolean isOffTheRecord() {
             return mIsOffTheRecord;
         }
 
@@ -61,7 +60,7 @@
         }
 
         @Override
-        public boolean isWebContentsActive(@NonNull ChromeActivity activity) {
+        public boolean isWebContentsActive() {
             return mIsWebContentsActive;
         }
 
@@ -77,7 +76,7 @@
 
         @Override
         @Nullable
-        public String getTwaPackageName(@Nullable ChromeActivity activity) {
+        public String getTwaPackageName() {
             return mTwaPackageName;
         }
     }
diff --git a/chrome/test/base/ui_test_utils.cc b/chrome/test/base/ui_test_utils.cc
index 555ee94..1eaed6b 100644
--- a/chrome/test/base/ui_test_utils.cc
+++ b/chrome/test/base/ui_test_utils.cc
@@ -396,7 +396,7 @@
   find_in_page::FindTabHelper* find_tab_helper =
       find_in_page::FindTabHelper::FromWebContents(tab);
   find_tab_helper->StartFinding(search_string, forward, match_case,
-                                true, /* find_next_if_selection_matches */
+                                true, /* find_match */
                                 true /* run_synchronously_for_testing */);
   FindResultWaiter observer(tab);
   observer.Wait();
diff --git a/chrome/test/data/web_apps/service_worker.js b/chrome/test/data/web_apps/service_worker.js
index 2e006aa..c7e8609 100644
--- a/chrome/test/data/web_apps/service_worker.js
+++ b/chrome/test/data/web_apps/service_worker.js
@@ -9,6 +9,7 @@
   'basic-48.png',
   'basic.html',
   'basic.json',
+  'no_service_worker.html',
 ];
 
 self.addEventListener('install', (event) => {
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index b53b30a..b464ca16 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -8,6 +8,7 @@
 import("//chrome/test/include_js_tests.gni")
 import("//third_party/closure_compiler/compile_js.gni")
 import("//ui/webui/resources/tools/js_modulizer.gni")
+import("//ui/webui/webui_features.gni")
 import("./namespace_rewrites.gni")
 
 if (include_js_tests) {
@@ -27,6 +28,10 @@
       "settings/cr_settings_v3_interactive_ui_tests.js",
     ]
 
+    if (enable_tab_search) {
+      sources += [ "tab_search/test/tab_search_interactive_ui_tests.js" ]
+    }
+
     gen_include_files = [
       "polymer_browser_test_base.js",
       "polymer_interactive_ui_test.js",
@@ -271,6 +276,7 @@
         "$root_gen_dir/chrome/test/data/webui/cr_components/chromeos/network/network_property_list_mojo_test.m.js",
         "$root_gen_dir/chrome/test/data/webui/cr_components/chromeos/network/network_proxy_exclusions_test.m.js",
         "$root_gen_dir/chrome/test/data/webui/cr_components/chromeos/network/network_proxy_input_test.m.js",
+        "$root_gen_dir/chrome/test/data/webui/cr_components/chromeos/network/network_proxy_test.m.js",
         "$root_gen_dir/chrome/test/data/webui/cr_components/chromeos/network/network_select_test.m.js",
         "$root_gen_dir/chrome/test/data/webui/cr_components/chromeos/network/network_siminfo_test.m.js",
         "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_searchable_drop_down_tests.m.js",
diff --git a/chrome/test/data/webui/chromeos/crostini_installer_app_test.js b/chrome/test/data/webui/chromeos/crostini_installer_app_test.js
index 7afe8f9..617eea1 100644
--- a/chrome/test/data/webui/chromeos/crostini_installer_app_test.js
+++ b/chrome/test/data/webui/chromeos/crostini_installer_app_test.js
@@ -149,7 +149,8 @@
     expectEquals(fakeBrowserProxy.handler.getCallCount('install'), 1);
     expectTrue(getInstallButton().hidden);
 
-    fakeBrowserProxy.page.onProgressUpdate(InstallerState.kStartConcierge, 0.5);
+    fakeBrowserProxy.page.onProgressUpdate(
+        InstallerState.kCreateDiskImage, 0.5);
     await flushTasks();
     expectTrue(
         !!app.$$('#installing-message > div').textContent.trim(),
diff --git a/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_browsertest.js b/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_browsertest.js
index 1422fcd..4c838e88 100644
--- a/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_browsertest.js
+++ b/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_browsertest.js
@@ -45,6 +45,7 @@
   ['NetworkPropertyListMojo', 'network/network_property_list_mojo_test.js', []],
   ['NetworkProxyExclusions', 'network/network_proxy_exclusions_test.js', []],
   ['NetworkProxyInput', 'network/network_proxy_input_test.js', []],
+  ['NetworkProxy', 'network/network_proxy_test.js', []],
   ['NetworkSiminfo', 'network/network_siminfo_test.js', []],
 ].forEach(test => registerTest('NetworkComponents', 'os-settings', ...test));
 
diff --git a/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_v3_browsertest.js b/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_v3_browsertest.js
index a606c92b..03162be 100644
--- a/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_v3_browsertest.js
+++ b/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_v3_browsertest.js
@@ -27,6 +27,7 @@
  ['NetworkPropertyListMojo', 'network/network_property_list_mojo_test.m.js'],
  ['NetworkProxyExclusions', 'network/network_proxy_exclusions_test.m.js'],
  ['NetworkProxyInput', 'network/network_proxy_input_test.m.js'],
+ ['NetworkProxy', 'network/network_proxy_test.m.js'],
  ['NetworkSelect', 'network/network_select_test.m.js'],
  ['NetworkSiminfo', 'network/network_siminfo_test.m.js'],
 ].forEach(test => registerTest('NetworkComponents', ...test));
diff --git a/chrome/test/data/webui/cr_components/chromeos/network/BUILD.gn b/chrome/test/data/webui/cr_components/chromeos/network/BUILD.gn
index 1e1678ad..4082fcf 100644
--- a/chrome/test/data/webui/cr_components/chromeos/network/BUILD.gn
+++ b/chrome/test/data/webui/cr_components/chromeos/network/BUILD.gn
@@ -23,10 +23,10 @@
     "network_property_list_mojo_test.js",
     "network_proxy_exclusions_test.js",
     "network_proxy_input_test.js",
+    "network_proxy_test.js",
     "network_select_test.js",
     "network_siminfo_test.js",
   ]
-  namespace_rewrites = [
-    "network_config.MojoInterfaceProviderImpl|MojoInterfaceProviderImpl",
-  ]
+  namespace_rewrites =
+      [ "network_config.MojoInterfaceProviderImpl|MojoInterfaceProviderImpl" ]
 }
diff --git a/chrome/test/data/webui/cr_components/chromeos/network/network_proxy_test.js b/chrome/test/data/webui/cr_components/chromeos/network/network_proxy_test.js
new file mode 100644
index 0000000..6f61737
--- /dev/null
+++ b/chrome/test/data/webui/cr_components/chromeos/network/network_proxy_test.js
@@ -0,0 +1,36 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// clang-format off
+// #import 'chrome://os-settings/strings.m.js';
+// #import 'chrome://resources/cr_components/chromeos/network/network_proxy.m.js';
+//
+// #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+// clang-format on
+
+suite('NetworkProxyTest', function() {
+  /** @type {!NetworkProxy|undefined} */
+  let netProxy;
+
+  setup(function() {
+    netProxy = document.createElement('network-proxy');
+    document.body.appendChild(netProxy);
+    Polymer.dom.flush();
+  });
+
+  test('Proxy select option change fires proxy-change event', function(done) {
+    let proxyType = netProxy.$.proxyType;
+
+    // Verify that changing the proxy type select option fires the proxy-change
+    // event with the new proxy type.
+    netProxy.addEventListener('proxy-change', function(e) {
+      assertEquals('WPAD', e.detail.type);
+      done();
+    });
+
+    // Simulate changing the proxy select option.
+    proxyType.value = 'WPAD';
+    proxyType.dispatchEvent(new Event('change'));
+  });
+});
diff --git a/chrome/typemaps.gni b/chrome/typemaps.gni
deleted file mode 100644
index b74bfe9..0000000
--- a/chrome/typemaps.gni
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-typemaps = [
-  "//chrome/common/search/search.typemap",
-  "//chrome/common/web_application_info_provider.typemap",
-  "//chrome/services/cups_proxy/public/mojom/proxy.typemap",
-  "//chrome/services/file_util/public/mojom/safe_archive_analyzer.typemap",
-  "//chrome/services/media_gallery_util/public/mojom/media_parser.typemap",
-  "//chrome/services/printing/public/mojom/pdf_render_settings.typemap",
-  "//chrome/services/printing/public/mojom/pdf_to_pwg_raster_converter.typemap",
-  "//chrome/services/util_win/public/mojom/util_win.typemap",
-]
diff --git a/chromeos/components/phonehub/BUILD.gn b/chromeos/components/phonehub/BUILD.gn
index 736d418..95f20a4d 100644
--- a/chromeos/components/phonehub/BUILD.gn
+++ b/chromeos/components/phonehub/BUILD.gn
@@ -68,6 +68,7 @@
     "//base",
     "//chromeos/components/multidevice",
     "//chromeos/components/multidevice/logging",
+    "//chromeos/components/phonehub/proto",
     "//chromeos/services/device_sync/public/cpp",
     "//chromeos/services/multidevice_setup/public/cpp",
     "//chromeos/services/secure_channel/public/cpp/client",
diff --git a/chromeos/components/phonehub/proto/BUILD.gn b/chromeos/components/phonehub/proto/BUILD.gn
new file mode 100644
index 0000000..4c1e43d
--- /dev/null
+++ b/chromeos/components/phonehub/proto/BUILD.gn
@@ -0,0 +1,9 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/protobuf/proto_library.gni")
+
+proto_library("proto") {
+  sources = [ "phonehub_api.proto" ]
+}
diff --git a/chromeos/components/phonehub/proto/phonehub_api.proto b/chromeos/components/phonehub/proto/phonehub_api.proto
new file mode 100644
index 0000000..0e417f15
--- /dev/null
+++ b/chromeos/components/phonehub/proto/phonehub_api.proto
@@ -0,0 +1,187 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+syntax = "proto3";
+
+package chromeos.phonehub.proto;
+
+option optimize_for = LITE_RUNTIME;
+
+enum MessageType {
+  PROVIDE_CROS_STATE = 0;
+  PHONE_STATUS_SNAPSHOT = 1;
+  PHONE_STATUS_UPDATE = 2;
+  UPDATE_NOTIFICATION_MODE_REQUEST = 3;
+  UPDATE_NOTIFICATION_MODE_RESPONSE = 4;
+  RING_DEVICE_REQUEST = 5;
+  RING_DEVICE_RESPONSE = 6;
+  UPDATE_BATTERY_MODE_REQUEST = 7;
+  UPDATE_BATTERY_MODE_RESPONSE = 8;
+  DISMISS_NOTIFICATION_REQUEST = 9;
+  DISMISS_NOTIFICATION_RESPONSE = 10;
+  NOTIFICATION_INLINE_REPLY_REQUEST = 11;
+  NOTIFICATION_INLINE_REPLY_RESPONSE = 12;
+  SHOW_NOTIFICATION_ACCESS_SETUP_REQUEST = 13;
+  SHOW_NOTIFICATION_ACCESS_SETUP_RESPONSE = 14;
+}
+
+enum NotificationSetting {
+  NOTIFICATIONS_OFF = 0;
+  NOTIFICATIONS_ON = 1;
+}
+
+enum ChargingState {
+  NOT_CHARGING = 0;
+  CHARGING_AC = 1;
+  CHARGING_USB = 2;
+  CHARGING_WIRELESS = 3;
+}
+
+enum BatteryMode {
+  BATTERY_SAVER_OFF = 0;
+  BATTERY_SAVER_ON = 1;
+}
+
+enum NotificationMode {
+  DO_NOT_DISTURB_OFF = 0;
+  DO_NOT_DISTURB_ON = 1;
+}
+
+enum NotificationAccessState {
+  ACCESS_NOT_GRANTED = 0;
+  ACCESS_GRANTED = 1;
+}
+
+enum FindMyDeviceRingStatus {
+  NOT_RINGING = 0;
+  RINGING = 1;
+}
+
+enum SignalStrength {
+  ZERO_BARS = 0;
+  ONE_BAR = 1;
+  TWO_BARS = 2;
+  THREE_BARS = 3;
+  FOUR_BARS = 4;
+}
+
+enum MobileConnectionState {
+  NO_SIM = 0;
+  SIM_BUT_NO_RECEPTION = 1;
+  SIM_WITH_RECEPTION = 2;
+}
+
+enum NotificationImportance {
+  UNSPECIFIED = 0;
+  NONE = 1;
+  MIN = 2;
+  LOW = 3;
+  DEFAULT = 4;
+  HIGH = 5;
+}
+
+message PhoneProperties {
+  int32 battery_percentage = 1;
+  ChargingState charging_state = 2;
+  BatteryMode battery_mode = 3;
+
+  // Note: If |connection_state| is not SIM_WITH_RECEPTION,
+  // |signal_strength| and |mobile_provider| should be ignored.
+  MobileConnectionState connection_state = 4;
+  SignalStrength signal_strength = 5;
+  string mobile_provider = 6;
+
+  NotificationMode notification_mode = 7;
+  NotificationAccessState notification_access_state = 8;
+
+  FindMyDeviceRingStatus ring_status = 9;
+}
+
+message App {
+  string package_name = 1;
+  string visible_name = 2;
+  bytes icon = 3;
+}
+
+message CrosState {
+  NotificationSetting notification_setting = 1;
+}
+
+message Action {
+  enum InputType {
+    UNKNOWN = 0;
+    TEXT = 1;
+    CONFIRMATION = 2;
+    OPEN = 3;
+    CANNED_REPLY = 4;
+  }
+
+  int64 id = 1;
+  string title = 2;
+  // Optional, but not specifying a type implies no response can be sent.
+  InputType type = 3;
+}
+
+message Notification {
+  int64 id = 1;
+  int64 epoch_time_millis = 2;
+  App origin_app = 3;
+  NotificationImportance importance = 4;
+  string title = 5;
+  string text_content = 6;
+  repeated Action actions = 7;
+
+  // Optionals:
+  bytes contact_image = 8;     // for messages
+  bytes background_image = 9;  // for media
+  bytes shared_image = 10;     // for messages
+}
+
+message PhoneStatusSnapshot {
+  PhoneProperties properties = 1;
+  repeated Notification notifications = 2;
+}
+
+message PhoneStatusUpdate {
+  PhoneProperties properties = 1;
+  // Notifications which have changed since the last update.
+  repeated Notification updated_notifications = 2;
+  // IDs of notification which have been removed since the last update.
+  repeated int64 removed_notification_ids = 3;
+}
+
+message UpdateNotificationModeRequest {
+  NotificationMode notification_mode = 1;
+}
+
+message UpdateNotificationModeResponse {}
+
+message RingDeviceRequest {
+  FindMyDeviceRingStatus ring_status = 1;
+}
+
+message RingDeviceResponse {}
+
+message UpdateBatteryModeRequest {
+  BatteryMode battery_mode = 1;
+}
+
+message UpdateBatteryModeResponse {}
+
+message DismissNotificationRequest {
+  int64 notification_id = 1;
+}
+
+message DismissNotificationResponse {}
+
+message NotificationInlineReplyRequest {
+  int64 notification_id = 1;
+  string reply_text = 2;
+}
+
+message NotificationInlineReplyResponse {}
+
+message ShowNotificationAccessSetupRequest {}
+
+message ShowNotificationAccessSetupResponse {}
diff --git a/chromeos/constants/chromeos_features.cc b/chromeos/constants/chromeos_features.cc
index 81a70e0..b6a6b05 100644
--- a/chromeos/constants/chromeos_features.cc
+++ b/chromeos/constants/chromeos_features.cc
@@ -55,12 +55,32 @@
 
 // Controls whether to enable assistive autocorrect.
 const base::Feature kAssistAutoCorrect{"AssistAutoCorrect",
-                                       base::FEATURE_DISABLED_BY_DEFAULT};
+                                       base::FEATURE_ENABLED_BY_DEFAULT};
 
-// Controls whether to enable assist personal information.
+// Controls whether to enable assistive personal information.
 const base::Feature kAssistPersonalInfo{"AssistPersonalInfo",
                                         base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Controls whether to suggest addresses in assistive personal information. This
+// is only effective when AssistPersonalInfo flag is enabled.
+const base::Feature kAssistPersonalInfoAddress{
+    "AssistPersonalInfoAddress", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Controls whether to suggest emails in assistive personal information. This is
+// only effective when AssistPersonalInfo flag is enabled.
+const base::Feature kAssistPersonalInfoEmail{"AssistPersonalInfoEmail",
+                                             base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Controls whether to suggest names in assistive personal information. This is
+// only effective when AssistPersonalInfo flag is enabled.
+const base::Feature kAssistPersonalInfoName{"AssistPersonalInfoName",
+                                            base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Controls whether to suggest phone numbers in assistive personal information.
+// This is only effective when AssistPersonalInfo flag is enabled.
+const base::Feature kAssistPersonalInfoPhoneNumber{
+    "AssistPersonalInfoPhoneNumber", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Displays the avatar toolbar button and the profile menu.
 // https://crbug.com/1041472
 extern const base::Feature kAvatarToolbarButton{
diff --git a/chromeos/constants/chromeos_features.h b/chromeos/constants/chromeos_features.h
index 3b7d1da4..4bf5f5f9 100644
--- a/chromeos/constants/chromeos_features.h
+++ b/chromeos/constants/chromeos_features.h
@@ -36,6 +36,14 @@
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 extern const base::Feature kAssistPersonalInfo;
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
+extern const base::Feature kAssistPersonalInfoAddress;
+COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
+extern const base::Feature kAssistPersonalInfoEmail;
+COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
+extern const base::Feature kAssistPersonalInfoName;
+COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
+extern const base::Feature kAssistPersonalInfoPhoneNumber;
+COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 extern const base::Feature kAvatarToolbarButton;
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 extern const base::Feature kBetterUpdateScreen;
diff --git a/chromeos/dbus/debug_daemon/debug_daemon_client.cc b/chromeos/dbus/debug_daemon/debug_daemon_client.cc
index 4ae7156..878c339 100644
--- a/chromeos/dbus/debug_daemon/debug_daemon_client.cc
+++ b/chromeos/dbus/debug_daemon/debug_daemon_client.cc
@@ -531,16 +531,6 @@
                        std::move(error_callback)));
   }
 
-  void StartConcierge(ConciergeCallback callback) override {
-    dbus::MethodCall method_call(debugd::kDebugdInterface,
-                                 debugd::kStartVmConcierge);
-    dbus::MessageWriter writer(&method_call);
-    debugdaemon_proxy_->CallMethod(
-        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
-        base::BindOnce(&DebugDaemonClientImpl::OnStartConcierge,
-                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-  }
-
   void StartPluginVmDispatcher(const std::string& owner_id,
                                const std::string& lang,
                                PluginVmDispatcherCallback callback) override {
@@ -870,15 +860,6 @@
       std::move(error_callback).Run();
   }
 
-  void OnStartConcierge(ConciergeCallback callback, dbus::Response* response) {
-    bool result = false;
-    if (response) {
-      dbus::MessageReader reader(response);
-      reader.PopBool(&result);
-    }
-    std::move(callback).Run(result);
-  }
-
   void OnStartPluginVmDispatcher(PluginVmDispatcherCallback callback,
                                  dbus::Response* response,
                                  dbus::ErrorResponse* error) {
diff --git a/chromeos/dbus/debug_daemon/debug_daemon_client.h b/chromeos/dbus/debug_daemon/debug_daemon_client.h
index bed3e4f..d493c10 100644
--- a/chromeos/dbus/debug_daemon/debug_daemon_client.h
+++ b/chromeos/dbus/debug_daemon/debug_daemon_client.h
@@ -235,14 +235,6 @@
                                  CupsRemovePrinterCallback callback,
                                  base::OnceClosure error_callback) = 0;
 
-  // A callback to handle the result of StartConcierge.
-  using ConciergeCallback = base::OnceCallback<void(bool success)>;
-  // Calls debugd::kStartVmConcierge, which starts the Concierge service.
-  // |callback| is called when the method finishes. If the |callback| is called
-  // with true, it is guaranteed that the service is ready to accept requests.
-  // It is not necessary for ConciergeClient to use WaitForServiceToBeAvailable.
-  virtual void StartConcierge(ConciergeCallback callback) = 0;
-
   // A callback to handle the result of
   // StartPluginVmDispatcher/StopPluginVmDispatcher.
   using PluginVmDispatcherCallback = base::OnceCallback<void(bool success)>;
diff --git a/chromeos/dbus/debug_daemon/fake_debug_daemon_client.cc b/chromeos/dbus/debug_daemon/fake_debug_daemon_client.cc
index a4d66a5e..5bda3a2 100644
--- a/chromeos/dbus/debug_daemon/fake_debug_daemon_client.cc
+++ b/chromeos/dbus/debug_daemon/fake_debug_daemon_client.cc
@@ -257,11 +257,6 @@
       FROM_HERE, base::BindOnce(std::move(callback), has_printer));
 }
 
-void FakeDebugDaemonClient::StartConcierge(ConciergeCallback callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), true));
-}
-
 void FakeDebugDaemonClient::StartPluginVmDispatcher(
     const std::string& /* owner_id */,
     const std::string& /* lang */,
diff --git a/chromeos/dbus/debug_daemon/fake_debug_daemon_client.h b/chromeos/dbus/debug_daemon/fake_debug_daemon_client.h
index 798a642a..069b356 100644
--- a/chromeos/dbus/debug_daemon/fake_debug_daemon_client.h
+++ b/chromeos/dbus/debug_daemon/fake_debug_daemon_client.h
@@ -88,7 +88,6 @@
   void CupsRemovePrinter(const std::string& name,
                          CupsRemovePrinterCallback callback,
                          base::OnceClosure error_callback) override;
-  void StartConcierge(ConciergeCallback callback) override;
   void StartPluginVmDispatcher(const std::string& owner_id,
                                const std::string& lang,
                                PluginVmDispatcherCallback callback) override;
diff --git a/chromeos/services/ime/ime_service.cc b/chromeos/services/ime/ime_service.cc
index 9de2d5c..f16c833 100644
--- a/chromeos/services/ime/ime_service.cc
+++ b/chromeos/services/ime/ime_service.cc
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/feature_list.h"
 #include "base/files/file_util.h"
 #include "base/location.h"
 #include "base/notreached.h"
@@ -99,6 +100,14 @@
   main_task_runner_->PostTask(FROM_HERE, base::BindOnce(task, task_id));
 }
 
+bool ImeService::IsFeatureEnabled(const char* feature_name) {
+  if (strcmp(feature_name, "SystemLatinPhysicalTyping") == 0) {
+    return base::FeatureList::IsEnabled(
+        chromeos::features::kSystemLatinPhysicalTyping);
+  }
+  return false;
+}
+
 int ImeService::SimpleDownloadToFile(const char* url,
                                      const char* file_path,
                                      SimpleDownloadCallback callback) {
diff --git a/chromeos/services/ime/ime_service.h b/chromeos/services/ime/ime_service.h
index 3879f638..91f10e7 100644
--- a/chromeos/services/ime/ime_service.h
+++ b/chromeos/services/ime/ime_service.h
@@ -53,6 +53,7 @@
                            SimpleDownloadCallback callback) override;
   ImeCrosDownloader* GetDownloader() override;
   void RunInMainSequence(ImeSequencedTask task, int task_id) override;
+  bool IsFeatureEnabled(const char* feature_name) override;
 
   // Callback used when a file download finishes by the |SimpleURLLoader|.
   // On failure, |file| will be empty.
diff --git a/chromeos/services/ime/public/cpp/shared_lib/interfaces.h b/chromeos/services/ime/public/cpp/shared_lib/interfaces.h
index 997ba02..b734c5f96 100644
--- a/chromeos/services/ime/public/cpp/shared_lib/interfaces.h
+++ b/chromeos/services/ime/public/cpp/shared_lib/interfaces.h
@@ -173,6 +173,9 @@
   // required to run in the thread creating its remote.
   virtual void RunInMainSequence(ImeSequencedTask task, int task_id) = 0;
 
+  // Returns whether a Chrome OS experimental feature is enabled or not.
+  virtual bool IsFeatureEnabled(const char* feature_name) = 0;
+
   // TODO(https://crbug.com/837156): Provide Logger for main entry.
 };
 
diff --git a/chromeos/services/secure_channel/BUILD.gn b/chromeos/services/secure_channel/BUILD.gn
index 525d03b..f61a673e 100644
--- a/chromeos/services/secure_channel/BUILD.gn
+++ b/chromeos/services/secure_channel/BUILD.gn
@@ -47,10 +47,6 @@
     "ble_scanner.h",
     "ble_scanner_impl.cc",
     "ble_scanner_impl.h",
-    "ble_service_data_helper.cc",
-    "ble_service_data_helper.h",
-    "ble_service_data_helper_impl.cc",
-    "ble_service_data_helper_impl.h",
     "ble_synchronizer.cc",
     "ble_synchronizer.h",
     "ble_synchronizer_base.cc",
@@ -62,6 +58,10 @@
     "ble_weave_packet_generator.h",
     "ble_weave_packet_receiver.cc",
     "ble_weave_packet_receiver.h",
+    "bluetooth_helper.cc",
+    "bluetooth_helper.h",
+    "bluetooth_helper_impl.cc",
+    "bluetooth_helper_impl.h",
     "channel_impl.cc",
     "channel_impl.h",
     "client_connection_parameters.cc",
@@ -195,10 +195,10 @@
     "fake_ble_connection_manager.h",
     "fake_ble_scanner.cc",
     "fake_ble_scanner.h",
-    "fake_ble_service_data_helper.cc",
-    "fake_ble_service_data_helper.h",
     "fake_ble_synchronizer.cc",
     "fake_ble_synchronizer.h",
+    "fake_bluetooth_helper.cc",
+    "fake_bluetooth_helper.h",
     "fake_channel.cc",
     "fake_channel.h",
     "fake_client_connection_parameters.cc",
@@ -270,11 +270,11 @@
     "ble_initiator_operation_unittest.cc",
     "ble_listener_operation_unittest.cc",
     "ble_scanner_impl_unittest.cc",
-    "ble_service_data_helper_impl_unittest.cc",
     "ble_synchronizer_unittest.cc",
     "ble_weave_client_connection_unittest.cc",
     "ble_weave_packet_generator_unittest.cc",
     "ble_weave_packet_receiver_unittest.cc",
+    "bluetooth_helper_impl_unittest.cc",
     "client_connection_parameters_impl_unittest.cc",
     "connect_to_device_operation_base_unittest.cc",
     "connection_attempt_base_unittest.cc",
diff --git a/chromeos/services/secure_channel/ble_advertisement_generator.h b/chromeos/services/secure_channel/ble_advertisement_generator.h
index 445192f..e8cbe8f 100644
--- a/chromeos/services/secure_channel/ble_advertisement_generator.h
+++ b/chromeos/services/secure_channel/ble_advertisement_generator.h
@@ -16,12 +16,6 @@
 class RemoteDeviceRef;
 }  // namespace multidevice
 
-namespace tether {
-class BleAdvertiserImplTest;
-class BleServiceDataHelperImplTest;
-class AdHocBleAdvertiserImplTest;
-}  // namespace tether
-
 namespace secure_channel {
 
 // Generates advertisements for the ProximityAuth BLE advertisement scheme.
@@ -45,10 +39,7 @@
 
  private:
   friend class SecureChannelBleAdvertisementGeneratorTest;
-  friend class SecureChannelBleServiceDataHelperImplTest;
-  friend class tether::BleAdvertiserImplTest;
-  friend class tether::BleServiceDataHelperImplTest;
-  friend class tether::AdHocBleAdvertiserImplTest;
+  friend class SecureChannelBluetoothHelperImplTest;
 
   static BleAdvertisementGenerator* instance_;
 
diff --git a/chromeos/services/secure_channel/ble_advertiser_impl.cc b/chromeos/services/secure_channel/ble_advertiser_impl.cc
index 504eb0f..76a31831 100644
--- a/chromeos/services/secure_channel/ble_advertiser_impl.cc
+++ b/chromeos/services/secure_channel/ble_advertiser_impl.cc
@@ -11,7 +11,7 @@
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/timer/timer.h"
 #include "chromeos/components/multidevice/logging/logging.h"
-#include "chromeos/services/secure_channel/ble_service_data_helper.h"
+#include "chromeos/services/secure_channel/bluetooth_helper.h"
 #include "chromeos/services/secure_channel/error_tolerant_ble_advertisement_impl.h"
 #include "chromeos/services/secure_channel/shared_resource_scheduler.h"
 #include "chromeos/services/secure_channel/timer_factory.h"
@@ -37,19 +37,19 @@
 // static
 std::unique_ptr<BleAdvertiser> BleAdvertiserImpl::Factory::Create(
     Delegate* delegate,
-    BleServiceDataHelper* ble_service_data_helper,
+    BluetoothHelper* bluetooth_helper,
     BleSynchronizerBase* ble_synchronizer_base,
     TimerFactory* timer_factory,
     scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner) {
   if (test_factory_) {
-    return test_factory_->CreateInstance(delegate, ble_service_data_helper,
+    return test_factory_->CreateInstance(delegate, bluetooth_helper,
                                          ble_synchronizer_base, timer_factory,
                                          sequenced_task_runner);
   }
 
-  return base::WrapUnique(new BleAdvertiserImpl(
-      delegate, ble_service_data_helper, ble_synchronizer_base, timer_factory,
-      sequenced_task_runner));
+  return base::WrapUnique(
+      new BleAdvertiserImpl(delegate, bluetooth_helper, ble_synchronizer_base,
+                            timer_factory, sequenced_task_runner));
 }
 
 // static
@@ -64,12 +64,12 @@
 
 BleAdvertiserImpl::BleAdvertiserImpl(
     Delegate* delegate,
-    BleServiceDataHelper* ble_service_data_helper,
+    BluetoothHelper* bluetooth_helper,
     BleSynchronizerBase* ble_synchronizer_base,
     TimerFactory* timer_factory,
     scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner)
     : BleAdvertiser(delegate),
-      ble_service_data_helper_(ble_service_data_helper),
+      bluetooth_helper_(bluetooth_helper),
       ble_synchronizer_base_(ble_synchronizer_base),
       timer_factory_(timer_factory),
       sequenced_task_runner_(sequenced_task_runner),
@@ -290,7 +290,7 @@
   const DeviceIdPair pair =
       active_advertisement_requests_[index_to_add]->device_id_pair;
   std::unique_ptr<DataWithTimestamp> service_data =
-      ble_service_data_helper_->GenerateForegroundAdvertisement(pair);
+      bluetooth_helper_->GenerateForegroundAdvertisement(pair);
 
   // If an advertisement could not be created, the request is immediately
   // removed. It's also tracked to prevent future operations from referencing
diff --git a/chromeos/services/secure_channel/ble_advertiser_impl.h b/chromeos/services/secure_channel/ble_advertiser_impl.h
index ec6f00dc..30e8e8b2 100644
--- a/chromeos/services/secure_channel/ble_advertiser_impl.h
+++ b/chromeos/services/secure_channel/ble_advertiser_impl.h
@@ -28,7 +28,7 @@
 
 namespace secure_channel {
 
-class BleServiceDataHelper;
+class BluetoothHelper;
 class BleSynchronizerBase;
 class ErrorTolerantBleAdvertisement;
 class SharedResourceScheduler;
@@ -56,7 +56,7 @@
    public:
     static std::unique_ptr<BleAdvertiser> Create(
         Delegate* delegate,
-        BleServiceDataHelper* ble_service_data_helper,
+        BluetoothHelper* bluetooth_helper,
         BleSynchronizerBase* ble_synchronizer_base,
         TimerFactory* timer_factory,
         scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner =
@@ -67,7 +67,7 @@
     virtual ~Factory();
     virtual std::unique_ptr<BleAdvertiser> CreateInstance(
         Delegate* delegate,
-        BleServiceDataHelper* ble_service_data_helper,
+        BluetoothHelper* bluetooth_helper,
         BleSynchronizerBase* ble_synchronizer_base,
         TimerFactory* timer_factory,
         scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner) = 0;
@@ -98,7 +98,7 @@
 
   BleAdvertiserImpl(
       Delegate* delegate,
-      BleServiceDataHelper* ble_service_data_helper,
+      BluetoothHelper* bluetooth_helper,
       BleSynchronizerBase* ble_synchronizer_base,
       TimerFactory* timer_factory,
       scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner);
@@ -132,7 +132,7 @@
   void AttemptToNotifyFailureToGenerateAdvertisement(
       const DeviceIdPair& device_id_pair);
 
-  BleServiceDataHelper* ble_service_data_helper_;
+  BluetoothHelper* bluetooth_helper_;
   BleSynchronizerBase* ble_synchronizer_base_;
   TimerFactory* timer_factory_;
 
diff --git a/chromeos/services/secure_channel/ble_advertiser_impl_unittest.cc b/chromeos/services/secure_channel/ble_advertiser_impl_unittest.cc
index a316aff..94d9eea 100644
--- a/chromeos/services/secure_channel/ble_advertiser_impl_unittest.cc
+++ b/chromeos/services/secure_channel/ble_advertiser_impl_unittest.cc
@@ -14,8 +14,8 @@
 #include "base/test/test_simple_task_runner.h"
 #include "chromeos/services/secure_channel/error_tolerant_ble_advertisement_impl.h"
 #include "chromeos/services/secure_channel/fake_ble_advertiser.h"
-#include "chromeos/services/secure_channel/fake_ble_service_data_helper.h"
 #include "chromeos/services/secure_channel/fake_ble_synchronizer.h"
+#include "chromeos/services/secure_channel/fake_bluetooth_helper.h"
 #include "chromeos/services/secure_channel/fake_error_tolerant_ble_advertisement.h"
 #include "chromeos/services/secure_channel/fake_one_shot_timer.h"
 #include "chromeos/services/secure_channel/fake_timer_factory.h"
@@ -31,9 +31,9 @@
     : public ErrorTolerantBleAdvertisementImpl::Factory {
  public:
   FakeErrorTolerantBleAdvertisementFactory(
-      BleServiceDataHelper* ble_service_data_helper,
+      BluetoothHelper* bluetooth_helper,
       BleSynchronizerBase* ble_synchronizer_base)
-      : ble_service_data_helper_(ble_service_data_helper),
+      : bluetooth_helper_(bluetooth_helper),
         ble_synchronizer_base_(ble_synchronizer_base) {}
   ~FakeErrorTolerantBleAdvertisementFactory() override = default;
 
@@ -54,9 +54,9 @@
       const DeviceIdPair& device_id_pair,
       std::unique_ptr<DataWithTimestamp> advertisement_data,
       BleSynchronizerBase* ble_synchronizer) override {
-    EXPECT_EQ(*ble_service_data_helper_->GenerateForegroundAdvertisement(
-                  device_id_pair),
-              *advertisement_data);
+    EXPECT_EQ(
+        *bluetooth_helper_->GenerateForegroundAdvertisement(device_id_pair),
+        *advertisement_data);
     EXPECT_EQ(ble_synchronizer_base_, ble_synchronizer);
 
     ++num_instances_created_;
@@ -82,7 +82,7 @@
     EXPECT_EQ(1u, num_deleted);
   }
 
-  BleServiceDataHelper* ble_service_data_helper_;
+  BluetoothHelper* bluetooth_helper_;
   BleSynchronizerBase* ble_synchronizer_base_;
 
   base::Optional<DeviceIdPair> last_created_device_id_pair_;
@@ -106,21 +106,20 @@
   // testing::Test:
   void SetUp() override {
     fake_delegate_ = std::make_unique<FakeBleAdvertiserDelegate>();
-    fake_ble_service_data_helper_ =
-        std::make_unique<FakeBleServiceDataHelper>();
+    fake_bluetooth_helper_ = std::make_unique<FakeBluetoothHelper>();
     fake_ble_synchronizer_ = std::make_unique<FakeBleSynchronizer>();
     fake_timer_factory_ = std::make_unique<FakeTimerFactory>();
 
     fake_advertisement_factory_ =
         std::make_unique<FakeErrorTolerantBleAdvertisementFactory>(
-            fake_ble_service_data_helper_.get(), fake_ble_synchronizer_.get());
+            fake_bluetooth_helper_.get(), fake_ble_synchronizer_.get());
     ErrorTolerantBleAdvertisementImpl::Factory::SetFactoryForTesting(
         fake_advertisement_factory_.get());
 
     test_runner_ = base::MakeRefCounted<base::TestSimpleTaskRunner>();
 
     advertiser_ = BleAdvertiserImpl::Factory::Create(
-        fake_delegate_.get(), fake_ble_service_data_helper_.get(),
+        fake_delegate_.get(), fake_bluetooth_helper_.get(),
         fake_ble_synchronizer_.get(), fake_timer_factory_.get(), test_runner_);
   }
 
@@ -194,7 +193,7 @@
       // Generate fake service data using the two device IDs.
       std::stringstream ss;
       ss << request.remote_device_id() << "+" << request.local_device_id();
-      fake_ble_service_data_helper_->SetAdvertisement(
+      fake_bluetooth_helper_->SetAdvertisement(
           request,
           DataWithTimestamp(ss.str() /* data */, kDefaultStartTimestamp,
                             kDefaultEndTimestamp));
@@ -257,15 +256,15 @@
 
   base::TestSimpleTaskRunner* test_runner() { return test_runner_.get(); }
   BleAdvertiser* advertiser() { return advertiser_.get(); }
-  FakeBleServiceDataHelper* fake_ble_service_data_helper() {
-    return fake_ble_service_data_helper_.get();
+  FakeBluetoothHelper* fake_bluetooth_helper() {
+    return fake_bluetooth_helper_.get();
   }
 
  private:
   base::test::TaskEnvironment task_environment_;
 
   std::unique_ptr<FakeBleAdvertiserDelegate> fake_delegate_;
-  std::unique_ptr<FakeBleServiceDataHelper> fake_ble_service_data_helper_;
+  std::unique_ptr<FakeBluetoothHelper> fake_bluetooth_helper_;
   std::unique_ptr<FakeBleSynchronizer> fake_ble_synchronizer_;
   std::unique_ptr<FakeTimerFactory> fake_timer_factory_;
 
diff --git a/chromeos/services/secure_channel/ble_connection_manager_impl.cc b/chromeos/services/secure_channel/ble_connection_manager_impl.cc
index 5450228..24d569ca 100644
--- a/chromeos/services/secure_channel/ble_connection_manager_impl.cc
+++ b/chromeos/services/secure_channel/ble_connection_manager_impl.cc
@@ -57,19 +57,19 @@
 // static
 std::unique_ptr<BleConnectionManager> BleConnectionManagerImpl::Factory::Create(
     scoped_refptr<device::BluetoothAdapter> bluetooth_adapter,
-    BleServiceDataHelper* ble_service_data_helper,
+    BluetoothHelper* bluetooth_helper,
     BleSynchronizerBase* ble_synchronizer,
     BleScanner* ble_scanner,
     TimerFactory* timer_factory,
     base::Clock* clock) {
   if (test_factory_) {
-    return test_factory_->CreateInstance(
-        bluetooth_adapter, ble_service_data_helper, ble_synchronizer,
-        ble_scanner, timer_factory, clock);
+    return test_factory_->CreateInstance(bluetooth_adapter, bluetooth_helper,
+                                         ble_synchronizer, ble_scanner,
+                                         timer_factory, clock);
   }
 
   return base::WrapUnique(new BleConnectionManagerImpl(
-      bluetooth_adapter, ble_service_data_helper, ble_synchronizer, ble_scanner,
+      bluetooth_adapter, bluetooth_helper, ble_synchronizer, ble_scanner,
       timer_factory, clock));
 }
 
@@ -206,7 +206,7 @@
 
 BleConnectionManagerImpl::BleConnectionManagerImpl(
     scoped_refptr<device::BluetoothAdapter> bluetooth_adapter,
-    BleServiceDataHelper* ble_service_data_helper,
+    BluetoothHelper* bluetooth_helper,
     BleSynchronizerBase* ble_synchronizer,
     BleScanner* ble_scanner,
     TimerFactory* timer_factory,
@@ -214,11 +214,10 @@
     : bluetooth_adapter_(bluetooth_adapter),
       clock_(clock),
       ble_scanner_(ble_scanner),
-      ble_advertiser_(
-          BleAdvertiserImpl::Factory::Create(this /* delegate */,
-                                             ble_service_data_helper,
-                                             ble_synchronizer,
-                                             timer_factory)),
+      ble_advertiser_(BleAdvertiserImpl::Factory::Create(this /* delegate */,
+                                                         bluetooth_helper,
+                                                         ble_synchronizer,
+                                                         timer_factory)),
       secure_channel_disconnector_(
           SecureChannelDisconnectorImpl::Factory::Create()) {
   ble_scanner_->AddObserver(this);
diff --git a/chromeos/services/secure_channel/ble_connection_manager_impl.h b/chromeos/services/secure_channel/ble_connection_manager_impl.h
index e7e3328..7ac2d9d 100644
--- a/chromeos/services/secure_channel/ble_connection_manager_impl.h
+++ b/chromeos/services/secure_channel/ble_connection_manager_impl.h
@@ -29,7 +29,7 @@
 
 namespace secure_channel {
 
-class BleServiceDataHelper;
+class BluetoothHelper;
 class BleSynchronizerBase;
 class SecureChannelDisconnector;
 class TimerFactory;
@@ -48,7 +48,7 @@
    public:
     static std::unique_ptr<BleConnectionManager> Create(
         scoped_refptr<device::BluetoothAdapter> bluetooth_adapter,
-        BleServiceDataHelper* ble_service_data_helper,
+        BluetoothHelper* bluetooth_helper,
         BleSynchronizerBase* ble_synchronizer,
         BleScanner* ble_scanner,
         TimerFactory* timer_factory,
@@ -59,7 +59,7 @@
     virtual ~Factory();
     virtual std::unique_ptr<BleConnectionManager> CreateInstance(
         scoped_refptr<device::BluetoothAdapter> bluetooth_adapter,
-        BleServiceDataHelper* ble_service_data_helper,
+        BluetoothHelper* bluetooth_helper,
         BleSynchronizerBase* ble_synchronizer,
         BleScanner* ble_scanner,
         TimerFactory* timer_factory,
@@ -106,7 +106,7 @@
 
   BleConnectionManagerImpl(
       scoped_refptr<device::BluetoothAdapter> bluetooth_adapter,
-      BleServiceDataHelper* ble_service_data_helper,
+      BluetoothHelper* bluetooth_helper,
       BleSynchronizerBase* ble_synchronizer,
       BleScanner* ble_scanner,
       TimerFactory* timer_factory,
diff --git a/chromeos/services/secure_channel/ble_connection_manager_impl_unittest.cc b/chromeos/services/secure_channel/ble_connection_manager_impl_unittest.cc
index 7fb883a..9caf783 100644
--- a/chromeos/services/secure_channel/ble_connection_manager_impl_unittest.cc
+++ b/chromeos/services/secure_channel/ble_connection_manager_impl_unittest.cc
@@ -26,8 +26,8 @@
 #include "chromeos/services/secure_channel/fake_authenticated_channel.h"
 #include "chromeos/services/secure_channel/fake_ble_advertiser.h"
 #include "chromeos/services/secure_channel/fake_ble_scanner.h"
-#include "chromeos/services/secure_channel/fake_ble_service_data_helper.h"
 #include "chromeos/services/secure_channel/fake_ble_synchronizer.h"
+#include "chromeos/services/secure_channel/fake_bluetooth_helper.h"
 #include "chromeos/services/secure_channel/fake_connection.h"
 #include "chromeos/services/secure_channel/fake_secure_channel_connection.h"
 #include "chromeos/services/secure_channel/fake_secure_channel_disconnector.h"
@@ -56,12 +56,10 @@
 
 class FakeBleAdvertiserFactory : public BleAdvertiserImpl::Factory {
  public:
-  FakeBleAdvertiserFactory(
-      FakeBleServiceDataHelper* expected_fake_ble_service_data_helper,
-      FakeBleSynchronizer* expected_fake_ble_synchronizer,
-      FakeTimerFactory* expected_fake_timer_factory)
-      : expected_fake_ble_service_data_helper_(
-            expected_fake_ble_service_data_helper),
+  FakeBleAdvertiserFactory(FakeBluetoothHelper* expected_fake_bluetooth_helper,
+                           FakeBleSynchronizer* expected_fake_ble_synchronizer,
+                           FakeTimerFactory* expected_fake_timer_factory)
+      : expected_fake_bluetooth_helper_(expected_fake_bluetooth_helper),
         expected_fake_ble_synchronizer_(expected_fake_ble_synchronizer),
         expected_fake_timer_factory_(expected_fake_timer_factory) {}
 
@@ -73,11 +71,11 @@
   // BleAdvertiserImpl::Factory:
   std::unique_ptr<BleAdvertiser> CreateInstance(
       BleAdvertiser::Delegate* delegate,
-      BleServiceDataHelper* ble_service_data_helper,
+      BluetoothHelper* bluetooth_helper,
       BleSynchronizerBase* ble_synchronizer_base,
       TimerFactory* timer_factory,
       scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner) override {
-    EXPECT_EQ(expected_fake_ble_service_data_helper_, ble_service_data_helper);
+    EXPECT_EQ(expected_fake_bluetooth_helper_, bluetooth_helper);
     EXPECT_EQ(expected_fake_ble_synchronizer_, ble_synchronizer_base);
     EXPECT_EQ(expected_fake_timer_factory_, timer_factory);
     EXPECT_FALSE(instance_);
@@ -89,7 +87,7 @@
 
   FakeBleAdvertiser* instance_ = nullptr;
 
-  FakeBleServiceDataHelper* expected_fake_ble_service_data_helper_;
+  FakeBluetoothHelper* expected_fake_bluetooth_helper_;
   FakeBleSynchronizer* expected_fake_ble_synchronizer_;
   FakeTimerFactory* expected_fake_timer_factory_;
 
@@ -259,8 +257,7 @@
     mock_adapter_ =
         base::MakeRefCounted<testing::NiceMock<device::MockBluetoothAdapter>>();
 
-    fake_ble_service_data_helper_ =
-        std::make_unique<FakeBleServiceDataHelper>();
+    fake_bluetooth_helper_ = std::make_unique<FakeBluetoothHelper>();
     fake_ble_synchronizer_ = std::make_unique<FakeBleSynchronizer>();
     fake_ble_scanner_ = std::make_unique<FakeBleScanner>();
 
@@ -270,7 +267,7 @@
     test_clock_->SetNow(base::Time::UnixEpoch());
 
     fake_ble_advertiser_factory_ = std::make_unique<FakeBleAdvertiserFactory>(
-        fake_ble_service_data_helper_.get(), fake_ble_synchronizer_.get(),
+        fake_bluetooth_helper_.get(), fake_ble_synchronizer_.get(),
         fake_timer_factory_.get());
     BleAdvertiserImpl::Factory::SetFactoryForTesting(
         fake_ble_advertiser_factory_.get());
@@ -296,7 +293,7 @@
         fake_authenticated_channel_factory_.get());
 
     manager_ = BleConnectionManagerImpl::Factory::Create(
-        mock_adapter_, fake_ble_service_data_helper_.get(),
+        mock_adapter_, fake_bluetooth_helper_.get(),
         fake_ble_synchronizer_.get(), fake_ble_scanner_.get(),
         fake_timer_factory_.get(), test_clock_.get());
   }
@@ -795,7 +792,7 @@
       fake_authenticated_channel_factory_;
 
   scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>> mock_adapter_;
-  std::unique_ptr<FakeBleServiceDataHelper> fake_ble_service_data_helper_;
+  std::unique_ptr<FakeBluetoothHelper> fake_bluetooth_helper_;
   std::unique_ptr<FakeBleSynchronizer> fake_ble_synchronizer_;
   std::unique_ptr<FakeBleScanner> fake_ble_scanner_;
   std::unique_ptr<FakeTimerFactory> fake_timer_factory_;
diff --git a/chromeos/services/secure_channel/ble_scanner_impl.cc b/chromeos/services/secure_channel/ble_scanner_impl.cc
index e2c932b..b1fcbbb 100644
--- a/chromeos/services/secure_channel/ble_scanner_impl.cc
+++ b/chromeos/services/secure_channel/ble_scanner_impl.cc
@@ -25,7 +25,7 @@
 
 namespace {
 
-// TODO(hansberry): Share this constant with BleServiceDataHelper.
+// TODO(hansberry): Share this constant with BluetoothHelper.
 const size_t kMinNumBytesInServiceData = 2;
 
 }  // namespace
@@ -35,16 +35,16 @@
 
 // static
 std::unique_ptr<BleScanner> BleScannerImpl::Factory::Create(
-    BleServiceDataHelper* service_data_helper,
+    BluetoothHelper* bluetooth_helper,
     BleSynchronizerBase* ble_synchronizer,
     scoped_refptr<device::BluetoothAdapter> adapter) {
   if (test_factory_) {
-    return test_factory_->CreateInstance(service_data_helper, ble_synchronizer,
+    return test_factory_->CreateInstance(bluetooth_helper, ble_synchronizer,
                                          adapter);
   }
 
   return base::WrapUnique(
-      new BleScannerImpl(service_data_helper, ble_synchronizer, adapter));
+      new BleScannerImpl(bluetooth_helper, ble_synchronizer, adapter));
 }
 
 // static
@@ -63,10 +63,10 @@
       device::BluetoothUUID(kAdvertisingServiceUuid));
 }
 
-BleScannerImpl::BleScannerImpl(BleServiceDataHelper* service_data_helper,
+BleScannerImpl::BleScannerImpl(BluetoothHelper* bluetooth_helper,
                                BleSynchronizerBase* ble_synchronizer,
                                scoped_refptr<device::BluetoothAdapter> adapter)
-    : service_data_helper_(service_data_helper),
+    : bluetooth_helper_(bluetooth_helper),
       ble_synchronizer_(ble_synchronizer),
       adapter_(adapter),
       service_data_provider_(std::make_unique<ServiceDataProvider>()) {
@@ -202,7 +202,7 @@
       base::WriteInto(&service_data_str, service_data->size() + 1);
   memcpy(string_contents_ptr, service_data->data(), service_data->size());
 
-  auto potential_result = service_data_helper_->IdentifyRemoteDevice(
+  auto potential_result = bluetooth_helper_->IdentifyRemoteDevice(
       service_data_str, GetAllDeviceIdPairs());
 
   // There was service data for the ProximityAuth UUID, but it did not apply to
@@ -217,7 +217,7 @@
 
 void BleScannerImpl::HandlePotentialScanResult(
     const std::string& service_data,
-    const BleServiceDataHelper::DeviceWithBackgroundBool& potential_result,
+    const BluetoothHelper::DeviceWithBackgroundBool& potential_result,
     device::BluetoothDevice* bluetooth_device) {
   std::vector<std::pair<ConnectionMedium, ConnectionRole>> results;
 
diff --git a/chromeos/services/secure_channel/ble_scanner_impl.h b/chromeos/services/secure_channel/ble_scanner_impl.h
index 8ec13bd..e46e15dc 100644
--- a/chromeos/services/secure_channel/ble_scanner_impl.h
+++ b/chromeos/services/secure_channel/ble_scanner_impl.h
@@ -12,7 +12,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "chromeos/services/secure_channel/ble_scanner.h"
-#include "chromeos/services/secure_channel/ble_service_data_helper.h"
+#include "chromeos/services/secure_channel/bluetooth_helper.h"
 #include "device/bluetooth/bluetooth_adapter.h"
 
 namespace device {
@@ -24,7 +24,7 @@
 
 namespace secure_channel {
 
-class BleServiceDataHelper;
+class BluetoothHelper;
 class BleSynchronizerBase;
 
 // Concrete BleScanner implementation.
@@ -34,7 +34,7 @@
   class Factory {
    public:
     static std::unique_ptr<BleScanner> Create(
-        BleServiceDataHelper* service_data_helper,
+        BluetoothHelper* bluetooth_helper,
         BleSynchronizerBase* ble_synchronizer,
         scoped_refptr<device::BluetoothAdapter> adapter);
     static void SetFactoryForTesting(Factory* test_factory);
@@ -42,7 +42,7 @@
    protected:
     virtual ~Factory();
     virtual std::unique_ptr<BleScanner> CreateInstance(
-        BleServiceDataHelper* service_data_helper,
+        BluetoothHelper* bluetooth_helper,
         BleSynchronizerBase* ble_synchronizer,
         scoped_refptr<device::BluetoothAdapter> adapter) = 0;
 
@@ -65,7 +65,7 @@
         device::BluetoothDevice* bluetooth_device);
   };
 
-  BleScannerImpl(BleServiceDataHelper* service_data_helper,
+  BleScannerImpl(BluetoothHelper* bluetooth_helper,
                  BleSynchronizerBase* ble_synchronizer,
                  scoped_refptr<device::BluetoothAdapter> adapter);
 
@@ -94,13 +94,13 @@
   void HandleDeviceUpdated(device::BluetoothDevice* bluetooth_device);
   void HandlePotentialScanResult(
       const std::string& service_data,
-      const BleServiceDataHelper::DeviceWithBackgroundBool& potential_result,
+      const BluetoothHelper::DeviceWithBackgroundBool& potential_result,
       device::BluetoothDevice* bluetooth_device);
 
   void SetServiceDataProviderForTesting(
       std::unique_ptr<ServiceDataProvider> service_data_provider);
 
-  BleServiceDataHelper* service_data_helper_;
+  BluetoothHelper* bluetooth_helper_;
   BleSynchronizerBase* ble_synchronizer_;
   scoped_refptr<device::BluetoothAdapter> adapter_;
 
diff --git a/chromeos/services/secure_channel/ble_scanner_impl_unittest.cc b/chromeos/services/secure_channel/ble_scanner_impl_unittest.cc
index c9e6d97..40abea97 100644
--- a/chromeos/services/secure_channel/ble_scanner_impl_unittest.cc
+++ b/chromeos/services/secure_channel/ble_scanner_impl_unittest.cc
@@ -17,8 +17,8 @@
 #include "chromeos/services/secure_channel/ble_constants.h"
 #include "chromeos/services/secure_channel/connection_role.h"
 #include "chromeos/services/secure_channel/fake_ble_scanner.h"
-#include "chromeos/services/secure_channel/fake_ble_service_data_helper.h"
 #include "chromeos/services/secure_channel/fake_ble_synchronizer.h"
+#include "chromeos/services/secure_channel/fake_bluetooth_helper.h"
 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
 #include "device/bluetooth/test/mock_bluetooth_device.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -89,16 +89,15 @@
   // testing::Test:
   void SetUp() override {
     fake_delegate_ = std::make_unique<FakeBleScannerObserver>();
-    fake_ble_service_data_helper_ =
-        std::make_unique<FakeBleServiceDataHelper>();
+    fake_bluetooth_helper_ = std::make_unique<FakeBluetoothHelper>();
     fake_ble_synchronizer_ = std::make_unique<FakeBleSynchronizer>();
 
     mock_adapter_ =
         base::MakeRefCounted<testing::NiceMock<device::MockBluetoothAdapter>>();
 
-    ble_scanner_ = BleScannerImpl::Factory::Create(
-        fake_ble_service_data_helper_.get(), fake_ble_synchronizer_.get(),
-        mock_adapter_);
+    ble_scanner_ = BleScannerImpl::Factory::Create(fake_bluetooth_helper_.get(),
+                                                   fake_ble_synchronizer_.get(),
+                                                   mock_adapter_);
     ble_scanner_->AddObserver(fake_delegate_.get());
 
     auto fake_service_data_provider =
@@ -186,7 +185,7 @@
     const std::vector<FakeBleScannerObserver::Result>& results =
         fake_delegate_->handled_scan_results();
 
-    fake_ble_service_data_helper_->SetIdentifiedDevice(
+    fake_bluetooth_helper_->SetIdentifiedDevice(
         service_data, expected_remote_device, is_background_advertisement);
 
     size_t num_results_before_call = results.size();
@@ -234,8 +233,8 @@
     return discovery_session_weak_ptr_.get();
   }
 
-  FakeBleServiceDataHelper* fake_ble_service_data_helper() {
-    return fake_ble_service_data_helper_.get();
+  FakeBluetoothHelper* fake_bluetooth_helper() {
+    return fake_bluetooth_helper_.get();
   }
 
   const multidevice::RemoteDeviceRefList& test_devices() {
@@ -269,7 +268,7 @@
   const multidevice::RemoteDeviceRefList test_devices_;
 
   std::unique_ptr<FakeBleScannerObserver> fake_delegate_;
-  std::unique_ptr<FakeBleServiceDataHelper> fake_ble_service_data_helper_;
+  std::unique_ptr<FakeBluetoothHelper> fake_bluetooth_helper_;
   std::unique_ptr<FakeBleSynchronizer> fake_ble_synchronizer_;
   scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>> mock_adapter_;
 
@@ -312,7 +311,7 @@
 
   // Set the device to be a foreground advertisement, even though the registered
   // role is listener.
-  fake_ble_service_data_helper()->SetIdentifiedDevice(
+  fake_bluetooth_helper()->SetIdentifiedDevice(
       "wrongRoleServiceData", test_devices()[0],
       false /* is_background_advertisement */);
 
diff --git a/chromeos/services/secure_channel/ble_service_data_helper.cc b/chromeos/services/secure_channel/bluetooth_helper.cc
similarity index 75%
rename from chromeos/services/secure_channel/ble_service_data_helper.cc
rename to chromeos/services/secure_channel/bluetooth_helper.cc
index 945f46b..5c0e52f 100644
--- a/chromeos/services/secure_channel/ble_service_data_helper.cc
+++ b/chromeos/services/secure_channel/bluetooth_helper.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/services/secure_channel/ble_service_data_helper.h"
+#include "chromeos/services/secure_channel/bluetooth_helper.h"
 
 #include "base/logging.h"
 #include "base/notreached.h"
@@ -12,12 +12,12 @@
 
 namespace secure_channel {
 
-BleServiceDataHelper::BleServiceDataHelper() = default;
+BluetoothHelper::BluetoothHelper() = default;
 
-BleServiceDataHelper::~BleServiceDataHelper() = default;
+BluetoothHelper::~BluetoothHelper() = default;
 
-base::Optional<BleServiceDataHelper::DeviceWithBackgroundBool>
-BleServiceDataHelper::IdentifyRemoteDevice(
+base::Optional<BluetoothHelper::DeviceWithBackgroundBool>
+BluetoothHelper::IdentifyRemoteDevice(
     const std::string& service_data,
     const DeviceIdPairSet& device_id_pair_set) {
   base::Optional<DeviceWithBackgroundBool>
@@ -34,7 +34,7 @@
       return potential_device_with_background_bool;
   }
 
-  PA_LOG(ERROR) << "BleServiceDataHelper::IdentifyRemoteDevice(): Identified "
+  PA_LOG(ERROR) << "BluetoothHelper::IdentifyRemoteDevice(): Identified "
                    "device was not present in the provided DeviceIdPairSet.";
   NOTREACHED();
   return base::nullopt;
diff --git a/chromeos/services/secure_channel/ble_service_data_helper.h b/chromeos/services/secure_channel/bluetooth_helper.h
similarity index 84%
rename from chromeos/services/secure_channel/ble_service_data_helper.h
rename to chromeos/services/secure_channel/bluetooth_helper.h
index 92b4f87..a9aeb438 100644
--- a/chromeos/services/secure_channel/ble_service_data_helper.h
+++ b/chromeos/services/secure_channel/bluetooth_helper.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMEOS_SERVICES_SECURE_CHANNEL_BLE_SERVICE_DATA_HELPER_H_
-#define CHROMEOS_SERVICES_SECURE_CHANNEL_BLE_SERVICE_DATA_HELPER_H_
+#ifndef CHROMEOS_SERVICES_SECURE_CHANNEL_BLUETOOTH_HELPER_H_
+#define CHROMEOS_SERVICES_SECURE_CHANNEL_BLUETOOTH_HELPER_H_
 
 #include <memory>
 #include <string>
@@ -22,9 +22,9 @@
 // Provides the ability to generate BLE advertisement service data and, given
 // service data that has been received in a BLE discovery session, identify the
 // device which sent the advertisement.
-class BleServiceDataHelper {
+class BluetoothHelper {
  public:
-  virtual ~BleServiceDataHelper();
+  virtual ~BluetoothHelper();
 
   // Generates service data to be used in a foreground BLE advertisement from
   // the device with ID |local_device_id| to the device with ID
@@ -44,17 +44,17 @@
       const DeviceIdPairSet& device_id_pair_set);
 
  protected:
-  BleServiceDataHelper();
+  BluetoothHelper();
 
   virtual base::Optional<DeviceWithBackgroundBool> PerformIdentifyRemoteDevice(
       const std::string& service_data,
       const DeviceIdPairSet& device_id_pair_set) = 0;
 
-  DISALLOW_COPY_AND_ASSIGN(BleServiceDataHelper);
+  DISALLOW_COPY_AND_ASSIGN(BluetoothHelper);
 };
 
 }  // namespace secure_channel
 
 }  // namespace chromeos
 
-#endif  // CHROMEOS_SERVICES_SECURE_CHANNEL_BLE_SERVICE_DATA_HELPER_H_
+#endif  // CHROMEOS_SERVICES_SECURE_CHANNEL_BLUETOOTH_HELPER_H_
diff --git a/chromeos/services/secure_channel/ble_service_data_helper_impl.cc b/chromeos/services/secure_channel/bluetooth_helper_impl.cc
similarity index 87%
rename from chromeos/services/secure_channel/ble_service_data_helper_impl.cc
rename to chromeos/services/secure_channel/bluetooth_helper_impl.cc
index e22ceaa..c0dca08 100644
--- a/chromeos/services/secure_channel/ble_service_data_helper_impl.cc
+++ b/chromeos/services/secure_channel/bluetooth_helper_impl.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/services/secure_channel/ble_service_data_helper_impl.h"
+#include "chromeos/services/secure_channel/bluetooth_helper_impl.h"
 
 #include "base/containers/flat_map.h"
 #include "base/memory/ptr_util.h"
@@ -35,36 +35,35 @@
 }  // namespace
 
 // static
-BleServiceDataHelperImpl::Factory*
-    BleServiceDataHelperImpl::Factory::test_factory_ = nullptr;
+BluetoothHelperImpl::Factory* BluetoothHelperImpl::Factory::test_factory_ =
+    nullptr;
 
 // static
-std::unique_ptr<BleServiceDataHelper> BleServiceDataHelperImpl::Factory::Create(
+std::unique_ptr<BluetoothHelper> BluetoothHelperImpl::Factory::Create(
     multidevice::RemoteDeviceCache* remote_device_cache) {
   if (test_factory_)
     return test_factory_->CreateInstance(remote_device_cache);
 
-  return base::WrapUnique(new BleServiceDataHelperImpl(remote_device_cache));
+  return base::WrapUnique(new BluetoothHelperImpl(remote_device_cache));
 }
 
 // static
-void BleServiceDataHelperImpl::Factory::SetFactoryForTesting(
-    Factory* test_factory) {
+void BluetoothHelperImpl::Factory::SetFactoryForTesting(Factory* test_factory) {
   test_factory_ = test_factory;
 }
 
-BleServiceDataHelperImpl::Factory::~Factory() = default;
+BluetoothHelperImpl::Factory::~Factory() = default;
 
-BleServiceDataHelperImpl::BleServiceDataHelperImpl(
+BluetoothHelperImpl::BluetoothHelperImpl(
     multidevice::RemoteDeviceCache* remote_device_cache)
     : remote_device_cache_(remote_device_cache),
       background_eid_generator_(std::make_unique<BackgroundEidGenerator>()),
       foreground_eid_generator_(std::make_unique<ForegroundEidGenerator>()) {}
 
-BleServiceDataHelperImpl::~BleServiceDataHelperImpl() = default;
+BluetoothHelperImpl::~BluetoothHelperImpl() = default;
 
 std::unique_ptr<DataWithTimestamp>
-BleServiceDataHelperImpl::GenerateForegroundAdvertisement(
+BluetoothHelperImpl::GenerateForegroundAdvertisement(
     const DeviceIdPair& device_id_pair) {
   base::Optional<multidevice::RemoteDeviceRef> local_device =
       remote_device_cache_->GetRemoteDevice(
@@ -92,8 +91,8 @@
       *remote_device, local_device->public_key());
 }
 
-base::Optional<BleServiceDataHelper::DeviceWithBackgroundBool>
-BleServiceDataHelperImpl::PerformIdentifyRemoteDevice(
+base::Optional<BluetoothHelper::DeviceWithBackgroundBool>
+BluetoothHelperImpl::PerformIdentifyRemoteDevice(
     const std::string& service_data,
     const DeviceIdPairSet& device_id_pair_set) {
   base::flat_map<std::string, std::vector<std::string>>
@@ -131,8 +130,8 @@
   return base::nullopt;
 }
 
-base::Optional<BleServiceDataHelper::DeviceWithBackgroundBool>
-BleServiceDataHelperImpl::PerformIdentifyRemoteDevice(
+base::Optional<BluetoothHelper::DeviceWithBackgroundBool>
+BluetoothHelperImpl::PerformIdentifyRemoteDevice(
     const std::string& service_data,
     const std::string& local_device_id,
     const std::vector<std::string>& remote_device_ids) {
@@ -178,14 +177,14 @@
   if (identified_device_id.empty())
     return base::nullopt;
 
-  return BleServiceDataHelper::DeviceWithBackgroundBool(
+  return BluetoothHelper::DeviceWithBackgroundBool(
       *remote_device_cache_->GetRemoteDevice(
           base::nullopt /* instance_id */,
           identified_device_id /* legacy_device_id */),
       is_background_advertisement);
 }
 
-void BleServiceDataHelperImpl::SetTestDoubles(
+void BluetoothHelperImpl::SetTestDoubles(
     std::unique_ptr<BackgroundEidGenerator> background_eid_generator,
     std::unique_ptr<ForegroundEidGenerator> foreground_eid_generator) {
   background_eid_generator_ = std::move(background_eid_generator);
diff --git a/chromeos/services/secure_channel/ble_service_data_helper_impl.h b/chromeos/services/secure_channel/bluetooth_helper_impl.h
similarity index 69%
rename from chromeos/services/secure_channel/ble_service_data_helper_impl.h
rename to chromeos/services/secure_channel/bluetooth_helper_impl.h
index 5f521ac..f3e6eda 100644
--- a/chromeos/services/secure_channel/ble_service_data_helper_impl.h
+++ b/chromeos/services/secure_channel/bluetooth_helper_impl.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMEOS_SERVICES_SECURE_CHANNEL_BLE_SERVICE_DATA_HELPER_IMPL_H_
-#define CHROMEOS_SERVICES_SECURE_CHANNEL_BLE_SERVICE_DATA_HELPER_IMPL_H_
+#ifndef CHROMEOS_SERVICES_SECURE_CHANNEL_BLUETOOTH_HELPER_IMPL_H_
+#define CHROMEOS_SERVICES_SECURE_CHANNEL_BLUETOOTH_HELPER_IMPL_H_
 
 #include <memory>
 #include <string>
@@ -11,7 +11,7 @@
 #include "base/macros.h"
 #include "base/optional.h"
 #include "chromeos/components/multidevice/remote_device_ref.h"
-#include "chromeos/services/secure_channel/ble_service_data_helper.h"
+#include "chromeos/services/secure_channel/bluetooth_helper.h"
 #include "chromeos/services/secure_channel/data_with_timestamp.h"
 
 namespace chromeos {
@@ -25,40 +25,40 @@
 class BackgroundEidGenerator;
 class ForegroundEidGenerator;
 
-// Concrete BleServiceDataHelper implementation.
-class BleServiceDataHelperImpl : public BleServiceDataHelper {
+// Concrete BluetoothHelper implementation.
+class BluetoothHelperImpl : public BluetoothHelper {
  public:
   class Factory {
    public:
-    static std::unique_ptr<BleServiceDataHelper> Create(
+    static std::unique_ptr<BluetoothHelper> Create(
         multidevice::RemoteDeviceCache* remote_device_cache);
     static void SetFactoryForTesting(Factory* test_factory);
 
    protected:
     virtual ~Factory();
-    virtual std::unique_ptr<BleServiceDataHelper> CreateInstance(
+    virtual std::unique_ptr<BluetoothHelper> CreateInstance(
         multidevice::RemoteDeviceCache* remote_device_cache) = 0;
 
    private:
     static Factory* test_factory_;
   };
 
-  ~BleServiceDataHelperImpl() override;
+  ~BluetoothHelperImpl() override;
 
  private:
-  friend class SecureChannelBleServiceDataHelperImplTest;
+  friend class SecureChannelBluetoothHelperImplTest;
 
-  explicit BleServiceDataHelperImpl(
+  explicit BluetoothHelperImpl(
       multidevice::RemoteDeviceCache* remote_device_cache);
 
-  // BleServiceDataHelper:
+  // BluetoothHelper:
   std::unique_ptr<DataWithTimestamp> GenerateForegroundAdvertisement(
       const DeviceIdPair& device_id_pair) override;
   base::Optional<DeviceWithBackgroundBool> PerformIdentifyRemoteDevice(
       const std::string& service_data,
       const DeviceIdPairSet& device_id_pair_set) override;
 
-  base::Optional<BleServiceDataHelper::DeviceWithBackgroundBool>
+  base::Optional<BluetoothHelper::DeviceWithBackgroundBool>
   PerformIdentifyRemoteDevice(
       const std::string& service_data,
       const std::string& local_device_id,
@@ -72,11 +72,11 @@
   std::unique_ptr<BackgroundEidGenerator> background_eid_generator_;
   std::unique_ptr<ForegroundEidGenerator> foreground_eid_generator_;
 
-  DISALLOW_COPY_AND_ASSIGN(BleServiceDataHelperImpl);
+  DISALLOW_COPY_AND_ASSIGN(BluetoothHelperImpl);
 };
 
 }  // namespace secure_channel
 
 }  // namespace chromeos
 
-#endif  // CHROMEOS_SERVICES_SECURE_CHANNEL_BLE_SERVICE_DATA_HELPER_IMPL_H_
+#endif  // CHROMEOS_SERVICES_SECURE_CHANNEL_BLUETOOTH_HELPER_IMPL_H_
diff --git a/chromeos/services/secure_channel/ble_service_data_helper_impl_unittest.cc b/chromeos/services/secure_channel/bluetooth_helper_impl_unittest.cc
similarity index 92%
rename from chromeos/services/secure_channel/ble_service_data_helper_impl_unittest.cc
rename to chromeos/services/secure_channel/bluetooth_helper_impl_unittest.cc
index 0cd317c..aeb1cd9 100644
--- a/chromeos/services/secure_channel/ble_service_data_helper_impl_unittest.cc
+++ b/chromeos/services/secure_channel/bluetooth_helper_impl_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/services/secure_channel/ble_service_data_helper_impl.h"
+#include "chromeos/services/secure_channel/bluetooth_helper_impl.h"
 
 #include <memory>
 
@@ -88,9 +88,9 @@
 
 }  // namespace
 
-class SecureChannelBleServiceDataHelperImplTest : public testing::Test {
+class SecureChannelBluetoothHelperImplTest : public testing::Test {
  protected:
-  SecureChannelBleServiceDataHelperImplTest()
+  SecureChannelBluetoothHelperImplTest()
       : test_local_device_1_(CreateLocalDevice(1)),
         test_local_device_2_(CreateLocalDevice(2)),
         test_remote_devices_(
@@ -104,7 +104,7 @@
                                 test_local_device_2_.GetDeviceId());
   }
 
-  ~SecureChannelBleServiceDataHelperImplTest() override = default;
+  ~SecureChannelBluetoothHelperImplTest() override = default;
 
   // testing::Test:
   void SetUp() override {
@@ -139,10 +139,9 @@
         });
     remote_device_cache_->SetRemoteDevices(devices);
 
-    helper_ =
-        BleServiceDataHelperImpl::Factory::Create(remote_device_cache_.get());
+    helper_ = BluetoothHelperImpl::Factory::Create(remote_device_cache_.get());
 
-    static_cast<BleServiceDataHelperImpl*>(helper_.get())
+    static_cast<BluetoothHelperImpl*>(helper_.get())
         ->SetTestDoubles(std::move(fake_background_eid_generator),
                          std::move(mock_foreground_eid_generator));
   }
@@ -158,7 +157,7 @@
 
   std::unique_ptr<multidevice::RemoteDeviceCache> remote_device_cache_;
 
-  std::unique_ptr<BleServiceDataHelper> helper_;
+  std::unique_ptr<BluetoothHelper> helper_;
 
   multidevice::RemoteDeviceRef test_local_device_1_;
   multidevice::RemoteDeviceRef test_local_device_2_;
@@ -168,10 +167,10 @@
   DataWithTimestamp fake_advertisement_;
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(SecureChannelBleServiceDataHelperImplTest);
+  DISALLOW_COPY_AND_ASSIGN(SecureChannelBluetoothHelperImplTest);
 };
 
-TEST_F(SecureChannelBleServiceDataHelperImplTest,
+TEST_F(SecureChannelBluetoothHelperImplTest,
        TestGenerateForegroundAdvertisement_CannotGenerateAdvertisement) {
   fake_ble_advertisement_generator_->set_advertisement(nullptr);
   EXPECT_FALSE(helper_->GenerateForegroundAdvertisement(
@@ -179,7 +178,7 @@
                    test_local_device_1_.GetDeviceId() /* local_device_id */)));
 }
 
-TEST_F(SecureChannelBleServiceDataHelperImplTest,
+TEST_F(SecureChannelBluetoothHelperImplTest,
        TestGenerateForegroundAdvertisement) {
   auto data_with_timestamp = helper_->GenerateForegroundAdvertisement(
       DeviceIdPair(test_remote_devices_[0].GetDeviceId() /* remote_device_id */,
@@ -187,21 +186,21 @@
   EXPECT_EQ(fake_advertisement_, *data_with_timestamp);
 }
 
-TEST_F(SecureChannelBleServiceDataHelperImplTest,
+TEST_F(SecureChannelBluetoothHelperImplTest,
        TestGenerateForegroundAdvertisement_InvalidLocalDevice) {
   EXPECT_FALSE(helper_->GenerateForegroundAdvertisement(
       DeviceIdPair(test_remote_devices_[0].GetDeviceId() /* remote_device_id */,
                    "invalid local device id" /* local_device_id */)));
 }
 
-TEST_F(SecureChannelBleServiceDataHelperImplTest,
+TEST_F(SecureChannelBluetoothHelperImplTest,
        TestGenerateForegroundAdvertisement_InvalidRemoteDevice) {
   EXPECT_FALSE(helper_->GenerateForegroundAdvertisement(
       DeviceIdPair("invalid remote device id" /* remote_device_id */,
                    test_local_device_1_.GetDeviceId() /* local_device_id */)));
 }
 
-TEST_F(SecureChannelBleServiceDataHelperImplTest,
+TEST_F(SecureChannelBluetoothHelperImplTest,
        TestIdentifyRemoteDevice_InvalidAdvertisementLength) {
   std::string invalid_service_data = "a";
   mock_foreground_eid_generator_->set_identified_device_id(
@@ -215,7 +214,7 @@
   EXPECT_FALSE(device_with_background_bool);
 }
 
-TEST_F(SecureChannelBleServiceDataHelperImplTest,
+TEST_F(SecureChannelBluetoothHelperImplTest,
        TestIdentifyRemoteDevice_ForegroundAdvertisement) {
   std::string valid_service_data_for_registered_device = "abcde";
   ASSERT_TRUE(valid_service_data_for_registered_device.size() >=
@@ -246,7 +245,7 @@
   EXPECT_FALSE(device_with_background_bool->second);
 }
 
-TEST_F(SecureChannelBleServiceDataHelperImplTest,
+TEST_F(SecureChannelBluetoothHelperImplTest,
        TestIdentifyRemoteDevice_ForegroundAdvertisement_NoRegisteredDevice) {
   std::string valid_service_data = "abcde";
   ASSERT_TRUE(valid_service_data.size() >=
@@ -260,7 +259,7 @@
   EXPECT_FALSE(device_with_background_bool);
 }
 
-TEST_F(SecureChannelBleServiceDataHelperImplTest,
+TEST_F(SecureChannelBluetoothHelperImplTest,
        TestIdentifyRemoteDevice_BackgroundAdvertisement) {
   std::string valid_service_data_for_registered_device = "ab";
   ASSERT_TRUE(valid_service_data_for_registered_device.size() >=
@@ -291,7 +290,7 @@
   EXPECT_TRUE(device_with_background_bool->second);
 }
 
-TEST_F(SecureChannelBleServiceDataHelperImplTest,
+TEST_F(SecureChannelBluetoothHelperImplTest,
        TestIdentifyRemoteDevice_BackgroundAdvertisement_NoRegisteredDevice) {
   std::string valid_service_data_for_registered_device = "ab";
   ASSERT_TRUE(valid_service_data_for_registered_device.size() >=
diff --git a/chromeos/services/secure_channel/fake_ble_service_data_helper.cc b/chromeos/services/secure_channel/fake_bluetooth_helper.cc
similarity index 73%
rename from chromeos/services/secure_channel/fake_ble_service_data_helper.cc
rename to chromeos/services/secure_channel/fake_bluetooth_helper.cc
index f2687d3..0b92899 100644
--- a/chromeos/services/secure_channel/fake_ble_service_data_helper.cc
+++ b/chromeos/services/secure_channel/fake_bluetooth_helper.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/services/secure_channel/fake_ble_service_data_helper.h"
+#include "chromeos/services/secure_channel/fake_bluetooth_helper.h"
 
 #include "base/stl_util.h"
 
@@ -10,22 +10,22 @@
 
 namespace secure_channel {
 
-FakeBleServiceDataHelper::FakeBleServiceDataHelper() = default;
+FakeBluetoothHelper::FakeBluetoothHelper() = default;
 
-FakeBleServiceDataHelper::~FakeBleServiceDataHelper() = default;
+FakeBluetoothHelper::~FakeBluetoothHelper() = default;
 
-void FakeBleServiceDataHelper::SetAdvertisement(
+void FakeBluetoothHelper::SetAdvertisement(
     const DeviceIdPair& device_id_pair,
     const DataWithTimestamp& service_data) {
   device_id_pair_to_service_data_map_.insert({device_id_pair, service_data});
 }
 
-void FakeBleServiceDataHelper::RemoveAdvertisement(
+void FakeBluetoothHelper::RemoveAdvertisement(
     const DeviceIdPair& device_id_pair) {
   device_id_pair_to_service_data_map_.erase(device_id_pair);
 }
 
-void FakeBleServiceDataHelper::SetIdentifiedDevice(
+void FakeBluetoothHelper::SetIdentifiedDevice(
     const std::string& service_data,
     multidevice::RemoteDeviceRef identified_device,
     bool is_background_advertisement) {
@@ -35,7 +35,7 @@
 }
 
 std::unique_ptr<DataWithTimestamp>
-FakeBleServiceDataHelper::GenerateForegroundAdvertisement(
+FakeBluetoothHelper::GenerateForegroundAdvertisement(
     const DeviceIdPair& device_id_pair) {
   if (!base::Contains(device_id_pair_to_service_data_map_, device_id_pair))
     return nullptr;
@@ -44,8 +44,8 @@
       device_id_pair_to_service_data_map_.at(device_id_pair));
 }
 
-base::Optional<BleServiceDataHelper::DeviceWithBackgroundBool>
-FakeBleServiceDataHelper::PerformIdentifyRemoteDevice(
+base::Optional<BluetoothHelper::DeviceWithBackgroundBool>
+FakeBluetoothHelper::PerformIdentifyRemoteDevice(
     const std::string& service_data,
     const DeviceIdPairSet& device_id_pair_set) {
   if (!base::Contains(service_data_to_device_with_background_bool_map_,
diff --git a/chromeos/services/secure_channel/fake_ble_service_data_helper.h b/chromeos/services/secure_channel/fake_bluetooth_helper.h
similarity index 74%
rename from chromeos/services/secure_channel/fake_ble_service_data_helper.h
rename to chromeos/services/secure_channel/fake_bluetooth_helper.h
index 11e0dc3b..f028d81 100644
--- a/chromeos/services/secure_channel/fake_ble_service_data_helper.h
+++ b/chromeos/services/secure_channel/fake_bluetooth_helper.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMEOS_SERVICES_SECURE_CHANNEL_FAKE_BLE_SERVICE_DATA_HELPER_H_
-#define CHROMEOS_SERVICES_SECURE_CHANNEL_FAKE_BLE_SERVICE_DATA_HELPER_H_
+#ifndef CHROMEOS_SERVICES_SECURE_CHANNEL_FAKE_BLUETOOTH_HELPER_H_
+#define CHROMEOS_SERVICES_SECURE_CHANNEL_FAKE_BLUETOOTH_HELPER_H_
 
 #include <memory>
 #include <string>
@@ -13,18 +13,18 @@
 #include "base/macros.h"
 #include "base/optional.h"
 #include "chromeos/components/multidevice/remote_device_ref.h"
-#include "chromeos/services/secure_channel/ble_service_data_helper.h"
+#include "chromeos/services/secure_channel/bluetooth_helper.h"
 #include "chromeos/services/secure_channel/data_with_timestamp.h"
 
 namespace chromeos {
 
 namespace secure_channel {
 
-// Test BleServiceDataHelper implementation.
-class FakeBleServiceDataHelper : public BleServiceDataHelper {
+// Test BluetoothHelper implementation.
+class FakeBluetoothHelper : public BluetoothHelper {
  public:
-  FakeBleServiceDataHelper();
-  ~FakeBleServiceDataHelper() override;
+  FakeBluetoothHelper();
+  ~FakeBluetoothHelper() override;
 
   // Sets the data to be returned by a GenerateForegroundAdvertisement() call.
   void SetAdvertisement(const DeviceIdPair& device_id_pair,
@@ -38,7 +38,7 @@
                            bool is_background_advertisement);
 
  private:
-  // BleServiceDataHelper:
+  // BluetoothHelper:
   std::unique_ptr<DataWithTimestamp> GenerateForegroundAdvertisement(
       const DeviceIdPair& device_id_pair) override;
   base::Optional<DeviceWithBackgroundBool> PerformIdentifyRemoteDevice(
@@ -51,11 +51,11 @@
   std::unordered_map<std::string, DeviceWithBackgroundBool>
       service_data_to_device_with_background_bool_map_;
 
-  DISALLOW_COPY_AND_ASSIGN(FakeBleServiceDataHelper);
+  DISALLOW_COPY_AND_ASSIGN(FakeBluetoothHelper);
 };
 
 }  // namespace secure_channel
 
 }  // namespace chromeos
 
-#endif  // CHROMEOS_SERVICES_SECURE_CHANNEL_FAKE_BLE_SERVICE_DATA_HELPER_H_
+#endif  // CHROMEOS_SERVICES_SECURE_CHANNEL_FAKE_BLUETOOTH_HELPER_H_
diff --git a/chromeos/services/secure_channel/secure_channel_impl.cc b/chromeos/services/secure_channel/secure_channel_impl.cc
index e190178..5c61668 100644
--- a/chromeos/services/secure_channel/secure_channel_impl.cc
+++ b/chromeos/services/secure_channel/secure_channel_impl.cc
@@ -14,8 +14,8 @@
 #include "chromeos/services/secure_channel/authenticated_channel.h"
 #include "chromeos/services/secure_channel/ble_connection_manager_impl.h"
 #include "chromeos/services/secure_channel/ble_scanner_impl.h"
-#include "chromeos/services/secure_channel/ble_service_data_helper_impl.h"
 #include "chromeos/services/secure_channel/ble_synchronizer.h"
+#include "chromeos/services/secure_channel/bluetooth_helper_impl.h"
 #include "chromeos/services/secure_channel/client_connection_parameters_impl.h"
 #include "chromeos/services/secure_channel/device_id_pair.h"
 #include "chromeos/services/secure_channel/pending_connection_manager_impl.h"
@@ -68,19 +68,18 @@
     : bluetooth_adapter_(std::move(bluetooth_adapter)),
       timer_factory_(TimerFactoryImpl::Factory::Create()),
       remote_device_cache_(multidevice::RemoteDeviceCache::Factory::Create()),
-      ble_service_data_helper_(BleServiceDataHelperImpl::Factory::Create(
-          remote_device_cache_.get())),
+      bluetooth_helper_(
+          BluetoothHelperImpl::Factory::Create(remote_device_cache_.get())),
       ble_synchronizer_(BleSynchronizer::Factory::Create(bluetooth_adapter_)),
-      ble_scanner_(
-          BleScannerImpl::Factory::Create(ble_service_data_helper_.get(),
-                                          ble_synchronizer_.get(),
-                                          bluetooth_adapter_)),
-      ble_connection_manager_(BleConnectionManagerImpl::Factory::Create(
-          bluetooth_adapter_,
-          ble_service_data_helper_.get(),
-          ble_synchronizer_.get(),
-          ble_scanner_.get(),
-          timer_factory_.get())),
+      ble_scanner_(BleScannerImpl::Factory::Create(bluetooth_helper_.get(),
+                                                   ble_synchronizer_.get(),
+                                                   bluetooth_adapter_)),
+      ble_connection_manager_(
+          BleConnectionManagerImpl::Factory::Create(bluetooth_adapter_,
+                                                    bluetooth_helper_.get(),
+                                                    ble_synchronizer_.get(),
+                                                    ble_scanner_.get(),
+                                                    timer_factory_.get())),
       pending_connection_manager_(PendingConnectionManagerImpl::Factory::Create(
           this /* delegate */,
           ble_connection_manager_.get(),
diff --git a/chromeos/services/secure_channel/secure_channel_impl.h b/chromeos/services/secure_channel/secure_channel_impl.h
index 4b3d2aa..0c88f32 100644
--- a/chromeos/services/secure_channel/secure_channel_impl.h
+++ b/chromeos/services/secure_channel/secure_channel_impl.h
@@ -30,7 +30,7 @@
 
 class BleConnectionManager;
 class BleScanner;
-class BleServiceDataHelper;
+class BluetoothHelper;
 class BleSynchronizerBase;
 class TimerFactory;
 
@@ -174,7 +174,7 @@
   scoped_refptr<device::BluetoothAdapter> bluetooth_adapter_;
   std::unique_ptr<TimerFactory> timer_factory_;
   std::unique_ptr<multidevice::RemoteDeviceCache> remote_device_cache_;
-  std::unique_ptr<BleServiceDataHelper> ble_service_data_helper_;
+  std::unique_ptr<BluetoothHelper> bluetooth_helper_;
   std::unique_ptr<BleSynchronizerBase> ble_synchronizer_;
   std::unique_ptr<BleScanner> ble_scanner_;
   std::unique_ptr<BleConnectionManager> ble_connection_manager_;
diff --git a/chromeos/services/secure_channel/secure_channel_service_unittest.cc b/chromeos/services/secure_channel/secure_channel_service_unittest.cc
index 68274fd..4d33253 100644
--- a/chromeos/services/secure_channel/secure_channel_service_unittest.cc
+++ b/chromeos/services/secure_channel/secure_channel_service_unittest.cc
@@ -17,15 +17,15 @@
 #include "chromeos/services/secure_channel/active_connection_manager_impl.h"
 #include "chromeos/services/secure_channel/ble_connection_manager_impl.h"
 #include "chromeos/services/secure_channel/ble_scanner_impl.h"
-#include "chromeos/services/secure_channel/ble_service_data_helper_impl.h"
 #include "chromeos/services/secure_channel/ble_synchronizer.h"
+#include "chromeos/services/secure_channel/bluetooth_helper_impl.h"
 #include "chromeos/services/secure_channel/client_connection_parameters_impl.h"
 #include "chromeos/services/secure_channel/fake_active_connection_manager.h"
 #include "chromeos/services/secure_channel/fake_authenticated_channel.h"
 #include "chromeos/services/secure_channel/fake_ble_connection_manager.h"
 #include "chromeos/services/secure_channel/fake_ble_scanner.h"
-#include "chromeos/services/secure_channel/fake_ble_service_data_helper.h"
 #include "chromeos/services/secure_channel/fake_ble_synchronizer.h"
+#include "chromeos/services/secure_channel/fake_bluetooth_helper.h"
 #include "chromeos/services/secure_channel/fake_client_connection_parameters.h"
 #include "chromeos/services/secure_channel/fake_connection_delegate.h"
 #include "chromeos/services/secure_channel/fake_pending_connection_manager.h"
@@ -96,35 +96,34 @@
   DISALLOW_COPY_AND_ASSIGN(TestRemoteDeviceCacheFactory);
 };
 
-class FakeBleServiceDataHelperFactory
-    : public BleServiceDataHelperImpl::Factory {
+class FakeBluetoothHelperFactory : public BluetoothHelperImpl::Factory {
  public:
-  FakeBleServiceDataHelperFactory(
+  FakeBluetoothHelperFactory(
       TestRemoteDeviceCacheFactory* test_remote_device_cache_factory)
       : test_remote_device_cache_factory_(test_remote_device_cache_factory) {}
 
-  ~FakeBleServiceDataHelperFactory() override = default;
+  ~FakeBluetoothHelperFactory() override = default;
 
-  FakeBleServiceDataHelper* instance() { return instance_; }
+  FakeBluetoothHelper* instance() { return instance_; }
 
  private:
-  // BleServiceDataHelperImpl::Factory:
-  std::unique_ptr<BleServiceDataHelper> CreateInstance(
+  // BluetoothHelperImpl::Factory:
+  std::unique_ptr<BluetoothHelper> CreateInstance(
       multidevice::RemoteDeviceCache* remote_device_cache) override {
     EXPECT_FALSE(instance_);
     EXPECT_EQ(test_remote_device_cache_factory_->instance(),
               remote_device_cache);
 
-    auto instance = std::make_unique<FakeBleServiceDataHelper>();
+    auto instance = std::make_unique<FakeBluetoothHelper>();
     instance_ = instance.get();
     return instance;
   }
 
   TestRemoteDeviceCacheFactory* test_remote_device_cache_factory_;
 
-  FakeBleServiceDataHelper* instance_ = nullptr;
+  FakeBluetoothHelper* instance_ = nullptr;
 
-  DISALLOW_COPY_AND_ASSIGN(FakeBleServiceDataHelperFactory);
+  DISALLOW_COPY_AND_ASSIGN(FakeBluetoothHelperFactory);
 };
 
 class FakeBleSynchronizerFactory : public BleSynchronizer::Factory {
@@ -153,10 +152,9 @@
 class FakeBleScannerFactory : public BleScannerImpl::Factory {
  public:
   FakeBleScannerFactory(
-      FakeBleServiceDataHelperFactory* fake_ble_service_data_helper_factory,
+      FakeBluetoothHelperFactory* fake_bluetooth_helper_factory,
       FakeBleSynchronizerFactory* fake_ble_synchronizer_factory)
-      : fake_ble_service_data_helper_factory_(
-            fake_ble_service_data_helper_factory),
+      : fake_bluetooth_helper_factory_(fake_bluetooth_helper_factory),
         fake_ble_synchronizer_factory_(fake_ble_synchronizer_factory) {}
 
   ~FakeBleScannerFactory() override = default;
@@ -166,11 +164,10 @@
  private:
   // BleScannerImpl::Factory:
   std::unique_ptr<BleScanner> CreateInstance(
-      BleServiceDataHelper* service_data_helper,
+      BluetoothHelper* bluetooth_helper,
       BleSynchronizerBase* ble_synchronizer_base,
       scoped_refptr<device::BluetoothAdapter> adapter) override {
-    EXPECT_EQ(fake_ble_service_data_helper_factory_->instance(),
-              service_data_helper);
+    EXPECT_EQ(fake_bluetooth_helper_factory_->instance(), bluetooth_helper);
     EXPECT_EQ(fake_ble_synchronizer_factory_->instance(),
               ble_synchronizer_base);
     EXPECT_FALSE(instance_);
@@ -182,7 +179,7 @@
 
   FakeBleScanner* instance_ = nullptr;
 
-  FakeBleServiceDataHelperFactory* fake_ble_service_data_helper_factory_;
+  FakeBluetoothHelperFactory* fake_bluetooth_helper_factory_;
   FakeBleSynchronizerFactory* fake_ble_synchronizer_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeBleScannerFactory);
@@ -193,13 +190,12 @@
  public:
   FakeBleConnectionManagerFactory(
       device::BluetoothAdapter* expected_bluetooth_adapter,
-      FakeBleServiceDataHelperFactory* fake_ble_service_data_helper_factory,
+      FakeBluetoothHelperFactory* fake_bluetooth_helper_factory,
       FakeBleSynchronizerFactory* fake_ble_synchronizer_factory,
       FakeBleScannerFactory* fake_ble_scanner_factory,
       FakeTimerFactoryFactory* fake_timer_factory_factory)
       : expected_bluetooth_adapter_(expected_bluetooth_adapter),
-        fake_ble_service_data_helper_factory_(
-            fake_ble_service_data_helper_factory),
+        fake_bluetooth_helper_factory_(fake_bluetooth_helper_factory),
         fake_ble_synchronizer_factory_(fake_ble_synchronizer_factory),
         fake_ble_scanner_factory_(fake_ble_scanner_factory),
         fake_timer_factory_factory_(fake_timer_factory_factory) {}
@@ -212,15 +208,14 @@
   // BleConnectionManagerImpl::Factory:
   std::unique_ptr<BleConnectionManager> CreateInstance(
       scoped_refptr<device::BluetoothAdapter> bluetooth_adapter,
-      BleServiceDataHelper* ble_service_data_helper,
+      BluetoothHelper* bluetooth_helper,
       BleSynchronizerBase* ble_synchronizer,
       BleScanner* ble_scanner,
       TimerFactory* timer_factory,
       base::Clock* clock) override {
     EXPECT_FALSE(instance_);
     EXPECT_EQ(expected_bluetooth_adapter_, bluetooth_adapter.get());
-    EXPECT_EQ(fake_ble_service_data_helper_factory_->instance(),
-              ble_service_data_helper);
+    EXPECT_EQ(fake_bluetooth_helper_factory_->instance(), bluetooth_helper);
     EXPECT_EQ(fake_ble_synchronizer_factory_->instance(), ble_synchronizer);
     EXPECT_EQ(fake_ble_scanner_factory_->instance(), ble_scanner);
     EXPECT_EQ(fake_timer_factory_factory_->instance(), timer_factory);
@@ -231,7 +226,7 @@
   }
 
   device::BluetoothAdapter* expected_bluetooth_adapter_;
-  FakeBleServiceDataHelperFactory* fake_ble_service_data_helper_factory_;
+  FakeBluetoothHelperFactory* fake_bluetooth_helper_factory_;
   FakeBleSynchronizerFactory* fake_ble_synchronizer_factory_;
   FakeBleScannerFactory* fake_ble_scanner_factory_;
   FakeTimerFactoryFactory* fake_timer_factory_factory_;
@@ -427,11 +422,11 @@
     multidevice::RemoteDeviceCache::Factory::SetFactoryForTesting(
         test_remote_device_cache_factory_.get());
 
-    fake_ble_service_data_helper_factory_ =
-        std::make_unique<FakeBleServiceDataHelperFactory>(
+    fake_bluetooth_helper_factory_ =
+        std::make_unique<FakeBluetoothHelperFactory>(
             test_remote_device_cache_factory_.get());
-    BleServiceDataHelperImpl::Factory::SetFactoryForTesting(
-        fake_ble_service_data_helper_factory_.get());
+    BluetoothHelperImpl::Factory::SetFactoryForTesting(
+        fake_bluetooth_helper_factory_.get());
 
     fake_ble_synchronizer_factory_ =
         std::make_unique<FakeBleSynchronizerFactory>();
@@ -439,14 +434,14 @@
         fake_ble_synchronizer_factory_.get());
 
     fake_ble_scanner_factory_ = std::make_unique<FakeBleScannerFactory>(
-        fake_ble_service_data_helper_factory_.get(),
+        fake_bluetooth_helper_factory_.get(),
         fake_ble_synchronizer_factory_.get());
     BleScannerImpl::Factory::SetFactoryForTesting(
         fake_ble_scanner_factory_.get());
 
     fake_ble_connection_manager_factory_ =
         std::make_unique<FakeBleConnectionManagerFactory>(
-            mock_adapter_.get(), fake_ble_service_data_helper_factory_.get(),
+            mock_adapter_.get(), fake_bluetooth_helper_factory_.get(),
             fake_ble_synchronizer_factory_.get(),
             fake_ble_scanner_factory_.get(), fake_timer_factory_factory_.get());
     BleConnectionManagerImpl::Factory::SetFactoryForTesting(
@@ -482,7 +477,7 @@
   void TearDown() override {
     TimerFactoryImpl::Factory::SetFactoryForTesting(nullptr);
     multidevice::RemoteDeviceCache::Factory::SetFactoryForTesting(nullptr);
-    BleServiceDataHelperImpl::Factory::SetFactoryForTesting(nullptr);
+    BluetoothHelperImpl::Factory::SetFactoryForTesting(nullptr);
     BleSynchronizer::Factory::SetFactoryForTesting(nullptr);
     BleScannerImpl::Factory::SetFactoryForTesting(nullptr);
     BleConnectionManagerImpl::Factory::SetFactoryForTesting(nullptr);
@@ -957,8 +952,7 @@
   std::unique_ptr<FakeTimerFactoryFactory> fake_timer_factory_factory_;
   std::unique_ptr<TestRemoteDeviceCacheFactory>
       test_remote_device_cache_factory_;
-  std::unique_ptr<FakeBleServiceDataHelperFactory>
-      fake_ble_service_data_helper_factory_;
+  std::unique_ptr<FakeBluetoothHelperFactory> fake_bluetooth_helper_factory_;
   std::unique_ptr<FakeBleSynchronizerFactory> fake_ble_synchronizer_factory_;
   std::unique_ptr<FakeBleScannerFactory> fake_ble_scanner_factory_;
   std::unique_ptr<FakeBleConnectionManagerFactory>
diff --git a/components/arc/arc_util.cc b/components/arc/arc_util.cc
index 9b62fe38..d831266 100644
--- a/components/arc/arc_util.cc
+++ b/components/arc/arc_util.cc
@@ -67,13 +67,7 @@
     LOG(ERROR) << "SetVmCpuRestriction for ARCVM failed";
 }
 
-void DoSetArcVmCpuRestriction(CpuRestrictionState cpu_restriction_state,
-                              bool concierge_started) {
-  if (!concierge_started) {
-    LOG(ERROR) << "Concierge D-Bus service is not available";
-    return;
-  }
-
+void SetArcVmCpuRestriction(CpuRestrictionState cpu_restriction_state) {
   auto* client = chromeos::DBusThreadManager::Get()->GetConciergeClient();
   if (!client) {
     LOG(ERROR) << "ConciergeClient is not available";
@@ -97,17 +91,6 @@
                               base::BindOnce(&OnSetArcVmCpuRestriction));
 }
 
-void SetArcVmCpuRestriction(CpuRestrictionState cpu_restriction_state) {
-  auto* client = chromeos::DBusThreadManager::Get()->GetDebugDaemonClient();
-  if (!client) {
-    LOG(WARNING) << "DebugDaemonClient is not available";
-    return;
-  }
-  // TODO(wvk): Call StartConcierge() only when the service is not running.
-  client->StartConcierge(
-      base::BindOnce(&DoSetArcVmCpuRestriction, cpu_restriction_state));
-}
-
 void SetArcContainerCpuRestriction(CpuRestrictionState cpu_restriction_state) {
   if (!chromeos::SessionManagerClient::Get()) {
     LOG(WARNING) << "SessionManagerClient is not available";
diff --git a/components/arc/session/arc_vm_client_adapter.cc b/components/arc/session/arc_vm_client_adapter.cc
index d25be35..d112e43 100644
--- a/components/arc/session/arc_vm_client_adapter.cc
+++ b/components/arc/session/arc_vm_client_adapter.cc
@@ -527,14 +527,6 @@
                        weak_factory_.GetWeakPtr(), std::move(callback)));
   }
 
-  void UpgradeArc(UpgradeParams params,
-                  chromeos::VoidDBusMethodCallback callback) override {
-    VLOG(1) << "Starting Concierge service";
-    GetDebugDaemonClient()->StartConcierge(base::BindOnce(
-        &ArcVmClientAdapter::OnConciergeStarted, weak_factory_.GetWeakPtr(),
-        std::move(params), std::move(callback)));
-  }
-
   void StopArcInstance(bool on_shutdown, bool should_backup_log) override {
     if (on_shutdown) {
       // Do nothing when |on_shutdown| is true because either vm_concierge.conf
@@ -675,14 +667,8 @@
     should_notify_observers_ = true;
   }
 
-  void OnConciergeStarted(UpgradeParams params,
-                          chromeos::VoidDBusMethodCallback callback,
-                          bool success) {
-    if (!success) {
-      LOG(ERROR) << "Failed to start Concierge service for arcvm";
-      std::move(callback).Run(false);
-      return;
-    }
+  void UpgradeArc(UpgradeParams params,
+                  chromeos::VoidDBusMethodCallback callback) override {
     VLOG(2) << "Checking file system status";
     base::ThreadPool::PostTaskAndReplyWithResult(
         FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
diff --git a/components/arc/session/arc_vm_client_adapter_unittest.cc b/components/arc/session/arc_vm_client_adapter_unittest.cc
index 6a469e4..0cc55878 100644
--- a/components/arc/session/arc_vm_client_adapter_unittest.cc
+++ b/components/arc/session/arc_vm_client_adapter_unittest.cc
@@ -97,11 +97,6 @@
   TestDebugDaemonClient() = default;
   ~TestDebugDaemonClient() override = default;
 
-  void StartConcierge(ConciergeCallback callback) override {
-    start_concierge_called_ = true;
-    std::move(callback).Run(start_concierge_result_);
-  }
-
   void BackupArcBugReport(const std::string& userhash,
                           chromeos::VoidDBusMethodCallback callback) override {
     backup_arc_bug_report_called_ = true;
@@ -115,14 +110,7 @@
     backup_arc_bug_report_result_ = result;
   }
 
-  bool start_concierge_called() const { return start_concierge_called_; }
-  void set_start_concierge_result(bool result) {
-    start_concierge_result_ = result;
-  }
-
  private:
-  bool start_concierge_called_ = false;
-  bool start_concierge_result_ = true;
   bool backup_arc_bug_report_called_ = false;
   bool backup_arc_bug_report_result_ = true;
 
@@ -313,14 +301,6 @@
   }
 
  protected:
-  bool GetStartConciergeCalled() {
-    return GetTestDebugDaemonClient()->start_concierge_called();
-  }
-
-  void SetStartConciergeResponse(bool response) {
-    GetTestDebugDaemonClient()->set_start_concierge_result(response);
-  }
-
   void SetValidUserInfo() { SetUserInfo(kUserIdHash, kSerialNumber); }
 
   void SetUserInfo(const std::string& hash, const std::string& serial) {
@@ -755,7 +735,6 @@
   InjectUpstartStartJobFailure(kArcVmServerProxyJobName);
 
   UpgradeArc(false);
-  EXPECT_TRUE(GetStartConciergeCalled());
   EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
 
@@ -781,7 +760,6 @@
 
   // Upgrade should still succeed.
   UpgradeArc(true);
-  EXPECT_TRUE(GetStartConciergeCalled());
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
 }
@@ -796,7 +774,6 @@
 
   EnableAdbOverUsbForTesting();
   UpgradeArc(false);
-  EXPECT_TRUE(GetStartConciergeCalled());
   EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
 
@@ -821,7 +798,6 @@
   InjectUpstartStartJobFailure(kArcCreateDataJobName);
 
   UpgradeArc(false);
-  EXPECT_TRUE(GetStartConciergeCalled());
   EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
 
@@ -847,7 +823,6 @@
   InjectUpstartStartJobFailure(kArcVmMountMyFilesJobName);
 
   UpgradeArc(false);
-  EXPECT_TRUE(GetStartConciergeCalled());
   EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
 
@@ -874,30 +849,6 @@
   InjectUpstartStartJobFailure(kArcVmMountRemovableMediaJobName);
 
   UpgradeArc(false);
-  EXPECT_TRUE(GetStartConciergeCalled());
-  EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
-  EXPECT_FALSE(arc_instance_stopped_called());
-
-  // Try to stop the VM. StopVm will fail in this case because
-  // no VM is running.
-  vm_tools::concierge::StopVmResponse response;
-  response.set_success(false);
-  GetTestConciergeClient()->set_stop_vm_response(response);
-  adapter()->StopArcInstance(/*on_shutdown=*/false,
-                             /*should_backup_log=*/false);
-  run_loop()->Run();
-  EXPECT_TRUE(GetTestConciergeClient()->stop_vm_called());
-  EXPECT_TRUE(arc_instance_stopped_called());
-}
-
-// Tests that UpgradeArc() handles StartConcierge() failures properly.
-TEST_F(ArcVmClientAdapterTest, UpgradeArc_StartConciergeFailure) {
-  SetValidUserInfo();
-  StartMiniArc();
-  // Inject failure to StartConcierge().
-  SetStartConciergeResponse(false);
-  UpgradeArc(false);
-  EXPECT_TRUE(GetStartConciergeCalled());
   EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
 
@@ -921,7 +872,6 @@
   StartMiniArc();
 
   UpgradeArc(false);
-  EXPECT_TRUE(GetStartConciergeCalled());
   EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
 
@@ -945,7 +895,6 @@
   StartMiniArc();
 
   UpgradeArc(false);
-  EXPECT_TRUE(GetStartConciergeCalled());
   EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
 
@@ -971,7 +920,6 @@
   GetTestConciergeClient()->set_start_vm_response(start_vm_response);
 
   UpgradeArc(false);
-  EXPECT_TRUE(GetStartConciergeCalled());
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
 
@@ -994,7 +942,6 @@
   GetTestConciergeClient()->set_start_vm_response(base::nullopt);
 
   UpgradeArc(false);
-  EXPECT_TRUE(GetStartConciergeCalled());
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
 
@@ -1015,7 +962,6 @@
   SetValidUserInfo();
   StartMiniArc();
   UpgradeArc(true);
-  EXPECT_TRUE(GetStartConciergeCalled());
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
 
@@ -1040,7 +986,6 @@
 
   UpgradeParams params(GetPopulatedUpgradeParams());
   UpgradeArcWithParams(true, std::move(params));
-  EXPECT_TRUE(GetStartConciergeCalled());
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
 }
@@ -1064,7 +1009,6 @@
   params.preferred_languages = {"en_US"};
 
   UpgradeArcWithParams(true, std::move(params));
-  EXPECT_TRUE(GetStartConciergeCalled());
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
 }
@@ -1084,7 +1028,6 @@
   params.demo_session_apps_path = base::FilePath(kDemoImage);
 
   UpgradeArcWithParams(true, std::move(params));
-  EXPECT_TRUE(GetStartConciergeCalled());
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
 
@@ -1108,7 +1051,6 @@
   StartMiniArcWithParams(true, std::move(start_params));
   UpgradeParams params(GetPopulatedUpgradeParams());
   UpgradeArcWithParams(true, std::move(params));
-  EXPECT_TRUE(GetStartConciergeCalled());
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
   EXPECT_TRUE(
@@ -1141,7 +1083,6 @@
   SetValidUserInfo();
   StartMiniArc();
   UpgradeArc(true);
-  EXPECT_TRUE(GetStartConciergeCalled());
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
 
@@ -1156,7 +1097,6 @@
   SetValidUserInfo();
   StartMiniArc();
   UpgradeArc(true);
-  EXPECT_TRUE(GetStartConciergeCalled());
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
 
@@ -1171,7 +1111,6 @@
   SetValidUserInfo();
   StartMiniArc();
   UpgradeArc(true);
-  EXPECT_TRUE(GetStartConciergeCalled());
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
 
@@ -1194,7 +1133,6 @@
   SetValidUserInfo();
   StartMiniArc();
   UpgradeArc(true);
-  EXPECT_TRUE(GetStartConciergeCalled());
   EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called());
   EXPECT_FALSE(arc_instance_stopped_called());
 
diff --git a/components/browser_ui/strings/android/browser_ui_strings.grd b/components/browser_ui/strings/android/browser_ui_strings.grd
index 6007880..af2d4c1c 100644
--- a/components/browser_ui/strings/android/browser_ui_strings.grd
+++ b/components/browser_ui/strings/android/browser_ui_strings.grd
@@ -300,6 +300,9 @@
       <message name="IDS_MENU_ITEM_MOVE_TO_TOP" desc="Option in item menu. User can click the 'Move to top' option to move the item up to the top of its list. [CHAR-LIMIT=24]">
         Move to top
       </message>
+      <message name="IDS_OPEN_SETTINGS" desc="Generic label for a button to show settings screen. [CHAR-LIMIT=20]">
+        Open settings
+      </message>
 
       <message name="IDS_ACCESSIBILITY_TOOLBAR_BTN_MENU" desc="Content description for the settings menu button.">
         More options
diff --git a/components/exo/wayland/BUILD.gn b/components/exo/wayland/BUILD.gn
index 505e977..4a71f21 100644
--- a/components/exo/wayland/BUILD.gn
+++ b/components/exo/wayland/BUILD.gn
@@ -232,7 +232,7 @@
 }
 
 config("client_support_config") {
-  if (ozone_platform_gbm) {
+  if (ozone_platform_drm) {
     defines = [ "USE_GBM" ]
     if (enable_vulkan) {
       defines += [ "USE_VULKAN" ]
@@ -269,7 +269,7 @@
     "//third_party/wayland-protocols:vsync_feedback_protocol",
   ]
 
-  if (ozone_platform_gbm) {
+  if (ozone_platform_drm) {
     configs += [ "//ui/gl:gl_config" ]
     deps += [
       "//build/config/linux/libdrm",
@@ -296,7 +296,7 @@
     "//ui/gl",
   ]
 
-  if (ozone_platform_gbm) {
+  if (ozone_platform_drm) {
     configs += [ "//ui/gl:gl_config" ]
     defines = [ "USE_GBM" ]
     deps += [
@@ -325,7 +325,7 @@
     "//ui/gl",
   ]
 
-  if (ozone_platform_gbm) {
+  if (ozone_platform_drm) {
     configs += [ "//ui/gl:gl_config" ]
   }
 }
@@ -348,7 +348,7 @@
     "//ui/gl",
   ]
 
-  if (ozone_platform_gbm) {
+  if (ozone_platform_drm) {
     configs += [ "//ui/gl:gl_config" ]
   }
 }
@@ -386,7 +386,7 @@
     "//ui/gl",
   ]
 
-  if (ozone_platform_gbm) {
+  if (ozone_platform_drm) {
     configs += [ "//ui/gl:gl_config" ]
   }
 }
@@ -407,7 +407,7 @@
     "//ui/gl",
   ]
 
-  if (ozone_platform_gbm) {
+  if (ozone_platform_drm) {
     configs += [ "//ui/gl:gl_config" ]
   }
 }
@@ -512,7 +512,7 @@
   }
 }
 
-if (ozone_platform_gbm) {
+if (ozone_platform_drm) {
   executable("wayland_yuv_client") {
     sources = [ "clients/yuv.cc" ]
 
diff --git a/components/find_in_page/android/find_in_page_bridge.cc b/components/find_in_page/android/find_in_page_bridge.cc
index 2346f0d..2931083d7 100644
--- a/components/find_in_page/android/find_in_page_bridge.cc
+++ b/components/find_in_page/android/find_in_page_bridge.cc
@@ -37,7 +37,7 @@
       ->StartFinding(
           base::android::ConvertJavaStringToUTF16(env, search_string),
           forward_direction, case_sensitive,
-          true /* find_next_if_selection_matches */);
+          true /* find_match */);
 }
 
 void FindInPageBridge::StopFinding(JNIEnv* env,
diff --git a/components/find_in_page/find_tab_helper.cc b/components/find_in_page/find_tab_helper.cc
index a3beda3..64cb266 100644
--- a/components/find_in_page/find_tab_helper.cc
+++ b/components/find_in_page/find_tab_helper.cc
@@ -45,7 +45,7 @@
 void FindTabHelper::StartFinding(base::string16 search_string,
                                  bool forward_direction,
                                  bool case_sensitive,
-                                 bool find_next_if_selection_matches,
+                                 bool find_match,
                                  bool run_synchronously_for_testing) {
   // Remove the carriage return character, which generally isn't in web content.
   const base::char16 kInvalidChars[] = {'\r', 0};
@@ -86,7 +86,7 @@
   options->forward = forward_direction;
   options->match_case = case_sensitive;
   options->new_session = new_session;
-  options->find_next_if_selection_matches = find_next_if_selection_matches;
+  options->find_match = find_match;
   options->run_synchronously_for_testing = run_synchronously_for_testing;
   web_contents_->Find(current_find_request_id_, find_text_, std::move(options));
 }
diff --git a/components/find_in_page/find_tab_helper.h b/components/find_in_page/find_tab_helper.h
index 73586ea..08c232d 100644
--- a/components/find_in_page/find_tab_helper.h
+++ b/components/find_in_page/find_tab_helper.h
@@ -47,13 +47,12 @@
   // receive the results through the notification mechanism. See Observe(...)
   // for details.
   //
-  // If |find_next_if_selection_matches| is true and the search results in an
-  // exact match of the selection, keep searching. It should generally be set to
-  // true unless you're starting a new find based on the selection.
+  // |find_match| controls whether to find the first match or to only do match
+  // counts and highlighting.
   void StartFinding(base::string16 search_string,
                     bool forward_direction,
                     bool case_sensitive,
-                    bool find_next_if_selection_matches,
+                    bool find_match,
                     bool run_synchronously_for_testing = false);
 
   // Stops the current Find operation.
diff --git a/components/javascript_dialogs/views/app_modal_dialog_view_views.cc b/components/javascript_dialogs/views/app_modal_dialog_view_views.cc
index a40f389..510c1f5 100644
--- a/components/javascript_dialogs/views/app_modal_dialog_view_views.cc
+++ b/components/javascript_dialogs/views/app_modal_dialog_view_views.cc
@@ -121,8 +121,8 @@
 }
 
 views::View* AppModalDialogViewViews::GetInitiallyFocusedView() {
-  if (message_box_view_->text_box())
-    return message_box_view_->text_box();
+  if (message_box_view_->GetVisiblePromptField())
+    return message_box_view_->GetVisiblePromptField();
   return views::DialogDelegate::GetInitiallyFocusedView();
 }
 
diff --git a/components/payments/content/android/java/src/org/chromium/components/payments/BrowserPaymentRequest.java b/components/payments/content/android/java/src/org/chromium/components/payments/BrowserPaymentRequest.java
index d4721f1..2240d80 100644
--- a/components/payments/content/android/java/src/org/chromium/components/payments/BrowserPaymentRequest.java
+++ b/components/payments/content/android/java/src/org/chromium/components/payments/BrowserPaymentRequest.java
@@ -4,11 +4,9 @@
 
 package org.chromium.components.payments;
 
-import androidx.annotation.Nullable;
-
 import org.chromium.payments.mojom.PaymentDetails;
+import org.chromium.payments.mojom.PaymentErrorReason;
 import org.chromium.payments.mojom.PaymentMethodData;
-import org.chromium.payments.mojom.PaymentOptions;
 import org.chromium.payments.mojom.PaymentRequest;
 import org.chromium.payments.mojom.PaymentValidationErrors;
 
@@ -32,16 +30,15 @@
     /**
      * Initialize the browser part of the {@link PaymentRequest} implementation and validate the raw
      * payment request data coming from the untrusted mojo.
-     * @param methodData The supported methods specified by the merchant.
-     * @param details The payment details specified by the merchant.
-     * @param options The payment options specified by the merchant, can be null.
+     * @param methodData The supported methods specified by the merchant, cannot be null.
+     * @param details The payment details specified by the merchant, cannot be null.
      * @param googlePayBridgeEligible True when the renderer process deems the current request
      *         eligible for the skip-to-GPay experimental flow. It is ultimately up to the browser
      *         process to determine whether to trigger it
      * @return whether the initialization is successful.
      */
     boolean initAndValidate(PaymentMethodData[] methodData, PaymentDetails details,
-            @Nullable PaymentOptions options, boolean googlePayBridgeEligible);
+            boolean googlePayBridgeEligible);
 
     /**
      * The browser part of the {@link PaymentRequest#show} implementation.
@@ -83,8 +80,12 @@
     /** The browser part of the {@link PaymentRequest#canMakePayment} implementation. */
     void canMakePayment();
 
-    /** Delegate to the same method of PaymentRequestImpl. */
-    void disconnectFromClientWithDebugMessage(String debugMessage);
+    /**
+     * Delegate to the same method of PaymentRequestImpl.
+     * @param debugMessage The debug message shown for web developers.
+     * @param reason The reason of the disconnection defined in {@link PaymentErrorReason}.
+     */
+    void disconnectFromClientWithDebugMessage(String debugMessage, int reason);
 
     /**
      * Close this instance. The callers of this method should stop referencing this instance upon
diff --git a/components/payments/content/android/java/src/org/chromium/components/payments/ComponentPaymentRequestImpl.java b/components/payments/content/android/java/src/org/chromium/components/payments/ComponentPaymentRequestImpl.java
index 75e2035b..43b68fae 100644
--- a/components/payments/content/android/java/src/org/chromium/components/payments/ComponentPaymentRequestImpl.java
+++ b/components/payments/content/android/java/src/org/chromium/components/payments/ComponentPaymentRequestImpl.java
@@ -4,6 +4,8 @@
 
 package org.chromium.components.payments;
 
+import android.text.TextUtils;
+
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
@@ -18,6 +20,7 @@
 import org.chromium.payments.mojom.PayerDetail;
 import org.chromium.payments.mojom.PaymentAddress;
 import org.chromium.payments.mojom.PaymentDetails;
+import org.chromium.payments.mojom.PaymentErrorReason;
 import org.chromium.payments.mojom.PaymentItem;
 import org.chromium.payments.mojom.PaymentMethodData;
 import org.chromium.payments.mojom.PaymentOptions;
@@ -55,6 +58,13 @@
     @Nullable
     private final byte[][] mCertificateChain;
     private final boolean mIsOffTheRecord;
+    @Nullable
+    private final PaymentOptions mPaymentOptions;
+    private final boolean mRequestShipping;
+    private final boolean mRequestPayerName;
+    private final boolean mRequestPayerPhone;
+    private final boolean mRequestPayerEmail;
+    private final Delegate mDelegate;
     private boolean mSkipUiForNonUrlPaymentMethodIdentifiers;
     private PaymentRequestLifecycleObserver mPaymentRequestLifecycleObserver;
     private boolean mHasClosed;
@@ -86,6 +96,50 @@
     }
 
     /**
+     * A delegate to ask questions about the system, that allows tests to inject behaviour without
+     * having to modify the entire system. This partially mirrors a similar C++
+     * (Content)PaymentRequestDelegate for the C++ implementation, allowing the test harness to
+     * override behaviour in both in a similar fashion.
+     */
+    public interface Delegate {
+        /**
+         * @return Whether the merchant's WebContents is currently showing an off-the-record tab.
+         *         Return true if the tab profile is not accessible from the WebContents.
+         */
+        boolean isOffTheRecord();
+
+        /**
+         * @return A non-null string if there is an invalid SSL certificate on the currently loaded
+         *         page.
+         */
+        String getInvalidSslCertificateErrorMessage();
+
+        /**
+         * @return True if the merchant's web contents that initiated the payment request is active.
+         */
+        boolean isWebContentsActive();
+
+        /**
+         * @return Whether the preferences allow CAN_MAKE_PAYMENT.
+         */
+        boolean prefsCanMakePayment();
+
+        /**
+         * @return True if the UI can be skipped for "basic-card" scenarios. This will only ever be
+         *         true in tests.
+         */
+        boolean skipUiForBasicCard();
+
+        /**
+         * @return If the merchant's WebContents is running inside of a Trusted Web Activity,
+         *         returns the package name for Trusted Web Activity. Otherwise returns an empty
+         *         string or null.
+         */
+        @Nullable
+        String getTwaPackageName();
+    }
+
+    /**
      * A test-only observer for the PaymentRequest service implementation.
      */
     public interface PaymentRequestServiceObserverForTest {
@@ -156,20 +210,21 @@
      * @param renderFrameHost The RenderFrameHost of the merchant page.
      * @param isOffTheRecord Whether the merchant page is in a off-the-record (e.g., incognito,
      *         guest mode) Tab.
+     * @param delegate The delegate of this class.
      * @param skipUiForBasicCard True if the PaymentRequest UI should be skipped when the request
      *         only supports basic-card methods.
      * @param browserPaymentRequestFactory The factory that generates BrowserPaymentRequest.
      * @return The created instance.
      */
     public static PaymentRequest createPaymentRequest(RenderFrameHost renderFrameHost,
-            boolean isOffTheRecord, boolean skipUiForBasicCard,
+            boolean isOffTheRecord, boolean skipUiForBasicCard, Delegate delegate,
             BrowserPaymentRequest.Factory browserPaymentRequestFactory) {
         return new MojoPaymentRequestGateKeeper(
                 (client, methodData, details, options, googlePayBridgeEligible, onClosedListener)
                         -> ComponentPaymentRequestImpl.createIfParamsValid(renderFrameHost,
                                 isOffTheRecord, skipUiForBasicCard, browserPaymentRequestFactory,
                                 client, methodData, details, options, googlePayBridgeEligible,
-                                onClosedListener));
+                                onClosedListener, delegate));
     }
 
     /**
@@ -182,7 +237,7 @@
             BrowserPaymentRequest.Factory browserPaymentRequestFactory,
             @Nullable PaymentRequestClient client, @Nullable PaymentMethodData[] methodData,
             @Nullable PaymentDetails details, @Nullable PaymentOptions options,
-            boolean googlePayBridgeEligible, Runnable onClosedListener) {
+            boolean googlePayBridgeEligible, Runnable onClosedListener, Delegate delegate) {
         assert renderFrameHost != null;
         assert browserPaymentRequestFactory != null;
         assert onClosedListener != null;
@@ -215,18 +270,27 @@
             return null;
         }
 
+        // details has default value, so could never be null, according to payment_request.idl.
         if (details == null) {
             abortBeforeInstantiation(client, journeyLogger, ErrorStrings.INVALID_PAYMENT_DETAILS,
                     AbortReason.INVALID_DATA_FROM_RENDERER);
             return null;
         }
 
+        // options has default value, so could never be null, according to
+        // payment_request.idl.
+        if (options == null) {
+            abortBeforeInstantiation(client, journeyLogger, ErrorStrings.INVALID_PAYMENT_OPTIONS,
+                    AbortReason.INVALID_DATA_FROM_RENDERER);
+            return null;
+        }
+
         ComponentPaymentRequestImpl instance =
                 new ComponentPaymentRequestImpl(client, renderFrameHost, webContents, journeyLogger,
-                        skipUiForBasicCard, isOffTheRecord, onClosedListener);
+                        options, skipUiForBasicCard, isOffTheRecord, onClosedListener, delegate);
         instance.onCreated();
-        boolean valid = instance.initAndValidate(renderFrameHost, browserPaymentRequestFactory,
-                methodData, details, options, googlePayBridgeEligible, isOffTheRecord);
+        boolean valid = instance.initAndValidate(
+                browserPaymentRequestFactory, methodData, details, googlePayBridgeEligible);
         if (!valid) {
             instance.close();
             return null;
@@ -250,11 +314,15 @@
 
     private ComponentPaymentRequestImpl(PaymentRequestClient client,
             RenderFrameHost renderFrameHost, WebContents webContents, JourneyLogger journeyLogger,
-            boolean skipUiForBasicCard, boolean isOffTheRecord, Runnable onClosedListener) {
+            PaymentOptions options, boolean skipUiForBasicCard, boolean isOffTheRecord,
+            Runnable onClosedListener, Delegate delegate) {
         assert client != null;
         assert renderFrameHost != null;
         assert webContents != null;
         assert journeyLogger != null;
+        assert options != null;
+        assert onClosedListener != null;
+        assert delegate != null;
 
         mRenderFrameHost = renderFrameHost;
         mPaymentRequestSecurityOrigin = mRenderFrameHost.getLastCommittedOrigin();
@@ -266,6 +334,12 @@
         mTopLevelOrigin =
                 UrlFormatter.formatUrlForSecurityDisplay(mWebContents.getLastCommittedUrl());
 
+        mPaymentOptions = options;
+        mRequestShipping = mPaymentOptions.requestShipping;
+        mRequestPayerName = mPaymentOptions.requestPayerName;
+        mRequestPayerPhone = mPaymentOptions.requestPayerPhone;
+        mRequestPayerEmail = mPaymentOptions.requestPayerEmail;
+
         mMerchantName = mWebContents.getTitle();
         mCertificateChain = CertificateChainHelper.getCertificateChain(mWebContents);
         mIsOffTheRecord = isOffTheRecord;
@@ -273,6 +347,7 @@
         mClient = client;
         mJourneyLogger = journeyLogger;
         mOnClosedListener = onClosedListener;
+        mDelegate = delegate;
         mHasClosed = false;
     }
 
@@ -292,13 +367,43 @@
         return sNativeObserverForTest;
     }
 
-    private boolean initAndValidate(RenderFrameHost renderFrameHost,
-            BrowserPaymentRequest.Factory factory, @Nullable PaymentMethodData[] methodData,
-            @Nullable PaymentDetails details, @Nullable PaymentOptions options,
-            boolean googlePayBridgeEligible, boolean isOffTheRecord) {
+    private boolean initAndValidate(BrowserPaymentRequest.Factory factory,
+            PaymentMethodData[] methodData, PaymentDetails details,
+            boolean googlePayBridgeEligible) {
         mBrowserPaymentRequest = factory.createBrowserPaymentRequest(this);
-        return mBrowserPaymentRequest.initAndValidate(
-                methodData, details, options, googlePayBridgeEligible);
+        mJourneyLogger.recordCheckoutStep(
+                org.chromium.components.payments.CheckoutFunnelStep.INITIATED);
+
+        if (!UrlUtil.isOriginAllowedToUseWebPaymentApis(mWebContents.getLastCommittedUrl())) {
+            Log.d(TAG, org.chromium.components.payments.ErrorStrings.PROHIBITED_ORIGIN);
+            Log.d(TAG,
+                    org.chromium.components.payments.ErrorStrings
+                            .PROHIBITED_ORIGIN_OR_INVALID_SSL_EXPLANATION);
+            mJourneyLogger.setAborted(
+                    org.chromium.components.payments.AbortReason.INVALID_DATA_FROM_RENDERER);
+            mBrowserPaymentRequest.disconnectFromClientWithDebugMessage(
+                    ErrorStrings.PROHIBITED_ORIGIN,
+                    PaymentErrorReason.NOT_SUPPORTED_FOR_INVALID_ORIGIN_OR_SSL);
+            return false;
+        }
+
+        mJourneyLogger.setRequestedInformation(
+                mRequestShipping, mRequestPayerEmail, mRequestPayerPhone, mRequestPayerName);
+
+        String rejectShowErrorMessage = mDelegate.getInvalidSslCertificateErrorMessage();
+        if (!TextUtils.isEmpty(rejectShowErrorMessage)) {
+            Log.d(TAG, rejectShowErrorMessage);
+            Log.d(TAG,
+                    org.chromium.components.payments.ErrorStrings
+                            .PROHIBITED_ORIGIN_OR_INVALID_SSL_EXPLANATION);
+            mJourneyLogger.setAborted(
+                    org.chromium.components.payments.AbortReason.INVALID_DATA_FROM_RENDERER);
+            mBrowserPaymentRequest.disconnectFromClientWithDebugMessage(rejectShowErrorMessage,
+                    PaymentErrorReason.NOT_SUPPORTED_FOR_INVALID_ORIGIN_OR_SSL);
+            return false;
+        }
+
+        return mBrowserPaymentRequest.initAndValidate(methodData, details, googlePayBridgeEligible);
     }
 
     /**
@@ -421,7 +526,8 @@
         assert mBrowserPaymentRequest != null;
 
         mJourneyLogger.setAborted(AbortReason.INVALID_DATA_FROM_RENDERER);
-        mBrowserPaymentRequest.disconnectFromClientWithDebugMessage(debugMessage);
+        mBrowserPaymentRequest.disconnectFromClientWithDebugMessage(
+                debugMessage, PaymentErrorReason.USER_CANCEL);
     }
 
     /**
@@ -615,6 +721,12 @@
         return mTopLevelOrigin;
     }
 
+    /** @return The payment options requested by the merchant, can be null. */
+    @Nullable
+    public PaymentOptions getPaymentOptions() {
+        return mPaymentOptions;
+    }
+
     /** @return The RendererFrameHost of the merchant page. */
     public RenderFrameHost getRenderFrameHost() {
         return mRenderFrameHost;
diff --git a/components/payments/content/android/java/src/org/chromium/components/payments/PaymentOptionsUtils.java b/components/payments/content/android/java/src/org/chromium/components/payments/PaymentOptionsUtils.java
index f5bdb4e..f01bf6c 100644
--- a/components/payments/content/android/java/src/org/chromium/components/payments/PaymentOptionsUtils.java
+++ b/components/payments/content/android/java/src/org/chromium/components/payments/PaymentOptionsUtils.java
@@ -7,7 +7,6 @@
 import androidx.annotation.Nullable;
 
 import org.chromium.payments.mojom.PaymentOptions;
-import org.chromium.payments.mojom.PaymentShippingType;
 
 /**
  * A collection of utility methods for PaymentOptions.
@@ -52,46 +51,4 @@
         return String.format("{payerEmail:%s,payerName:%s,payerPhone:%s,shipping:%s}",
                 requestPayerEmail, requestPayerName, requestPayerPhone, requestShipping);
     }
-
-    /**
-     * @param paymentOptions The PaymentOptions of the payment request.
-     * @return Whether requestShipping is specified in the payment request.
-     */
-    public static boolean requestShipping(PaymentOptions paymentOptions) {
-        return paymentOptions != null && paymentOptions.requestShipping;
-    }
-
-    /**
-     * @param paymentOptions The PaymentOptions of the payment request.
-     * @return Whether requestPayerName is specified in the payment request.
-     */
-    public static boolean requestPayerName(PaymentOptions paymentOptions) {
-        return paymentOptions != null && paymentOptions.requestPayerName;
-    }
-
-    /**
-     * @param paymentOptions The PaymentOptions of the payment request.
-     * @return Whether requestPayerPhone is specified in the payment request.
-     */
-    public static boolean requestPayerPhone(PaymentOptions paymentOptions) {
-        return paymentOptions != null && paymentOptions.requestPayerPhone;
-    }
-
-    /**
-     * @param paymentOptions The PaymentOptions of the payment request.
-     * @return Whether requestPayerEmail is specified in the payment request.
-     */
-    public static boolean requestPayerEmail(PaymentOptions paymentOptions) {
-        return paymentOptions != null && paymentOptions.requestPayerEmail;
-    }
-
-    /**
-     * @param options The PaymentOptions of the payment request.
-     * @return The shippingType of the payment request.
-     */
-    public static int getShippingType(PaymentOptions options) {
-        // SHIPPING chosen as default according to w3c spec
-        // (https://w3c.github.io/payment-request/#paymentoptions-dictionary).
-        return options == null ? PaymentShippingType.SHIPPING : options.shippingType;
-    }
 }
\ No newline at end of file
diff --git a/components/payments/content/android/java_templates/ErrorStrings.java.tmpl b/components/payments/content/android/java_templates/ErrorStrings.java.tmpl
index 741b2cf..a120277 100644
--- a/components/payments/content/android/java_templates/ErrorStrings.java.tmpl
+++ b/components/payments/content/android/java_templates/ErrorStrings.java.tmpl
@@ -20,6 +20,8 @@
 
     public static final String INVALID_PAYMENT_DETAILS = "Invalid payment details.";
 
+    public static final String INVALID_PAYMENT_OPTIONS = "Invalid payment options.";
+
     public static final String INVALID_VALIDATION_ERRORS = "Invalid payment validation errors.";
 
     public static final String TAB_OVERVIEW_MODE =
diff --git a/components/permissions/android/java/src/org/chromium/components/permissions/PermissionDialogController.java b/components/permissions/android/java/src/org/chromium/components/permissions/PermissionDialogController.java
index 3865d53..2b05abc8 100644
--- a/components/permissions/android/java/src/org/chromium/components/permissions/PermissionDialogController.java
+++ b/components/permissions/android/java/src/org/chromium/components/permissions/PermissionDialogController.java
@@ -6,6 +6,9 @@
 
 import android.annotation.SuppressLint;
 import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.provider.Settings;
 
 import androidx.annotation.IntDef;
 import androidx.annotation.VisibleForTesting;
@@ -173,18 +176,22 @@
 
     /**
      * Displays the dialog explaining that Chrome has detected an overlay. Offers the user to close
-     * the overlay window and try again.
+     * overlay window or revoke "Draw on top" permission in Android settings.
      */
     private void showFilteredTouchEventDialog(Context context) {
+        // Settings.ACTION_MANAGE_OVERLAY_PERMISSION is only supported on M+ therefore we shouldn't
+        // display this dialog on L. The function won't be called on L anyway because touch
+        // filtering was introduced in M.
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return;
+
         // Don't show another dialog if one is already displayed.
         if (mOverlayDetectedDialogModel != null) return;
 
         ModalDialogProperties.Controller overlayDetectedDialogController =
                 new SimpleModalDialogController(mModalDialogManager, (Integer dismissalCause) -> {
-                    if (dismissalCause == DialogDismissalCause.POSITIVE_BUTTON_CLICKED
-                            && mDialogModel != null) {
-                        mModalDialogManager.dismissDialog(
-                                mDialogModel, DialogDismissalCause.NAVIGATE_BACK_OR_TOUCH_OUTSIDE);
+                    if (dismissalCause == DialogDismissalCause.POSITIVE_BUTTON_CLICKED) {
+                        context.startActivity(
+                                new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION));
                     }
                     mOverlayDetectedDialogModel = null;
                 });
@@ -197,7 +204,7 @@
                         .with(ModalDialogProperties.MESSAGE, context.getResources(),
                                 R.string.overlay_detected_dialog_message)
                         .with(ModalDialogProperties.POSITIVE_BUTTON_TEXT, context.getResources(),
-                                R.string.cancel)
+                                R.string.open_settings)
                         .with(ModalDialogProperties.NEGATIVE_BUTTON_TEXT, context.getResources(),
                                 R.string.try_again)
                         .with(ModalDialogProperties.CANCEL_ON_TOUCH_OUTSIDE, true)
diff --git a/components/permissions/android/permissions_android_strings.grd b/components/permissions/android/permissions_android_strings.grd
index b5d2cf4..60b560d 100644
--- a/components/permissions/android/permissions_android_strings.grd
+++ b/components/permissions/android/permissions_android_strings.grd
@@ -198,10 +198,10 @@
 
       <!-- Overlay detected dialog -->
       <message name="IDS_OVERLAY_DETECTED_DIALOG_TITLE" desc="Title of the dialog that informs the user about detected overlay window that prevents interaction with permissions.">
-        This site can’t ask for your permission
+        Another app is displaying over <ph name="APP_NAME">%1$s<ex>Chrome</ex></ph>
       </message>
       <message name="IDS_OVERLAY_DETECTED_DIALOG_MESSAGE" desc="Dialog message that informs the user about detected overlay window that prevents interaction with permissions.">
-        Close any bubbles or overlays from other apps. Then, try again.
+        To change the permission for this site, close the other app and try again.\n\nIf you can’t close the app, turn off the app’s permission to “Display over other apps” in Android settings.
       </message>
     </messages>
   </release>
diff --git a/components/permissions/android/permissions_android_strings_grd/IDS_OVERLAY_DETECTED_DIALOG_MESSAGE.png.sha1 b/components/permissions/android/permissions_android_strings_grd/IDS_OVERLAY_DETECTED_DIALOG_MESSAGE.png.sha1
index 3136fef..e94e244 100644
--- a/components/permissions/android/permissions_android_strings_grd/IDS_OVERLAY_DETECTED_DIALOG_MESSAGE.png.sha1
+++ b/components/permissions/android/permissions_android_strings_grd/IDS_OVERLAY_DETECTED_DIALOG_MESSAGE.png.sha1
@@ -1 +1 @@
-9d91339a62c7718bb8da43b6702173172723980d
\ No newline at end of file
+59eeb17905a49e3917ea3de287f529e8de3df872
\ No newline at end of file
diff --git a/components/permissions/android/permissions_android_strings_grd/IDS_OVERLAY_DETECTED_DIALOG_TITLE.png.sha1 b/components/permissions/android/permissions_android_strings_grd/IDS_OVERLAY_DETECTED_DIALOG_TITLE.png.sha1
index 3136fef..e94e244 100644
--- a/components/permissions/android/permissions_android_strings_grd/IDS_OVERLAY_DETECTED_DIALOG_TITLE.png.sha1
+++ b/components/permissions/android/permissions_android_strings_grd/IDS_OVERLAY_DETECTED_DIALOG_TITLE.png.sha1
@@ -1 +1 @@
-9d91339a62c7718bb8da43b6702173172723980d
\ No newline at end of file
+59eeb17905a49e3917ea3de287f529e8de3df872
\ No newline at end of file
diff --git a/components/plugins/renderer/plugin_placeholder.cc b/components/plugins/renderer/plugin_placeholder.cc
index a5d3009..94ef8e92 100644
--- a/components/plugins/renderer/plugin_placeholder.cc
+++ b/components/plugins/renderer/plugin_placeholder.cc
@@ -34,7 +34,7 @@
       plugin_(WebViewPlugin::Create(render_frame->GetRenderView(),
                                     this,
                                     render_frame
-                                        ? render_frame->GetWebkitPreferences()
+                                        ? render_frame->GetBlinkPreferences()
                                         : blink::web_pref::WebPreferences(),
                                     html_data,
                                     GURL(kPluginPlaceholderDataURL))),
diff --git a/components/plugins/renderer/webview_plugin.cc b/components/plugins/renderer/webview_plugin.cc
index 55833cea4..0729889 100644
--- a/components/plugins/renderer/webview_plugin.cc
+++ b/components/plugins/renderer/webview_plugin.cc
@@ -16,7 +16,6 @@
 #include "base/numerics/safe_conversions.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "content/public/renderer/render_view.h"
 #include "gin/converter.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "skia/ext/platform_canvas.h"
@@ -268,7 +267,7 @@
                       /*opener=*/nullptr, mojo::NullAssociatedReceiver());
   // ApplyWebPreferences before making a WebLocalFrame so that the frame sees a
   // consistent view of our preferences.
-  content::RenderView::ApplyWebPreferences(preferences, web_view_);
+  blink::WebView::ApplyWebPreferences(preferences, web_view_);
   WebLocalFrame* web_frame = WebLocalFrame::CreateMainFrame(
       web_view_, this, nullptr, base::UnguessableToken::Create(), nullptr);
   // The created WebFrameWidget is owned by the |web_frame|.
diff --git a/components/printing/browser/print_manager.cc b/components/printing/browser/print_manager.cc
index e069a7e..ce665e9 100644
--- a/components/printing/browser/print_manager.cc
+++ b/components/printing/browser/print_manager.cc
@@ -103,9 +103,9 @@
 }
 
 void PrintManager::DidGetPrintedPagesCount(int32_t cookie,
-                                           int32_t number_pages) {
+                                           uint32_t number_pages) {
   DCHECK_GT(cookie, 0);
-  DCHECK_GT(number_pages, 0);
+  DCHECK_GT(number_pages, 0u);
   number_pages_ = number_pages;
 }
 
diff --git a/components/printing/browser/print_manager.h b/components/printing/browser/print_manager.h
index 0055912..49ac5e6 100644
--- a/components/printing/browser/print_manager.h
+++ b/components/printing/browser/print_manager.h
@@ -45,7 +45,7 @@
 #endif
 
   // printing::mojom::PrintManagerHost:
-  void DidGetPrintedPagesCount(int32_t cookie, int32_t number_pages) override;
+  void DidGetPrintedPagesCount(int32_t cookie, uint32_t number_pages) override;
   void DidGetDocumentCookie(int32_t cookie) override;
 #if BUILDFLAG(ENABLE_TAGGED_PDF)
   void SetAccessibilityTree(
@@ -114,7 +114,7 @@
                                const mojom::ScriptedPrintParams& params,
                                IPC::Message* reply_msg) = 0;
 
-  int number_pages_ = 0;  // Number of pages to print in the print job.
+  uint32_t number_pages_ = 0;  // Number of pages to print in the print job.
   int cookie_ = 0;        // The current document cookie.
   // Holds WebContents associated mojo receivers.
   content::WebContentsFrameReceiverSet<printing::mojom::PrintManagerHost>
diff --git a/components/printing/common/print.mojom b/components/printing/common/print.mojom
index c76d05c..3a8f9c3 100644
--- a/components/printing/common/print.mojom
+++ b/components/printing/common/print.mojom
@@ -58,9 +58,9 @@
 struct DidStartPreviewParams {
   // Total page count for the rendered preview. (Not the number of pages the
   // user selected to print.)
-  int32 page_count;
+  uint32 page_count;
   // The list of 0-based page numbers that will be rendered.
-  array<int32> pages_to_render;
+  array<uint32> pages_to_render;
   // number of pages per sheet and should be greater or equal to 1.
   int32 pages_per_sheet;
   // Physical size of the page, including non-printable margins.
@@ -157,7 +157,7 @@
   // value for all the document.
   PrintParams params;
   // If empty, this means a request to render all the printed pages.
-  array<int32> pages;
+  array<uint32> pages;
 };
 
 // Parameters to describe a rendered page.
@@ -179,7 +179,7 @@
 // Parameters to get a print setting from a user before printing.
 struct ScriptedPrintParams {
   int32 cookie;
-  int32 expected_pages_count;
+  uint32 expected_pages_count;
   bool has_selection;
   bool is_scripted;
   bool is_modifiable;
@@ -278,7 +278,7 @@
 interface PrintManagerHost {
   // Tells the browser that the renderer is done calculating the number of
   // rendered pages according to the specified settings.
-  DidGetPrintedPagesCount(int32 cookie, int32 number_pages);
+  DidGetPrintedPagesCount(int32 cookie, uint32 number_pages);
 
   // Sends the document cookie of the current printer query to the browser.
   DidGetDocumentCookie(int32 cookie);
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc
index f2a1f49..ab63f19 100644
--- a/components/printing/renderer/print_render_frame_helper.cc
+++ b/components/printing/renderer/print_render_frame_helper.cc
@@ -20,6 +20,7 @@
 #include "base/logging.h"
 #include "base/memory/shared_memory_mapping.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/process/process_handle.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
@@ -31,7 +32,6 @@
 #include "components/printing/common/print_messages.h"
 #include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_thread.h"
-#include "content/public/renderer/render_view.h"
 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "net/base/escape.h"
@@ -159,7 +159,7 @@
 }
 
 mojom::PrintParamsPtr GetCssPrintParams(blink::WebLocalFrame* frame,
-                                        int page_index,
+                                        uint32_t page_index,
                                         const mojom::PrintParams& page_params) {
   mojom::PrintParamsPtr page_css_params = page_params.Clone();
   int dpi = GetDPI(page_params);
@@ -372,11 +372,11 @@
 }
 
 bool PrintingFrameHasPageSizeStyle(blink::WebLocalFrame* frame,
-                                   int total_page_count) {
+                                   uint32_t total_page_count) {
   if (!frame)
     return false;
   bool frame_has_custom_page_size_style = false;
-  for (int i = 0; i < total_page_count; ++i) {
+  for (uint32_t i = 0; i < total_page_count; ++i) {
     if (frame->GetPageSizeType(i) != blink::PageSizeType::kAuto) {
       // TODO(crbug.com/1016235): We should propagate the page size type all the
       // way to the UI. See the crbug issue for details.
@@ -507,7 +507,7 @@
 
 mojom::PrintParamsPtr CalculatePrintParamsForCss(
     blink::WebLocalFrame* frame,
-    int page_index,
+    uint32_t page_index,
     const mojom::PrintParams& page_params,
     bool ignore_css_margins,
     bool fit_to_page,
@@ -650,12 +650,16 @@
 // static - Not anonymous so that platform implementations can use it.
 void PrintRenderFrameHelper::PrintHeaderAndFooter(
     cc::PaintCanvas* canvas,
-    int page_number,
-    int total_pages,
+    uint32_t page_number,
+    uint32_t total_pages,
     const blink::WebLocalFrame& source_frame,
     float webkit_scale_factor,
     const mojom::PageSizeMargins& page_layout,
     const mojom::PrintParams& params) {
+  DCHECK_LE(total_pages, kMaxPageCount);
+  // |page_number| is 1-based here, so it could be equal to kMaxPageCount.
+  DCHECK_LE(page_number, kMaxPageCount);
+
   cc::PaintCanvasAutoRestore auto_restore(canvas, true);
   canvas->scale(1 / webkit_scale_factor, 1 / webkit_scale_factor);
 
@@ -719,8 +723,8 @@
   options->SetDoubleKey("bottomMargin", page_layout.margin_bottom);
   options->SetDoubleKey("leftMargin", page_layout.margin_left);
   options->SetDoubleKey("rightMargin", page_layout.margin_right);
-  options->SetIntKey("pageNumber", page_number);
-  options->SetIntKey("totalPages", total_pages);
+  options->SetIntKey("pageNumber", base::checked_cast<int>(page_number));
+  options->SetIntKey("totalPages", base::checked_cast<int>(total_pages));
   options->SetStringKey("url", params.url);
   base::string16 title = source_frame.GetDocument().Title().Utf16();
   options->SetStringKey("title", title.empty() ? params.title : title);
@@ -742,7 +746,7 @@
 
 // static - Not anonymous so that platform implementations can use it.
 float PrintRenderFrameHelper::RenderPageContent(blink::WebLocalFrame* frame,
-                                                int page_number,
+                                                uint32_t page_number,
                                                 const gfx::Rect& canvas_area,
                                                 const gfx::Rect& content_area,
                                                 double scale_factor,
@@ -783,7 +787,7 @@
 
   const blink::WebNode& node() const { return node_to_print_; }
 
-  int GetExpectedPageCount() const { return expected_pages_count_; }
+  uint32_t GetExpectedPageCount() const { return expected_pages_count_; }
 
   void FinishPrinting();
 
@@ -822,7 +826,7 @@
   blink::WebPrintParams web_print_params_;
   gfx::Size prev_view_size_;
   gfx::Size prev_scroll_offset_;
-  int expected_pages_count_ = 0;
+  uint32_t expected_pages_count_ = 0;
   base::OnceClosure on_ready_;
   const bool should_print_backgrounds_;
   const bool should_print_selection_only_;
@@ -945,7 +949,7 @@
       /*is_inside_portal=*/false,
       /*compositing_enabled=*/false,
       /*opener=*/nullptr, mojo::NullAssociatedReceiver());
-  content::RenderView::ApplyWebPreferences(prefs, web_view);
+  blink::WebView::ApplyWebPreferences(prefs, web_view);
   blink::WebLocalFrame* main_frame = blink::WebLocalFrame::CreateMainFrame(
       web_view, this, nullptr, base::UnguessableToken::Create(), nullptr);
   frame_.Reset(main_frame);
@@ -1487,7 +1491,7 @@
     auto pauser_to_destroy = print_preview_context_.TakePauser();
 
   prep_frame_view_->CopySelectionIfNeeded(
-      render_frame()->GetWebkitPreferences(),
+      render_frame()->GetBlinkPreferences(),
       base::BindOnce(&PrintRenderFrameHelper::OnFramePreparedForPreviewDocument,
                      weak_ptr_factory_.GetWeakPtr()));
 }
@@ -1523,7 +1527,7 @@
   }
 
   const mojom::PrintParams& print_params = *print_pages_params_->params;
-  const std::vector<int>& pages = print_pages_params_->pages;
+  const std::vector<uint32_t>& pages = print_pages_params_->pages;
 
   bool require_document_metafile =
       print_renderer_ ||
@@ -1594,8 +1598,8 @@
   }
 
   while (!print_preview_context_.IsFinalPageRendered()) {
-    int page_number = print_preview_context_.GetNextPageNumber();
-    DCHECK_GE(page_number, 0);
+    uint32_t page_number = print_preview_context_.GetNextPageNumber();
+    DCHECK_NE(page_number, kInvalidPageIndex);
 
     blink::WebLocalFrame* frame = print_preview_context_.source_frame();
     if (frame) {
@@ -1632,7 +1636,7 @@
   return CREATE_SUCCESS;
 }
 
-bool PrintRenderFrameHelper::RenderPreviewPage(int page_number) {
+bool PrintRenderFrameHelper::RenderPreviewPage(uint32_t page_number) {
   TRACE_EVENT1("print", "PrintRenderFrameHelper::RenderPreviewPage",
                "page_number", page_number);
 
@@ -1856,14 +1860,14 @@
 
   FrameReference frame_ref(frame);
 
-  int expected_page_count = 0;
+  uint32_t expected_page_count = 0;
   if (!CalculateNumberOfPages(frame, node, &expected_page_count)) {
     DidFinishPrinting(FAIL_PRINT_INIT);
     return;  // Failed to init print page settings.
   }
 
   // Some full screen plugins can say they don't want to print.
-  if (!expected_page_count) {
+  if (!expected_page_count || expected_page_count > kMaxPageCount) {
     DidFinishPrinting(FAIL_PRINT);
     return;
   }
@@ -1971,9 +1975,10 @@
 
   prep_frame_view_->StartPrinting();
 
-  int page_count = prep_frame_view_->GetExpectedPageCount();
-  if (!page_count) {
-    LOG(ERROR) << "Can't print 0 pages.";
+  uint32_t page_count = prep_frame_view_->GetExpectedPageCount();
+  if (!page_count || page_count > kMaxPageCount) {
+    LOG(ERROR) << "Can't print 0 pages and the page count couldn't be greater "
+                  "than kMaxPageCount.";
     return DidFinishPrinting(FAIL_PRINT);
   }
 
@@ -2001,12 +2006,12 @@
 }
 
 bool PrintRenderFrameHelper::PrintPagesNative(blink::WebLocalFrame* frame,
-                                              int page_count,
+                                              uint32_t page_count,
                                               bool is_pdf) {
   const mojom::PrintPagesParams& params = *print_pages_params_;
   const mojom::PrintParams& print_params = *params.params;
 
-  std::vector<int> printed_pages = GetPrintedPages(params, page_count);
+  std::vector<uint32_t> printed_pages = GetPrintedPages(params, page_count);
   if (printed_pages.empty())
     return false;
 
@@ -2076,7 +2081,7 @@
 // static - Not anonymous so that platform implementations can use it.
 void PrintRenderFrameHelper::ComputePageLayoutInPointsForCss(
     blink::WebLocalFrame* frame,
-    int page_index,
+    uint32_t page_index,
     const mojom::PrintParams& page_params,
     bool ignore_css_margins,
     double* scale_factor,
@@ -2090,17 +2095,17 @@
 }
 
 // static - Not anonymous so that platform implementations can use it.
-std::vector<int> PrintRenderFrameHelper::GetPrintedPages(
+std::vector<uint32_t> PrintRenderFrameHelper::GetPrintedPages(
     const mojom::PrintPagesParams& params,
-    int page_count) {
-  std::vector<int> printed_pages;
+    uint32_t page_count) {
+  std::vector<uint32_t> printed_pages;
   if (params.pages.empty()) {
-    for (int i = 0; i < page_count; ++i) {
+    for (uint32_t i = 0; i < page_count; ++i) {
       printed_pages.push_back(i);
     }
   } else {
-    for (int page : params.pages) {
-      if (page >= 0 && page < page_count) {
+    for (uint32_t page : params.pages) {
+      if (page != kInvalidPageIndex && page < page_count) {
         printed_pages.push_back(page);
       }
     }
@@ -2151,7 +2156,7 @@
 
 bool PrintRenderFrameHelper::CalculateNumberOfPages(blink::WebLocalFrame* frame,
                                                     const blink::WebNode& node,
-                                                    int* number_of_pages) {
+                                                    uint32_t* number_of_pages) {
   DCHECK(frame);
   bool fit_to_paper_size = !IsPrintingNodeOrPdfFrame(frame, node);
   if (!InitPrintSettings(fit_to_paper_size)) {
@@ -2261,7 +2266,7 @@
 void PrintRenderFrameHelper::GetPrintSettingsFromUser(
     blink::WebLocalFrame* frame,
     const blink::WebNode& node,
-    int expected_pages_count,
+    uint32_t expected_pages_count,
     PrintRequestType print_request_type,
     mojom::PrintPagesParams* print_settings) {
   bool is_scripted = print_request_type == PrintRequestType::kScripted;
@@ -2302,7 +2307,7 @@
   DCHECK(!print_pages_params_->params->selection_only ||
          print_pages_params_->pages.empty());
   prep_frame_view_->CopySelectionIfNeeded(
-      render_frame()->GetWebkitPreferences(),
+      render_frame()->GetBlinkPreferences(),
       base::BindOnce(&PrintRenderFrameHelper::OnFramePreparedForPrintPages,
                      weak_ptr_factory_.GetWeakPtr()));
   return true;
@@ -2310,8 +2315,8 @@
 
 #if !defined(OS_APPLE)
 void PrintRenderFrameHelper::PrintPageInternal(const mojom::PrintParams& params,
-                                               int page_number,
-                                               int page_count,
+                                               uint32_t page_number,
+                                               uint32_t page_count,
                                                double scale_factor,
                                                blink::WebLocalFrame* frame,
                                                MetafileSkia* metafile,
@@ -2507,9 +2512,9 @@
 }
 
 bool PrintRenderFrameHelper::PreviewPageRendered(
-    int page_number,
+    uint32_t page_number,
     std::unique_ptr<MetafileSkia> metafile) {
-  DCHECK_GE(page_number, FIRST_PAGE_INDEX);
+  DCHECK_NE(page_number, kInvalidPageIndex);
   DCHECK(metafile);
   DCHECK(print_preview_context_.IsModifiable());
 
@@ -2626,7 +2631,7 @@
 
 bool PrintRenderFrameHelper::PrintPreviewContext::CreatePreviewDocument(
     std::unique_ptr<PrepareFrameAndViewForPrint> prepared_frame,
-    const std::vector<int>& pages,
+    const std::vector<uint32_t>& pages,
     mojom::SkiaDocumentType doc_type,
     int document_cookie,
     bool require_document_metafile) {
@@ -2638,8 +2643,9 @@
   prep_frame_view_->StartPrinting();
 
   total_page_count_ = prep_frame_view_->GetExpectedPageCount();
-  if (total_page_count_ == 0) {
-    LOG(ERROR) << "CreatePreviewDocument got 0 page count";
+  if (total_page_count_ == 0 || total_page_count_ > kMaxPageCount) {
+    LOG(ERROR) << "CreatePreviewDocument got 0 page count or it's greater than "
+                  "kMaxPageCount.";
     set_error(PREVIEW_ERROR_ZERO_PAGES);
     return false;
   }
@@ -2665,7 +2671,7 @@
   if (pages_to_render_.empty()) {
     // Render all pages.
     pages_to_render_.reserve(total_page_count_);
-    for (int i = 0; i < total_page_count_; ++i)
+    for (uint32_t i = 0; i < total_page_count_; ++i)
       pages_to_render_.push_back(i);
   }
   print_ready_metafile_page_count_ = pages_to_render_.size();
@@ -2743,10 +2749,10 @@
   ClearContext();
 }
 
-int PrintRenderFrameHelper::PrintPreviewContext::GetNextPageNumber() {
+uint32_t PrintRenderFrameHelper::PrintPreviewContext::GetNextPageNumber() {
   DCHECK_EQ(RENDERING, state_);
   if (IsFinalPageRendered())
-    return -1;
+    return kInvalidPageIndex;
   return pages_to_render_[current_page_index_++];
 }
 
@@ -2822,12 +2828,12 @@
   return prep_frame_view_->node();
 }
 
-int PrintRenderFrameHelper::PrintPreviewContext::total_page_count() const {
+uint32_t PrintRenderFrameHelper::PrintPreviewContext::total_page_count() const {
   DCHECK(state_ != UNINITIALIZED);
   return total_page_count_;
 }
 
-const std::vector<int>&
+const std::vector<uint32_t>&
 PrintRenderFrameHelper::PrintPreviewContext::pages_to_render() const {
   DCHECK_EQ(RENDERING, state_);
   return pages_to_render_;
diff --git a/components/printing/renderer/print_render_frame_helper.h b/components/printing/renderer/print_render_frame_helper.h
index 04bb088..0039338 100644
--- a/components/printing/renderer/print_render_frame_helper.h
+++ b/components/printing/renderer/print_render_frame_helper.h
@@ -270,7 +270,7 @@
 
   // Renders a print preview page. |page_number| is 0-based.
   // Returns true if print preview should continue, false on failure.
-  bool RenderPreviewPage(int page_number);
+  bool RenderPreviewPage(uint32_t page_number);
 
   // Finalize the print ready preview document.
   bool FinalizePrintReadyDocument();
@@ -313,7 +313,7 @@
   // Calculate number of pages in source document.
   bool CalculateNumberOfPages(blink::WebLocalFrame* frame,
                               const blink::WebNode& node,
-                              int* number_of_pages);
+                              uint32_t* number_of_pages);
 
 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
   // Set options for print preset from source PDF document.
@@ -331,7 +331,7 @@
   // WARNING: |this| may be gone after this method returns.
   void GetPrintSettingsFromUser(blink::WebLocalFrame* frame,
                                 const blink::WebNode& node,
-                                int expected_pages_count,
+                                uint32_t expected_pages_count,
                                 PrintRequestType print_request_type,
                                 mojom::PrintPagesParams* print_settings);
 
@@ -340,7 +340,7 @@
   void OnFramePreparedForPrintPages();
   void PrintPages();
   bool PrintPagesNative(blink::WebLocalFrame* frame,
-                        int page_count,
+                        uint32_t page_count,
                         bool is_pdf);
   void FinishFramePrinting();
   // Render the frame for printing.
@@ -349,8 +349,8 @@
 
   // Platform-specific helper function for rendering page(s) to |metafile|.
   void PrintPageInternal(const mojom::PrintParams& params,
-                         int page_number,
-                         int page_count,
+                         uint32_t page_number,
+                         uint32_t page_count,
                          double scale_factor,
                          blink::WebLocalFrame* frame,
                          MetafileSkia* metafile,
@@ -362,7 +362,7 @@
   // When method is called, canvas should be setup to draw to |canvas_area|
   // with |scale_factor|.
   static float RenderPageContent(blink::WebLocalFrame* frame,
-                                 int page_number,
+                                 uint32_t page_number,
                                  const gfx::Rect& canvas_area,
                                  const gfx::Rect& content_area,
                                  double scale_factor,
@@ -379,7 +379,7 @@
   // Helper method to get page layout in points and fit to page if needed.
   static void ComputePageLayoutInPointsForCss(
       blink::WebLocalFrame* frame,
-      int page_index,
+      uint32_t page_index,
       const mojom::PrintParams& default_params,
       bool ignore_css_margins,
       double* scale_factor,
@@ -387,15 +387,16 @@
 
   // Return an array of pages to print given the print |params| and an expected
   // |page_count|. Page numbers are zero-based.
-  static std::vector<int> GetPrintedPages(const mojom::PrintPagesParams& params,
-                                          int page_count);
+  static std::vector<uint32_t> GetPrintedPages(
+      const mojom::PrintPagesParams& params,
+      uint32_t page_count);
 
   // Given the |device| and |canvas| to draw on, prints the appropriate headers
   // and footers using strings from |header_footer_info| on to the canvas.
   static void PrintHeaderAndFooter(
       cc::PaintCanvas* canvas,
-      int page_number,
-      int total_pages,
+      uint32_t page_number,
+      uint32_t total_pages,
       const blink::WebLocalFrame& source_frame,
       float webkit_scale_factor,
       const mojom::PageSizeMargins& page_layout_in_points,
@@ -426,7 +427,7 @@
   // |page_number| is 0-based.
   // |metafile| is the rendered page and should be valid.
   // Returns true if print preview should continue, false on failure.
-  bool PreviewPageRendered(int page_number,
+  bool PreviewPageRendered(uint32_t page_number,
                            std::unique_ptr<MetafileSkia> metafile);
 
   // Called when the connection with the |preview_ui_| goes away.
@@ -499,7 +500,7 @@
     // Create the print preview document. |pages| is empty to print all pages.
     bool CreatePreviewDocument(
         std::unique_ptr<PrepareFrameAndViewForPrint> prepared_frame,
-        const std::vector<int>& pages,
+        const std::vector<uint32_t>& pages,
         mojom::SkiaDocumentType doc_type,
         int document_cookie,
         bool require_document_metafile);
@@ -525,7 +526,7 @@
     void Failed(bool report_error);
 
     // Helper functions
-    int GetNextPageNumber();
+    uint32_t GetNextPageNumber();
     bool IsRendering() const;
     bool IsForArc() const;
     bool IsPlugin() const;
@@ -552,8 +553,8 @@
     // generated from it, e.g. copy of selected block.
     const blink::WebNode& prepared_node() const;
 
-    int total_page_count() const;
-    const std::vector<int>& pages_to_render() const;
+    uint32_t total_page_count() const;
+    const std::vector<uint32_t>& pages_to_render() const;
     size_t pages_rendered_count() const;
     MetafileSkia* metafile();
     ContentProxySet* typeface_content_info();
@@ -589,13 +590,13 @@
     std::unique_ptr<MetafileSkia> metafile_;
 
     // Total page count in the renderer.
-    int total_page_count_ = 0;
+    uint32_t total_page_count_ = 0;
 
     // The current page to render.
     int current_page_index_ = 0;
 
     // List of page indices that need to be rendered.
-    std::vector<int> pages_to_render_;
+    std::vector<uint32_t> pages_to_render_;
 
     // True, if the document source is a plugin.
     bool is_plugin_ = false;
diff --git a/components/printing/renderer/print_render_frame_helper_mac.mm b/components/printing/renderer/print_render_frame_helper_mac.mm
index 594eadbe..779a40f 100644
--- a/components/printing/renderer/print_render_frame_helper_mac.mm
+++ b/components/printing/renderer/print_render_frame_helper_mac.mm
@@ -21,8 +21,8 @@
 namespace printing {
 
 void PrintRenderFrameHelper::PrintPageInternal(const mojom::PrintParams& params,
-                                               int page_number,
-                                               int page_count,
+                                               uint32_t page_number,
+                                               uint32_t page_count,
                                                double scale_factor,
                                                blink::WebLocalFrame* frame,
                                                MetafileSkia* metafile,
diff --git a/components/printing/test/mock_printer.cc b/components/printing/test/mock_printer.cc
index 73fc2c0..4f52dcc 100644
--- a/components/printing/test/mock_printer.cc
+++ b/components/printing/test/mock_printer.cc
@@ -75,8 +75,8 @@
       document_cookie_(-1),
       current_document_cookie_(0),
       printer_status_(PRINTER_READY),
-      number_pages_(0),
-      page_number_(0),
+      number_pages_(0u),
+      page_number_(0u),
       is_first_request_(true),
       print_to_pdf_(false),
       preview_request_id_(0),
@@ -146,7 +146,7 @@
 }
 
 void MockPrinter::ScriptedPrint(int cookie,
-                                int expected_pages_count,
+                                uint32_t expected_pages_count,
                                 bool has_selection,
                                 printing::mojom::PrintPagesParams* settings) {
   // Verify the input parameters.
@@ -174,7 +174,7 @@
 
 void MockPrinter::UpdateSettings(int cookie,
                                  printing::mojom::PrintPagesParams* params,
-                                 const std::vector<int>& pages,
+                                 const std::vector<uint32_t>& pages,
                                  int margins_type,
                                  const gfx::Size& page_size,
                                  int scale_factor) {
@@ -190,17 +190,17 @@
   printer_status_ = PRINTER_PRINTING;
 }
 
-void MockPrinter::SetPrintedPagesCount(int cookie, int number_pages) {
+void MockPrinter::SetPrintedPagesCount(int cookie, uint32_t number_pages) {
   // Verify the input parameter and update the printer status so that the
   // RenderViewTest class can verify the this function finishes without errors.
   EXPECT_EQ(document_cookie_, cookie);
   EXPECT_EQ(PRINTER_PRINTING, printer_status_);
-  EXPECT_EQ(0, number_pages_);
-  EXPECT_EQ(0, page_number_);
+  EXPECT_EQ(0u, number_pages_);
+  EXPECT_EQ(0u, page_number_);
 
   // Initialize the job status.
   number_pages_ = number_pages;
-  page_number_ = 0;
+  page_number_ = 0u;
   pages_.clear();
 }
 
diff --git a/components/printing/test/mock_printer.h b/components/printing/test/mock_printer.h
index d24981d..4e1ab15 100644
--- a/components/printing/test/mock_printer.h
+++ b/components/printing/test/mock_printer.h
@@ -77,16 +77,16 @@
   // Functions that handles IPC events.
   void GetDefaultPrintSettings(printing::mojom::PrintParams* params);
   void ScriptedPrint(int cookie,
-                     int expected_pages_count,
+                     uint32_t expected_pages_count,
                      bool has_selection,
                      printing::mojom::PrintPagesParams* settings);
   void UpdateSettings(int cookie,
                       printing::mojom::PrintPagesParams* params,
-                      const std::vector<int>& page_range_array,
+                      const std::vector<uint32_t>& page_range_array,
                       int margins_type,
                       const gfx::Size& page_size,
                       int scale_factor);
-  void SetPrintedPagesCount(int cookie, int number_pages);
+  void SetPrintedPagesCount(int cookie, uint32_t number_pages);
   void PrintPage(const printing::mojom::DidPrintDocumentParams& params);
 
   // Functions that retrieve the output pages.
@@ -136,8 +136,8 @@
   Status printer_status_;
 
   // The output of a printing job.
-  int number_pages_;
-  int page_number_;
+  uint32_t number_pages_;
+  uint32_t page_number_;
 
   // Used only in the preview sequence.
   bool is_first_request_;
diff --git a/components/printing/test/print_mock_render_thread.cc b/components/printing/test/print_mock_render_thread.cc
index 1ea4a319..6c74853 100644
--- a/components/printing/test/print_mock_render_thread.cc
+++ b/components/printing/test/print_mock_render_thread.cc
@@ -109,8 +109,8 @@
 void PrintMockRenderThread::OnDidPreviewPage(
     const printing::mojom::DidPreviewPageParams& params,
     const printing::mojom::PreviewIds& ids) {
-  int page_number = params.page_number;
-  DCHECK_GE(page_number, printing::FIRST_PAGE_INDEX);
+  uint32_t page_number = params.page_number;
+  DCHECK_NE(page_number, printing::kInvalidPageIndex);
   print_preview_pages_remaining_--;
   print_preview_pages_.emplace_back(
       params.page_number, params.content->metafile_data_region.GetSize());
@@ -202,7 +202,7 @@
       job_settings.FindIntKey(printing::kSettingScaleFactor);
   int scale_factor = setting_scale_factor.value_or(100);
 
-  std::vector<int> pages(printing::PageRange::GetPages(new_ranges));
+  std::vector<uint32_t> pages(printing::PageRange::GetPages(new_ranges));
   printer_->UpdateSettings(document_cookie, &params, pages,
                            margins_type.value(), page_size, scale_factor);
   base::Optional<bool> selection_only =
@@ -224,15 +224,16 @@
   print_dialog_user_response_ = response;
 }
 
-void PrintMockRenderThread::set_print_preview_cancel_page_number(int page) {
+void PrintMockRenderThread::set_print_preview_cancel_page_number(
+    uint32_t page) {
   print_preview_cancel_page_number_ = page;
 }
 
-int PrintMockRenderThread::print_preview_pages_remaining() const {
+uint32_t PrintMockRenderThread::print_preview_pages_remaining() const {
   return print_preview_pages_remaining_;
 }
 
-const std::vector<std::pair<int, uint32_t>>&
+const std::vector<std::pair<uint32_t, uint32_t>>&
 PrintMockRenderThread::print_preview_pages() const {
   return print_preview_pages_;
 }
diff --git a/components/printing/test/print_mock_render_thread.h b/components/printing/test/print_mock_render_thread.h
index 7561d8b3..0ee13ef 100644
--- a/components/printing/test/print_mock_render_thread.h
+++ b/components/printing/test/print_mock_render_thread.h
@@ -18,6 +18,7 @@
 #include "components/printing/common/print.mojom-forward.h"
 #include "content/public/test/mock_render_thread.h"
 #include "printing/buildflags/buildflags.h"
+#include "printing/print_job_constants.h"
 
 namespace base {
 class DictionaryValue;
@@ -51,13 +52,13 @@
   void set_print_dialog_user_response(bool response);
 
   // Cancel print preview when print preview has |page| remaining pages.
-  void set_print_preview_cancel_page_number(int page);
+  void set_print_preview_cancel_page_number(uint32_t page);
 
   // Get the number of pages to generate for print preview.
-  int print_preview_pages_remaining() const;
+  uint32_t print_preview_pages_remaining() const;
 
   // Get a vector of print preview pages.
-  const std::vector<std::pair<int, uint32_t>>& print_preview_pages() const;
+  const std::vector<std::pair<uint32_t, uint32_t>>& print_preview_pages() const;
 #endif
 
   MockPrinter* GetPrinter() { return printer_.get(); }
@@ -97,13 +98,13 @@
 
   // Simulates cancelling print preview if |print_preview_pages_remaining_|
   // equals this.
-  int print_preview_cancel_page_number_ = -1;
+  uint32_t print_preview_cancel_page_number_ = printing::kInvalidPageIndex;
 
   // Number of pages to generate for print preview.
-  int print_preview_pages_remaining_ = 0;
+  uint32_t print_preview_pages_remaining_ = 0;
 
   // Vector of <page_number, content_data_size> that were previewed.
-  std::vector<std::pair<int, uint32_t>> print_preview_pages_;
+  std::vector<std::pair<uint32_t, uint32_t>> print_preview_pages_;
 #endif
 
   scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
diff --git a/components/printing/test/print_render_frame_helper_browsertest.cc b/components/printing/test/print_render_frame_helper_browsertest.cc
index 3aa5aa8..8984286 100644
--- a/components/printing/test/print_render_frame_helper_browsertest.cc
+++ b/components/printing/test/print_render_frame_helper_browsertest.cc
@@ -223,7 +223,7 @@
 
   // mojom::PrintManagerInterceptorForTesting
   mojom::PrintManagerHost* GetForwardingInterface() override { return nullptr; }
-  void DidGetPrintedPagesCount(int32_t cookie, int32_t number_pages) override {
+  void DidGetPrintedPagesCount(int32_t cookie, uint32_t number_pages) override {
     if (number_pages_ > 0)
       EXPECT_EQ(number_pages, number_pages_);
     printer_->SetPrintedPagesCount(cookie, number_pages);
@@ -231,7 +231,7 @@
   void DidGetDocumentCookie(int32_t cookie) override {}
   void DidShowPrintDialog() override {}
 
-  void SetExpectedPagesCount(int32_t number_pages) {
+  void SetExpectedPagesCount(uint32_t number_pages) {
     number_pages_ = number_pages;
   }
 
@@ -249,7 +249,7 @@
         std::move(handle)));
   }
 
-  int32_t number_pages_ = -1;
+  uint32_t number_pages_ = 0;
   MockPrinter* printer_;
   mojo::AssociatedReceiver<mojom::PrintManagerHost> receiver_{this};
 };
@@ -309,7 +309,7 @@
   // The renderer should be done calculating the number of rendered pages
   // according to the specified settings defined in the mock render thread.
   // Verify the page count is correct.
-  void VerifyPreviewPageCount(int expected_count) {
+  void VerifyPreviewPageCount(uint32_t expected_count) {
     const IPC::Message* preview_started_message =
         render_thread_->sink().GetUniqueMessageMatching(
             PrintHostMsg_DidStartPreview::ID);
@@ -790,7 +790,7 @@
   }
 
   // |page_number| is 0-based.
-  void VerifyDidPreviewPage(bool expect_generated, int page_number) {
+  void VerifyDidPreviewPage(bool expect_generated, uint32_t page_number) {
     bool msg_found = false;
     uint32_t data_size = 0;
     for (const auto& preview : print_render_thread()->print_preview_pages()) {
@@ -870,7 +870,7 @@
   CreatePrintSettingsDictionary(&dict);
   OnPrintPreview(dict);
 
-  EXPECT_EQ(0, print_render_thread()->print_preview_pages_remaining());
+  EXPECT_EQ(0u, print_render_thread()->print_preview_pages_remaining());
   VerifyDidPreviewPage(true, 0);
   VerifyPreviewPageCount(1);
   VerifyDefaultPageLayout(540, 720, 36, 36, 36, 36, false);
@@ -903,7 +903,7 @@
   dict.SetInteger(kSettingPrinterType, static_cast<int>(PrinterType::kLocal));
   OnPrintPreview(dict);
 
-  EXPECT_EQ(0, print_render_thread()->print_preview_pages_remaining());
+  EXPECT_EQ(0u, print_render_thread()->print_preview_pages_remaining());
   VerifyDefaultPageLayout(519, 432, 216, 144, 21, 72, false);
   VerifyDidPreviewPage(true, 0);
   VerifyPreviewPageCount(1);
@@ -929,7 +929,7 @@
                   static_cast<int>(mojom::MarginType::kNoMargins));
   OnPrintPreview(dict);
 
-  EXPECT_EQ(0, print_render_thread()->print_preview_pages_remaining());
+  EXPECT_EQ(0u, print_render_thread()->print_preview_pages_remaining());
   VerifyDefaultPageLayout(612, 792, 0, 0, 0, 0, true);
   VerifyDidPreviewPage(true, 0);
   VerifyPreviewPageCount(1);
@@ -954,7 +954,7 @@
                   static_cast<int>(mojom::MarginType::kPrintableAreaMargins));
   OnPrintPreview(dict);
 
-  EXPECT_EQ(0, print_render_thread()->print_preview_pages_remaining());
+  EXPECT_EQ(0u, print_render_thread()->print_preview_pages_remaining());
   // Since PRINT_TO_PDF is selected, pdf page size is equal to print media page
   // size.
   VerifyDefaultPageLayout(252, 252, 18, 18, 18, 18, true);
@@ -1080,7 +1080,7 @@
   dict.SetInteger(kSettingPrinterType, static_cast<int>(PrinterType::kLocal));
   OnPrintPreview(dict);
 
-  EXPECT_EQ(0, print_render_thread()->print_preview_pages_remaining());
+  EXPECT_EQ(0u, print_render_thread()->print_preview_pages_remaining());
   VerifyDidPreviewPage(true, 0);
   VerifyDidPreviewPage(true, 1);
   VerifyPreviewPageCount(2);
@@ -1115,7 +1115,7 @@
   CreatePrintSettingsDictionary(&dict);
   OnPrintPreview(dict);
 
-  EXPECT_EQ(0, print_render_thread()->print_preview_pages_remaining());
+  EXPECT_EQ(0u, print_render_thread()->print_preview_pages_remaining());
   // Since PRINT_TO_PDF is selected, pdf page size is equal to print media page
   // size.
   VerifyDefaultPageLayout(915, 648, 216, 144, 21, 72, true);
@@ -1140,7 +1140,7 @@
   dict.SetInteger(kSettingPrinterType, static_cast<int>(PrinterType::kLocal));
   OnPrintPreview(dict);
 
-  EXPECT_EQ(0, print_render_thread()->print_preview_pages_remaining());
+  EXPECT_EQ(0u, print_render_thread()->print_preview_pages_remaining());
   VerifyDefaultPageLayout(216, 216, 288, 288, 198, 198, true);
   VerifyDidPreviewPage(true, 0);
   VerifyPreviewPageCount(1);
@@ -1174,7 +1174,7 @@
   dict.SetInteger(kSettingPrinterType, static_cast<int>(PrinterType::kLocal));
   OnPrintPreview(dict);
 
-  EXPECT_EQ(0, print_render_thread()->print_preview_pages_remaining());
+  EXPECT_EQ(0u, print_render_thread()->print_preview_pages_remaining());
   VerifyDefaultPageLayout(571, 652, 69, 71, 20, 21, true);
   VerifyDidPreviewPage(true, 0);
   VerifyPreviewPageCount(1);
@@ -1200,7 +1200,7 @@
                   static_cast<int>(mojom::MarginType::kNoMargins));
   OnPrintPreview(dict);
 
-  EXPECT_EQ(0, print_render_thread()->print_preview_pages_remaining());
+  EXPECT_EQ(0u, print_render_thread()->print_preview_pages_remaining());
   VerifyDefaultPageLayout(792, 612, 0, 0, 0, 0, true);
   VerifyDidPreviewPage(true, 0);
   VerifyPreviewPageCount(1);
@@ -1225,7 +1225,7 @@
                   static_cast<int>(mojom::MarginType::kCustomMargins));
   OnPrintPreview(dict);
 
-  EXPECT_EQ(0, print_render_thread()->print_preview_pages_remaining());
+  EXPECT_EQ(0u, print_render_thread()->print_preview_pages_remaining());
   VerifyDefaultPageLayout(748, 568, 21, 23, 21, 23, true);
   VerifyDidPreviewPage(true, 0);
   VerifyPreviewPageCount(1);
@@ -1246,7 +1246,7 @@
 
   OnPrintPreview(dict);
 
-  EXPECT_EQ(0, print_render_thread()->print_preview_pages_remaining());
+  EXPECT_EQ(0u, print_render_thread()->print_preview_pages_remaining());
   VerifyDidPreviewPage(true, 0);
   VerifyDidPreviewPage(true, 1);
   VerifyDidPreviewPage(true, 2);
@@ -1283,7 +1283,7 @@
   // generated, the print_preview_pages_remaining() result is 1.
   // TODO(thestig): Fix this on the browser side to accept the number of actual
   // pages generated instead, or to take both page counts.
-  EXPECT_EQ(1, print_render_thread()->print_preview_pages_remaining());
+  EXPECT_EQ(1u, print_render_thread()->print_preview_pages_remaining());
   VerifyDidPreviewPage(false, 0);
   VerifyDidPreviewPage(true, 1);
   VerifyDidPreviewPage(true, 2);
@@ -1310,7 +1310,7 @@
 
   OnPrintPreview(dict);
 
-  EXPECT_EQ(0, print_render_thread()->print_preview_pages_remaining());
+  EXPECT_EQ(0u, print_render_thread()->print_preview_pages_remaining());
   VerifyDidPreviewPage(true, 0);
   VerifyPreviewPageCount(1);
   VerifyPrintPreviewCancelled(false);
@@ -1335,7 +1335,7 @@
 
   OnPrintPreview(dict);
 
-  EXPECT_EQ(0, print_render_thread()->print_preview_pages_remaining());
+  EXPECT_EQ(0u, print_render_thread()->print_preview_pages_remaining());
   VerifyDidPreviewPage(true, 0);
   VerifyPreviewPageCount(2);
   VerifyPrintPreviewCancelled(false);
@@ -1350,7 +1350,7 @@
 TEST_F(MAYBE_PrintRenderFrameHelperPreviewTest, PrintPreviewCancel) {
   LoadHTML(kLongPageHTML);
 
-  const int kCancelPage = 3;
+  const uint32_t kCancelPage = 3;
   print_render_thread()->set_print_preview_cancel_page_number(kCancelPage);
   // Fill in some dummy values.
   base::DictionaryValue dict;
@@ -1383,7 +1383,7 @@
 
   // We should have received invalid printer settings from |printer_|.
   VerifyPrintPreviewInvalidPrinterSettings(true);
-  EXPECT_EQ(0, print_render_thread()->print_preview_pages_remaining());
+  EXPECT_EQ(0u, print_render_thread()->print_preview_pages_remaining());
 
   // It should receive the invalid printer settings message only.
   VerifyPrintPreviewFailed(false);
@@ -1405,7 +1405,7 @@
   OnPrintPreview(dict);
 
   VerifyPrintPreviewInvalidPrinterSettings(true);
-  EXPECT_EQ(0, print_render_thread()->print_preview_pages_remaining());
+  EXPECT_EQ(0u, print_render_thread()->print_preview_pages_remaining());
 
   // It should receive the invalid printer settings message only.
   VerifyPrintPreviewFailed(false);
@@ -1427,7 +1427,7 @@
   OnPrintPreview(dict);
 
   VerifyPrintPreviewInvalidPrinterSettings(true);
-  EXPECT_EQ(0, print_render_thread()->print_preview_pages_remaining());
+  EXPECT_EQ(0u, print_render_thread()->print_preview_pages_remaining());
 
   // It should receive the invalid printer settings message only.
   VerifyPrintPreviewFailed(false);
@@ -1444,7 +1444,7 @@
   CreatePrintSettingsDictionary(&dict);
   OnPrintPreview(dict);
 
-  EXPECT_EQ(0, print_render_thread()->print_preview_pages_remaining());
+  EXPECT_EQ(0u, print_render_thread()->print_preview_pages_remaining());
   VerifyDidPreviewPage(true, 0);
   VerifyPreviewPageCount(1);
   VerifyDefaultPageLayout(540, 720, 36, 36, 36, 36, false);
diff --git a/components/search_engines/BUILD.gn b/components/search_engines/BUILD.gn
index aa65c00..1f7e2e69 100644
--- a/components/search_engines/BUILD.gn
+++ b/components/search_engines/BUILD.gn
@@ -50,6 +50,7 @@
   ]
 
   public_deps = [
+    ":prepopulated_engines",
     ":search_engine_type",
     "//base",
     "//components/google/core/common",
@@ -61,7 +62,6 @@
   ]
 
   deps = [
-    ":prepopulated_engines",
     "//base:i18n",
     "//components/country_codes",
     "//components/database_utils",
diff --git a/components/translate/core/browser/BUILD.gn b/components/translate/core/browser/BUILD.gn
index 0c62970..5198ffb 100644
--- a/components/translate/core/browser/BUILD.gn
+++ b/components/translate/core/browser/BUILD.gn
@@ -26,6 +26,9 @@
     "translate_language_list.h",
     "translate_manager.cc",
     "translate_manager.h",
+    "translate_metrics_logger.h",
+    "translate_metrics_logger_impl.cc",
+    "translate_metrics_logger_impl.h",
     "translate_prefs.cc",
     "translate_prefs.h",
     "translate_ranker.h",
diff --git a/components/translate/core/browser/translate_metrics_logger.h b/components/translate/core/browser/translate_metrics_logger.h
new file mode 100644
index 0000000..303d8ca
--- /dev/null
+++ b/components/translate/core/browser/translate_metrics_logger.h
@@ -0,0 +1,31 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_METRICS_LOGGER_H_
+#define COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_METRICS_LOGGER_H_
+
+namespace translate {
+
+// TranslateMetricsLogger tracks and logs various UKM and UMA metrics for Chrome
+// Translate over the course of a page load.
+class TranslateMetricsLogger {
+ public:
+  TranslateMetricsLogger() = default;
+  virtual ~TranslateMetricsLogger() = default;
+
+  TranslateMetricsLogger(const TranslateMetricsLogger&) = delete;
+  TranslateMetricsLogger& operator=(const TranslateMetricsLogger&) = delete;
+
+  // Tracks the state of the page over the course of a page load.
+  virtual void OnPageLoadStart(bool is_foreground) = 0;
+  virtual void OnForegroundChange(bool is_foreground) = 0;
+
+  // Logs all stored page load metrics. If is_final is |true| then RecordMetrics
+  // won't be called again.
+  virtual void RecordMetrics(bool is_final) = 0;
+};
+
+}  // namespace translate
+
+#endif  // COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_METRICS_LOGGER_H_
diff --git a/components/translate/core/browser/translate_metrics_logger_impl.cc b/components/translate/core/browser/translate_metrics_logger_impl.cc
new file mode 100644
index 0000000..bc96ef9
--- /dev/null
+++ b/components/translate/core/browser/translate_metrics_logger_impl.cc
@@ -0,0 +1,24 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/translate/core/browser/translate_metrics_logger_impl.h"
+
+namespace translate {
+
+void TranslateMetricsLoggerImpl::OnPageLoadStart(bool is_foreground) {
+  is_foreground_ = is_foreground;
+}
+
+void TranslateMetricsLoggerImpl::OnForegroundChange(bool is_foreground) {
+  is_foreground_ = is_foreground;
+}
+
+void TranslateMetricsLoggerImpl::RecordMetrics(bool is_final) {
+  // TODO(curranmax): Log UKM and UMA metrics now that the page load is.
+  // completed. https://crbug.com/1114868.
+
+  sequence_no_++;
+}
+
+}  // namespace translate
diff --git a/components/translate/core/browser/translate_metrics_logger_impl.h b/components/translate/core/browser/translate_metrics_logger_impl.h
new file mode 100644
index 0000000..d9803e2
--- /dev/null
+++ b/components/translate/core/browser/translate_metrics_logger_impl.h
@@ -0,0 +1,49 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_METRICS_LOGGER_IMPL_H_
+#define COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_METRICS_LOGGER_IMPL_H_
+
+#include <memory>
+
+#include "components/translate/core/browser/translate_metrics_logger.h"
+
+namespace translate {
+
+// TranslateMetricsLogger tracks and logs various UKM and UMA metrics for Chrome
+// Translate over the course of a page load.
+class TranslateMetricsLoggerImpl : public TranslateMetricsLogger {
+ public:
+  TranslateMetricsLoggerImpl() = default;
+  ~TranslateMetricsLoggerImpl() override = default;
+
+  TranslateMetricsLoggerImpl(const TranslateMetricsLoggerImpl&) = delete;
+  TranslateMetricsLoggerImpl& operator=(const TranslateMetricsLoggerImpl&) =
+      delete;
+
+  // TranslateMetricsLogger
+  void OnPageLoadStart(bool is_foreground) override;
+  void OnForegroundChange(bool is_foreground) override;
+  void RecordMetrics(bool is_final) override;
+
+  // TODO(curranmax): Connect to TranslateManager so metrics can be collected
+  // from the rest of the Translate code. https://crbug.com/1114868.
+  // TODO(curranmax): Add appropriate functions for the Translate code to log
+  // relevant events. https://crbug.com/1114868.
+ private:
+  // Since |RecordMetrics()| can be called multiple times, such as when Chrome
+  // is backgrounded and reopened, we use |sequence_no_| to differentiate the
+  // recorded UKM protos.
+  unsigned int sequence_no_{0};
+
+  // Tracks if the associated page is in the foreground (|true|) or the
+  // background (|false|)
+  bool is_foreground_{false};
+};
+
+}  // namespace translate
+
+// TODO(curranmax): Add unit tests for this class. https://crbug.com/1114868.
+
+#endif  // COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_METRICS_LOGGER_IMPL_H_
diff --git a/content/browser/android/content_startup_flags.cc b/content/browser/android/content_startup_flags.cc
index 9fcc54f..971e9c3 100644
--- a/content/browser/android/content_startup_flags.cc
+++ b/content/browser/android/content_startup_flags.cc
@@ -12,6 +12,7 @@
 #include "content/public/browser/android/compositor.h"
 #include "content/public/common/content_switches.h"
 #include "gpu/command_buffer/service/gpu_switches.h"
+#include "third_party/blink/public/common/switches.h"
 #include "ui/base/ui_base_switches.h"
 
 namespace content {
@@ -40,7 +41,7 @@
       base::android::SDK_VERSION_MARSHMALLOW) {
     parsed_command_line->AppendSwitch(switches::kEnableLongpressDragSelection);
     parsed_command_line->AppendSwitchASCII(
-        switches::kTouchTextSelectionStrategy, "direction");
+        blink::switches::kTouchTextSelectionStrategy, "direction");
   }
 
   // On legacy low-memory devices the behavior has not been studied with regard
diff --git a/content/browser/browser_interface_binders.cc b/content/browser/browser_interface_binders.cc
index c80f820..d59b3571 100644
--- a/content/browser/browser_interface_binders.cc
+++ b/content/browser/browser_interface_binders.cc
@@ -74,6 +74,7 @@
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/appcache/appcache.mojom.h"
 #include "third_party/blink/public/mojom/background_fetch/background_fetch.mojom.h"
+#include "third_party/blink/public/mojom/background_sync/background_sync.mojom.h"
 #include "third_party/blink/public/mojom/badging/badging.mojom.h"
 #include "third_party/blink/public/mojom/bluetooth/web_bluetooth.mojom.h"
 #include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom.h"
@@ -679,6 +680,14 @@
                           base::Unretained(host)));
 #endif
 
+  map->Add<blink::mojom::OneShotBackgroundSyncService>(
+      base::BindRepeating(&RenderProcessHost::CreateOneShotSyncService,
+                          base::Unretained(host->GetProcess())));
+
+  map->Add<blink::mojom::PeriodicBackgroundSyncService>(
+      base::BindRepeating(&RenderProcessHost::CreatePeriodicSyncService,
+                          base::Unretained(host->GetProcess())));
+
   map->Add<media::mojom::VideoDecodePerfHistory>(
       base::BindRepeating(&RenderProcessHost::BindVideoDecodePerfHistory,
                           base::Unretained(host->GetProcess())));
@@ -1023,6 +1032,12 @@
   // render process host binders
   map->Add<media::mojom::VideoDecodePerfHistory>(BindServiceWorkerReceiver(
       &RenderProcessHostImpl::BindVideoDecodePerfHistory, host));
+  map->Add<blink::mojom::OneShotBackgroundSyncService>(
+      BindServiceWorkerReceiver(
+          &RenderProcessHostImpl::CreateOneShotSyncService, host));
+  map->Add<blink::mojom::PeriodicBackgroundSyncService>(
+      BindServiceWorkerReceiver(
+          &RenderProcessHostImpl::CreatePeriodicSyncService, host));
 }
 
 void PopulateBinderMapWithContext(
diff --git a/content/browser/renderer_host/input/composited_scrolling_browsertest.cc b/content/browser/renderer_host/input/composited_scrolling_browsertest.cc
index decdc08..3b69413 100644
--- a/content/browser/renderer_host/input/composited_scrolling_browsertest.cc
+++ b/content/browser/renderer_host/input/composited_scrolling_browsertest.cc
@@ -200,7 +200,7 @@
     if (enable_composited_scrolling)
       cmd->AppendSwitch(blink::switches::kEnablePreferCompositingToLCDText);
     else
-      cmd->AppendSwitch(switches::kDisableThreadedScrolling);
+      cmd->AppendSwitch(blink::switches::kDisableThreadedScrolling);
   }
 
   bool CompositingEnabled() { return GetParam(); }
diff --git a/content/browser/renderer_host/input/scroll_latency_browsertest.cc b/content/browser/renderer_host/input/scroll_latency_browsertest.cc
index 786177a..b0a6328 100644
--- a/content/browser/renderer_host/input/scroll_latency_browsertest.cc
+++ b/content/browser/renderer_host/input/scroll_latency_browsertest.cc
@@ -29,6 +29,7 @@
 #include "content/shell/browser/shell.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/common/input/synthetic_web_input_event_builders.h"
+#include "third_party/blink/public/common/switches.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/native_theme/native_theme_features.h"
 
@@ -100,7 +101,7 @@
   void SetUpCommandLine(base::CommandLine* command_line) override {
     ContentBrowserTest::SetUpCommandLine(command_line);
     if (disable_threaded_scrolling_) {
-      command_line->AppendSwitch(::switches::kDisableThreadedScrolling);
+      command_line->AppendSwitch(::blink::switches::kDisableThreadedScrolling);
     }
     // Set the scroll animation duration to a large number so that
     // we ensure secondary GestureScrollUpdates update the animation
diff --git a/content/browser/renderer_host/render_frame_host_impl_browsertest.cc b/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
index 29d9411..9b1c9de 100644
--- a/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
+++ b/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
@@ -3717,26 +3717,17 @@
 // Check that same site navigation correctly resets document_used_web_otp_.
 IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
                        SameSiteNavigationResetsDocumentUsedWebOTP) {
-  const GURL first_url(embedded_test_server()->GetURL("/title1.html"));
-  ASSERT_TRUE(NavigateToURL(shell(), first_url));
+  const GURL first_url(
+      embedded_test_server()->GetURL("/page_with_webotp.html"));
+  const GURL second_url(embedded_test_server()->GetURL("/empty.html"));
 
-  std::string script = R"(
-    var element = document.createElement('div');
-    document.body.appendChild(element);
-    navigator.credentials.get({
-      otp: {transport:['sms']}
-    })
-    .then(content => element.value = content.code);
-  )";
-  EXPECT_TRUE(ExecuteScript(web_contents(), script));
-  EXPECT_TRUE(WaitForLoadStop(web_contents()));
+  // Load a URL that maps to the same SiteInstance as the second URL, to make
+  // sure the second navigation will not be cross-process.
+  ASSERT_TRUE(NavigateToURL(shell(), first_url));
 
   RenderFrameHostImpl* main_rfh = web_contents()->GetMainFrame();
   EXPECT_TRUE(main_rfh->DocumentUsedWebOTP());
 
-  // Loads a URL that maps to the same SiteInstance as the first URL, to make
-  // sure the navigation will not be cross-process.
-  const GURL second_url(embedded_test_server()->GetURL("/title2.html"));
   ASSERT_TRUE(NavigateToURL(shell(), second_url));
   EXPECT_FALSE(main_rfh->DocumentUsedWebOTP());
 }
diff --git a/content/browser/renderer_host/render_frame_proxy_host.cc b/content/browser/renderer_host/render_frame_proxy_host.cc
index b73b351..31bd79b 100644
--- a/content/browser/renderer_host/render_frame_proxy_host.cc
+++ b/content/browser/renderer_host/render_frame_proxy_host.cc
@@ -14,6 +14,7 @@
 #include "content/browser/bad_message.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
 #include "content/browser/child_process_security_policy_impl.h"
+#include "content/browser/renderer_host/agent_scheduling_group_host.h"
 #include "content/browser/renderer_host/cross_process_frame_connector.h"
 #include "content/browser/renderer_host/frame_tree.h"
 #include "content/browser/renderer_host/frame_tree_node.h"
@@ -183,7 +184,9 @@
 }
 
 bool RenderFrameProxyHost::Send(IPC::Message* msg) {
-  return GetProcess()->Send(msg);
+  return static_cast<SiteInstanceImpl*>(site_instance_.get())
+      ->GetAgentSchedulingGroup()
+      .Send(msg);
 }
 
 bool RenderFrameProxyHost::OnMessageReceived(const IPC::Message& msg) {
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index ff226c9..d766168 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -2313,14 +2313,6 @@
 
   AddUIThreadInterface(
       registry.get(),
-      base::BindRepeating(&RenderProcessHostImpl::CreateOneShotSyncService,
-                          weak_factory_.GetWeakPtr()));
-  AddUIThreadInterface(
-      registry.get(),
-      base::BindRepeating(&RenderProcessHostImpl::CreatePeriodicSyncService,
-                          weak_factory_.GetWeakPtr()));
-  AddUIThreadInterface(
-      registry.get(),
       base::BindRepeating(&RenderProcessHostImpl::CreateDomStorageProvider,
                           weak_factory_.GetWeakPtr()));
   AddUIThreadInterface(
@@ -2665,6 +2657,7 @@
 void RenderProcessHostImpl::CreateOneShotSyncService(
     mojo::PendingReceiver<blink::mojom::OneShotBackgroundSyncService>
         receiver) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   storage_partition_impl_->GetBackgroundSyncContext()->CreateOneShotSyncService(
       std::move(receiver));
 }
@@ -2672,6 +2665,7 @@
 void RenderProcessHostImpl::CreatePeriodicSyncService(
     mojo::PendingReceiver<blink::mojom::PeriodicBackgroundSyncService>
         receiver) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   storage_partition_impl_->GetBackgroundSyncContext()
       ->CreatePeriodicSyncService(std::move(receiver));
 }
@@ -3313,7 +3307,6 @@
     switches::kAndroidFontsPath,
     switches::kAudioBufferSize,
     switches::kAutoplayPolicy,
-    switches::kBlinkSettings,
     switches::kMojoCoreLibraryPath,
     switches::kDisable2dCanvasImageChromium,
     switches::kDisableYUVImageDecoding,
@@ -3343,7 +3336,6 @@
     switches::kDisableSkiaRuntimeOpts,
     switches::kDisableSpeechAPI,
     switches::kDisableThreadedCompositing,
-    switches::kDisableThreadedScrolling,
     switches::kDisableTouchDragDrop,
     switches::kDisableV8IdleTasks,
     switches::kDisableVideoCaptureUseGpuMemoryBuffer,
@@ -3393,10 +3385,8 @@
     switches::kMaxActiveWebGLContexts,
     switches::kMSEAudioBufferSizeLimitMb,
     switches::kMSEVideoBufferSizeLimitMb,
-    switches::kNetworkQuietTimeout,
     switches::kNoZygote,
     switches::kOverridePluginPowerSaverForTesting,
-    switches::kPassiveListenersDefault,
     switches::kPerfettoDisableInterning,
     switches::kPpapiInProcess,
     switches::kProfilingAtStart,
@@ -3412,7 +3402,6 @@
     switches::kSkiaResourceCacheLimitMb,
     switches::kTestType,
     switches::kTouchEventFeatureDetection,
-    switches::kTouchTextSelectionStrategy,
     switches::kTraceToConsole,
     switches::kUseFakeCodecForPeerConnection,
     switches::kUseFakeUIForMediaStream,
@@ -3426,20 +3415,25 @@
     switches::kWebglMSAASampleCount,
     // Please keep these in alphabetical order.
     blink::switches::kAllowPreCommitInput,
+    blink::switches::kBlinkSettings,
     blink::switches::kDefaultTileWidth,
     blink::switches::kDefaultTileHeight,
     blink::switches::kDisableImageAnimationResync,
     blink::switches::kDisableLowResTiling,
     blink::switches::kDisablePreferCompositingToLCDText,
     blink::switches::kDisableRGBA4444Textures,
+    blink::switches::kDisableThreadedScrolling,
     blink::switches::kEnableLowResTiling,
     blink::switches::kEnablePreferCompositingToLCDText,
     blink::switches::kEnableRGBA4444Textures,
     blink::switches::kMinHeightForGpuRasterTile,
     blink::switches::kMaxUntiledLayerWidth,
     blink::switches::kMaxUntiledLayerHeight,
+    blink::switches::kNetworkQuietTimeout,
+    blink::switches::kPassiveListenersDefault,
     blink::switches::kShowLayoutShiftRegions,
     blink::switches::kShowPaintRects,
+    blink::switches::kTouchTextSelectionStrategy,
     // Please keep these in alphabetical order. Compositor switches here
     // should also be added to
     // chrome/browser/chromeos/login/chrome_restart_request.cc.
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index d640c306..ca39b61 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -584,6 +584,20 @@
       mojo::PendingReceiver<media::mojom::VideoDecodePerfHistory> receiver)
       override;
 
+  // Binds |receiver| to a OneShotBackgroundSyncService instance owned by the
+  // StoragePartition associated with the render process host, and is used by
+  // frames and service workers via BrowserInterfaceBroker.
+  void CreateOneShotSyncService(
+      mojo::PendingReceiver<blink::mojom::OneShotBackgroundSyncService>
+          receiver) override;
+
+  // Binds |receiver| to a PeriodicBackgroundSyncService instance owned by the
+  // StoragePartition associated with the render process host, and is used by
+  // frames and service workers via BrowserInterfaceBroker.
+  void CreatePeriodicSyncService(
+      mojo::PendingReceiver<blink::mojom::PeriodicBackgroundSyncService>
+          receiver) override;
+
   // Binds |receiver| to a QuotaManagerHost instance indirectly owned by the
   // StoragePartition associated with the render process host. Used by frames
   // and workers via BrowserInterfaceBroker.
@@ -780,12 +794,6 @@
       mojo::PendingReceiver<blink::mojom::WebDatabaseHost> receiver);
   void BindAecDumpManager(
       mojo::PendingReceiver<blink::mojom::AecDumpManager> receiver);
-  void CreateOneShotSyncService(
-      mojo::PendingReceiver<blink::mojom::OneShotBackgroundSyncService>
-          receiver);
-  void CreatePeriodicSyncService(
-      mojo::PendingReceiver<blink::mojom::PeriodicBackgroundSyncService>
-          receiver);
   void BindPushMessagingManager(
       mojo::PendingReceiver<blink::mojom::PushMessaging> receiver);
   void BindP2PSocketManager(
diff --git a/content/public/android/java/src/org/chromium/content/browser/font/AndroidFontLookupImpl.java b/content/public/android/java/src/org/chromium/content/browser/font/AndroidFontLookupImpl.java
index b5618cf..e4486ee6 100644
--- a/content/public/android/java/src/org/chromium/content/browser/font/AndroidFontLookupImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/font/AndroidFontLookupImpl.java
@@ -9,7 +9,9 @@
 import android.content.Context;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.ParcelFileDescriptor;
+import android.os.SystemClock;
 
+import androidx.annotation.IntDef;
 import androidx.annotation.VisibleForTesting;
 import androidx.core.provider.FontRequest;
 import androidx.core.provider.FontsContractCompat;
@@ -18,6 +20,7 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
+import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.task.PostTask;
 import org.chromium.base.task.TaskTraits;
 import org.chromium.blink.mojom.AndroidFontLookup;
@@ -45,6 +48,12 @@
     private static final String TAG = "AndroidFontLookup";
     private static final String READ_ONLY_MODE = "r";
 
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    static final String FETCH_FONT_HISTOGRAM = "Android.FontLookup.FetchFontResult";
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    static final String MATCH_LOCAL_FONT_BY_UNIQUE_NAME_HISTOGRAM =
+            "Android.FontLookup.MatchLocalFontByUniqueName.Time";
+
     private final Context mAppContext;
     private FontsContractWrapper mFontsContract = new FontsContractWrapper();
     /**
@@ -59,6 +68,24 @@
         mAppContext = appContext;
     }
 
+    // These values are persisted to logs. Entries should not be renumbered and
+    // numeric values should never be reused. These values must stay in sync with enums.xml.
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    @IntDef({FetchFontResult.SUCCESS, FetchFontResult.FAILED_UNEXPECTED_NAME,
+            FetchFontResult.FAILED_STATUS_CODE, FetchFontResult.FAILED_NON_UNIQUE_RESULT,
+            FetchFontResult.FAILED_RESULT_CODE, FetchFontResult.FAILED_FILE_OPEN,
+            FetchFontResult.FAILED_EXCEPTION})
+    @interface FetchFontResult {
+        int SUCCESS = 0;
+        int FAILED_UNEXPECTED_NAME = 1;
+        int FAILED_STATUS_CODE = 2;
+        int FAILED_NON_UNIQUE_RESULT = 3;
+        int FAILED_RESULT_CODE = 4;
+        int FAILED_FILE_OPEN = 5;
+        int FAILED_EXCEPTION = 6;
+        int COUNT = 7;
+    }
+
     /**
      * Verifies which fonts are available from GMS Core and can be fetched quickly, and
      * asynchronously responds with that list. These fonts should have already been preloaded via
@@ -99,6 +126,8 @@
     @Override
     public void matchLocalFontByUniqueName(
             String fontUniqueName, MatchLocalFontByUniqueNameResponse callback) {
+        long startTimeMs = SystemClock.elapsedRealtime();
+
         // Get executor associated with the current thread for running Mojo callback.
         Core core = CoreImpl.getInstance();
         Executor executor = ExecutorFactory.getExecutorForCurrentThread(core);
@@ -106,17 +135,19 @@
         // Post synchronous font request to background worker thread.
         PostTask.postTask(TaskTraits.USER_BLOCKING, () -> {
             ParcelFileDescriptor fileDescriptor = tryFetchFont(fontUniqueName);
-            if (fileDescriptor == null) {
-                executor.execute(() -> callback.call(null));
-                return;
+            File file = null;
+
+            if (fileDescriptor != null) {
+                // Wrap file descriptor as an opened Mojo file handle.
+                file = new File();
+                file.fd = core.wrapFileDescriptor(fileDescriptor);
+                file.async = false;
             }
 
-            // Wrap file descriptor as an opened Mojo file handle.
-            File file = new File();
-            file.fd = core.wrapFileDescriptor(fileDescriptor);
-            file.async = false;
-
-            executor.execute(() -> callback.call(file));
+            final File result = file;
+            RecordHistogram.recordTimesHistogram(MATCH_LOCAL_FONT_BY_UNIQUE_NAME_HISTOGRAM,
+                    SystemClock.elapsedRealtime() - startTimeMs);
+            executor.execute(() -> callback.call(result));
         });
     }
 
@@ -124,6 +155,7 @@
         String query = mFullFontNameToQuery.get(fontUniqueName);
         if (query == null) {
             Log.d(TAG, "Query format not found for full font name: %s", fontUniqueName);
+            logFetchFontResult(FetchFontResult.FAILED_UNEXPECTED_NAME);
             return null;
         }
 
@@ -137,6 +169,7 @@
             if (fontFamilyResult.getStatusCode() != FontFamilyResult.STATUS_OK) {
                 Log.d(TAG, "Font fetch failed with status code: %d",
                         fontFamilyResult.getStatusCode());
+                logFetchFontResult(FetchFontResult.FAILED_STATUS_CODE);
                 return null;
             }
 
@@ -144,12 +177,14 @@
             if (fontInfos.length != 1) {
                 Log.d(TAG, "Font fetch did not return a unique result: length = %d",
                         fontInfos.length);
+                logFetchFontResult(FetchFontResult.FAILED_NON_UNIQUE_RESULT);
                 return null;
             }
 
             FontInfo fontInfo = fontInfos[0];
             if (fontInfo.getResultCode() != FontsContractCompat.Columns.RESULT_CODE_OK) {
                 Log.d(TAG, "Returned font has failed status code: %d", fontInfo.getResultCode());
+                logFetchFontResult(FetchFontResult.FAILED_RESULT_CODE);
                 return null;
             }
 
@@ -158,10 +193,15 @@
                     contentResolver.openFileDescriptor(fontInfo.getUri(), READ_ONLY_MODE);
             if (fileDescriptor == null) {
                 Log.d(TAG, "Unable to open font file at: %s", fontInfo.getUri());
+                logFetchFontResult(FetchFontResult.FAILED_FILE_OPEN);
+                return null;
             }
+
+            logFetchFontResult(FetchFontResult.SUCCESS);
             return fileDescriptor;
         } catch (NameNotFoundException | IOException | OutOfMemoryError e) {
             Log.d(TAG, "Failed to get font with: %s", e.toString());
+            logFetchFontResult(FetchFontResult.FAILED_EXCEPTION);
             return null;
         }
     }
@@ -185,6 +225,11 @@
         return map;
     }
 
+    private static void logFetchFontResult(@FetchFontResult int result) {
+        RecordHistogram.recordEnumeratedHistogram(
+                FETCH_FONT_HISTOGRAM, result, FetchFontResult.COUNT);
+    }
+
     @Override
     public void close() {}
 
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/font/AndroidFontLookupImplTest.java b/content/public/android/javatests/src/org/chromium/content/browser/font/AndroidFontLookupImplTest.java
index 55ff74c..85ab248 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/font/AndroidFontLookupImplTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/font/AndroidFontLookupImplTest.java
@@ -4,6 +4,8 @@
 
 package org.chromium.content.browser.font;
 
+import static junit.framework.Assert.assertEquals;
+
 import static org.mockito.AdditionalMatchers.aryEq;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
@@ -40,10 +42,12 @@
 import org.mockito.Mock;
 import org.mockito.stubbing.OngoingStubbing;
 
+import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.blink.mojom.AndroidFontLookup;
 import org.chromium.blink.mojom.AndroidFontLookup.GetUniqueNameLookupTableResponse;
 import org.chromium.blink.mojom.AndroidFontLookup.MatchLocalFontByUniqueNameResponse;
+import org.chromium.content.browser.font.AndroidFontLookupImpl.FetchFontResult;
 import org.chromium.content_public.browser.test.NativeLibraryTestUtils;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
 import org.chromium.mojo.MojoTestRule;
@@ -121,6 +125,11 @@
 
         mMojoTestRule.runLoop(RUN_LOOP_TIMEOUT_MS);
         verify(mGetUniqueNameLookupTableCallback).call(aryEq(expected));
+
+        assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        AndroidFontLookupImpl.FETCH_FONT_HISTOGRAM,
+                        FetchFontResult.FAILED_NON_UNIQUE_RESULT));
     }
 
     @SmallTest
@@ -137,6 +146,10 @@
 
         mMojoTestRule.runLoop(RUN_LOOP_TIMEOUT_MS);
         verify(mGetUniqueNameLookupTableCallback).call(aryEq(expected));
+
+        assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        AndroidFontLookupImpl.FETCH_FONT_HISTOGRAM, FetchFontResult.SUCCESS));
     }
 
     @SmallTest
@@ -173,6 +186,14 @@
 
         mMojoTestRule.runLoop(RUN_LOOP_TIMEOUT_MS);
         verify(mGetUniqueNameLookupTableCallback).call(aryEq(expected));
+
+        assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        AndroidFontLookupImpl.FETCH_FONT_HISTOGRAM,
+                        FetchFontResult.FAILED_NON_UNIQUE_RESULT));
+        assertEquals(2,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        AndroidFontLookupImpl.FETCH_FONT_HISTOGRAM, FetchFontResult.SUCCESS));
     }
 
     @SmallTest
@@ -184,6 +205,15 @@
         verify(mMatchLocalFontByUniqueNameCallback,
                 timeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL))
                 .call(isNull());
+
+        assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        AndroidFontLookupImpl.FETCH_FONT_HISTOGRAM,
+                        FetchFontResult.FAILED_UNEXPECTED_NAME));
+
+        assertEquals(1,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        AndroidFontLookupImpl.MATCH_LOCAL_FONT_BY_UNIQUE_NAME_HISTOGRAM));
     }
 
     @SmallTest
@@ -200,6 +230,15 @@
         verify(mMatchLocalFontByUniqueNameCallback,
                 timeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL))
                 .call(isNull());
+
+        assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        AndroidFontLookupImpl.FETCH_FONT_HISTOGRAM,
+                        FetchFontResult.FAILED_STATUS_CODE));
+
+        assertEquals(1,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        AndroidFontLookupImpl.MATCH_LOCAL_FONT_BY_UNIQUE_NAME_HISTOGRAM));
     }
 
     @SmallTest
@@ -215,6 +254,15 @@
         verify(mMatchLocalFontByUniqueNameCallback,
                 timeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL))
                 .call(isNull());
+
+        assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        AndroidFontLookupImpl.FETCH_FONT_HISTOGRAM,
+                        FetchFontResult.FAILED_NON_UNIQUE_RESULT));
+
+        assertEquals(1,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        AndroidFontLookupImpl.MATCH_LOCAL_FONT_BY_UNIQUE_NAME_HISTOGRAM));
     }
 
     @SmallTest
@@ -232,6 +280,38 @@
         verify(mMatchLocalFontByUniqueNameCallback,
                 timeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL))
                 .call(isNull());
+
+        assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        AndroidFontLookupImpl.FETCH_FONT_HISTOGRAM,
+                        FetchFontResult.FAILED_RESULT_CODE));
+
+        assertEquals(1,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        AndroidFontLookupImpl.MATCH_LOCAL_FONT_BY_UNIQUE_NAME_HISTOGRAM));
+    }
+
+    @SmallTest
+    @Test
+    public void testMatchLocalFontByUniqueName_Throws() throws NameNotFoundException {
+        whenFetchFontsWith(FONT_QUERY).thenThrow(new NameNotFoundException());
+
+        mAndroidFontLookup.matchLocalFontByUniqueName(
+                FULL_FONT_NAME, mMatchLocalFontByUniqueNameCallback);
+
+        mMojoTestRule.runLoop(RUN_LOOP_TIMEOUT_MS);
+        verify(mMatchLocalFontByUniqueNameCallback,
+                timeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL))
+                .call(isNull());
+
+        assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        AndroidFontLookupImpl.FETCH_FONT_HISTOGRAM,
+                        FetchFontResult.FAILED_EXCEPTION));
+
+        assertEquals(1,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        AndroidFontLookupImpl.MATCH_LOCAL_FONT_BY_UNIQUE_NAME_HISTOGRAM));
     }
 
     @SmallTest
@@ -249,6 +329,14 @@
         verify(mMatchLocalFontByUniqueNameCallback,
                 timeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL))
                 .call(notNull());
+
+        assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        AndroidFontLookupImpl.FETCH_FONT_HISTOGRAM, FetchFontResult.SUCCESS));
+
+        assertEquals(1,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        AndroidFontLookupImpl.MATCH_LOCAL_FONT_BY_UNIQUE_NAME_HISTOGRAM));
     }
 
     private OngoingStubbing<FontFamilyResult> whenFetchFontsWith(String query)
diff --git a/content/public/browser/render_process_host.h b/content/public/browser/render_process_host.h
index 5ab86795..e3bc13d 100644
--- a/content/public/browser/render_process_host.h
+++ b/content/public/browser/render_process_host.h
@@ -33,6 +33,7 @@
 #include "services/network/public/mojom/restricted_cookie_manager.mojom-forward.h"
 #include "services/network/public/mojom/url_loader_factory.mojom-forward.h"
 #include "third_party/blink/public/mojom/appcache/appcache.mojom.h"
+#include "third_party/blink/public/mojom/background_sync/background_sync.mojom.h"
 #include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom-forward.h"
 #include "third_party/blink/public/mojom/filesystem/file_system.mojom-forward.h"
 #include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-forward.h"
@@ -503,6 +504,12 @@
           receiver) = 0;
   virtual void BindVideoDecodePerfHistory(
       mojo::PendingReceiver<media::mojom::VideoDecodePerfHistory> receiver) = 0;
+  virtual void CreateOneShotSyncService(
+      mojo::PendingReceiver<blink::mojom::OneShotBackgroundSyncService>
+          receiver) = 0;
+  virtual void CreatePeriodicSyncService(
+      mojo::PendingReceiver<blink::mojom::PeriodicBackgroundSyncService>
+          receiver) = 0;
   virtual void BindQuotaManagerHost(
       int render_frame_id,
       const url::Origin& origin,
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index a43101a..20681abb 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -43,12 +43,6 @@
 // TODO(enne): remove this once app cache has been removed.
 const char kAppCacheForceEnabled[] = "app-cache-force-enabled";
 
-// Set blink settings. Format is <name>[=<value],<name>[=<value>],...
-// The names are declared in Settings.json5. For boolean type, use "true",
-// "false", or omit '=<value>' part to set to true. For enum type, use the int
-// value of the enum value. Applied after other command line flags and prefs.
-const char kBlinkSettings[]                 = "blink-settings";
-
 // Causes the browser process to crash on startup.
 const char kBrowserCrashTest[]              = "crash-test";
 
@@ -271,9 +265,6 @@
 // Disable multithreaded GPU compositing of web content.
 const char kDisableThreadedCompositing[]    = "disable-threaded-compositing";
 
-// Disable multithreaded, compositor scrolling of web content.
-const char kDisableThreadedScrolling[]      = "disable-threaded-scrolling";
-
 // Disable V8 idle tasks.
 const char kDisableV8IdleTasks[]            = "disable-v8-idle-tasks";
 
@@ -569,13 +560,6 @@
 // Use a Mojo-based LocalStorage implementation.
 const char kMojoLocalStorage[]              = "mojo-local-storage";
 
-// Sets the timeout seconds of the network-quiet timers in IdlenessDetector.
-// Used by embedders who want to change the timeout time in order to run web
-// contents on various embedded devices and changeable network bandwidths in
-// different regions. For example, it's useful when using FirstMeaningfulPaint
-// signal to dismiss a splash screen.
-const char kNetworkQuietTimeout[] = "network-quiet-timeout";
-
 // Disables the use of a zygote process for forking child processes. Instead,
 // child processes will be forked and exec'd directly. Note that --no-sandbox
 // should also be used together with this flag because the sandbox needs the
@@ -595,13 +579,6 @@
 const char kOverridePluginPowerSaverForTesting[] =
     "override-plugin-power-saver-for-testing";
 
-// Override the default value for the 'passive' field in javascript
-// addEventListener calls. Values are defined as:
-//  'documentonlytrue' to set the default be true only for document level nodes.
-//  'true' to set the default to be true on all nodes (when not specified).
-//  'forcealltrue' to force the value on all nodes.
-const char kPassiveListenersDefault[] = "passive-listeners-default";
-
 // Argument to the process type that indicates a PPAPI broker process type.
 const char kPpapiBrokerProcess[]            = "ppapi-broker";
 
@@ -769,11 +746,6 @@
 //   disabled: touch events are disabled.
 const char kTouchEventFeatureDetectionDisabled[] = "disabled";
 
-// Controls how text selection granularity changes when touch text selection
-// handles are dragged. Should be "character" or "direction". If not specified,
-// the platform default is used.
-const char kTouchTextSelectionStrategy[]    = "touch-selection-strategy";
-
 // Accepts specified file URL of a trustable WebBundle file. This flag
 // should be used only for testing purpose.
 const char kTrustableWebBundleFileUrl[] = "trustable-web-bundles-file-url";
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 7b258d6..18f61bd 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -23,7 +23,6 @@
 CONTENT_EXPORT extern const char kAllowSyncXHRInPageDismissal[];
 CONTENT_EXPORT extern const char kAndroidFontsPath[];
 CONTENT_EXPORT extern const char kAppCacheForceEnabled[];
-CONTENT_EXPORT extern const char kBlinkSettings[];
 CONTENT_EXPORT extern const char kBrowserCrashTest[];
 CONTENT_EXPORT extern const char kBrowserStartupDialog[];
 CONTENT_EXPORT extern const char kBrowserSubprocessPath[];
@@ -90,7 +89,6 @@
 CONTENT_EXPORT extern const char kDisableSpeechSynthesisAPI[];
 CONTENT_EXPORT extern const char kDisableTestCerts[];
 CONTENT_EXPORT extern const char kDisableThreadedCompositing[];
-CONTENT_EXPORT extern const char kDisableThreadedScrolling[];
 extern const char kDisableV8IdleTasks[];
 CONTENT_EXPORT extern const char kDisableWebGLImageChromium[];
 CONTENT_EXPORT extern const char kDisableWebSecurity[];
@@ -169,12 +167,10 @@
 CONTENT_EXPORT extern const char kMockCertVerifierDefaultResultForTesting[];
 CONTENT_EXPORT extern const char kMojoCoreLibraryPath[];
 CONTENT_EXPORT extern const char kMojoLocalStorage[];
-CONTENT_EXPORT extern const char kNetworkQuietTimeout[];
 CONTENT_EXPORT extern const char kNoZygote[];
 extern const char kNoV8UntrustedCodeMitigations[];
 CONTENT_EXPORT extern const char kNumRasterThreads[];
 CONTENT_EXPORT extern const char kOverridePluginPowerSaverForTesting[];
-CONTENT_EXPORT extern const char kPassiveListenersDefault[];
 CONTENT_EXPORT extern const char kPpapiBrokerProcess[];
 CONTENT_EXPORT extern const char kPpapiFlashArgs[];
 CONTENT_EXPORT extern const char kPpapiInProcess[];
@@ -208,7 +204,6 @@
 CONTENT_EXPORT extern const char kTouchEventFeatureDetectionAuto[];
 CONTENT_EXPORT extern const char kTouchEventFeatureDetectionEnabled[];
 CONTENT_EXPORT extern const char kTouchEventFeatureDetectionDisabled[];
-CONTENT_EXPORT extern const char kTouchTextSelectionStrategy[];
 CONTENT_EXPORT extern const char kTrustableWebBundleFileUrl[];
 CONTENT_EXPORT extern const char kUseFakeCodecForPeerConnection[];
 CONTENT_EXPORT extern const char kUseFakeUIForMediaStream[];
diff --git a/content/public/renderer/render_frame.h b/content/public/renderer/render_frame.h
index 2c414bd..96175d5 100644
--- a/content/public/renderer/render_frame.h
+++ b/content/public/renderer/render_frame.h
@@ -147,7 +147,7 @@
   virtual blink::WebLocalFrame* GetWebFrame() = 0;
 
   // Gets WebKit related preferences associated with this frame.
-  virtual const blink::web_pref::WebPreferences& GetWebkitPreferences() = 0;
+  virtual const blink::web_pref::WebPreferences& GetBlinkPreferences() = 0;
 
   // Shows a context menu with the given information. The given client will
   // be called with the result.
diff --git a/content/public/renderer/render_view.h b/content/public/renderer/render_view.h
index 50518b3..6db89cd 100644
--- a/content/public/renderer/render_view.h
+++ b/content/public/renderer/render_view.h
@@ -56,11 +56,6 @@
   // been closed but not yet destroyed are excluded).
   static void ForEach(RenderViewVisitor* visitor);
 
-  // Applies WebKit related preferences to this view.
-  static void ApplyWebPreferences(
-      const blink::web_pref::WebPreferences& preferences,
-      blink::WebView* web_view);
-
   // Returns the main RenderFrame.
   virtual RenderFrame* GetMainRenderFrame() = 0;
 
@@ -71,11 +66,11 @@
   virtual float GetZoomLevel() = 0;
 
   // Gets WebKit related preferences associated with this view.
-  virtual const blink::web_pref::WebPreferences& GetWebkitPreferences() = 0;
+  virtual const blink::web_pref::WebPreferences& GetBlinkPreferences() = 0;
 
   // Overrides the WebKit related preferences associated with this view. Note
   // that the browser process may update the preferences at any time.
-  virtual void SetWebkitPreferences(
+  virtual void SetBlinkPreferences(
       const blink::web_pref::WebPreferences& preferences) = 0;
 
   // Returns the associated WebView. May return NULL when the view is closing.
diff --git a/content/public/test/mock_render_process_host.h b/content/public/test/mock_render_process_host.h
index 6c3fd89..c5e9ab2 100644
--- a/content/public/test/mock_render_process_host.h
+++ b/content/public/test/mock_render_process_host.h
@@ -199,6 +199,12 @@
       int render_frame_id,
       const url::Origin& origin,
       mojo::PendingReceiver<blink::mojom::LockManager> receiver) override {}
+  void CreateOneShotSyncService(
+      mojo::PendingReceiver<blink::mojom::OneShotBackgroundSyncService>
+          receiver) override {}
+  void CreatePeriodicSyncService(
+      mojo::PendingReceiver<blink::mojom::PeriodicBackgroundSyncService>
+          receiver) override {}
   void CreatePermissionService(
       const url::Origin& origin,
       mojo::PendingReceiver<blink::mojom::PermissionService> receiver)
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 26d9a7b..bdac1fb 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -22,10 +22,10 @@
   # internal content ones) should depend on the public one.
   visibility = [
     ":for_content_tests",
+    "//chromecast/media/audio:*",
     "//content/app:*",
     "//content/public/renderer:renderer_sources",
     "//content/renderer:audio_decoder_fuzzer",
-    "//chromecast/media/audio:*",
   ]
 
   sources = [
@@ -137,7 +137,6 @@
     "media/audio/audio_device_factory.h",
     "media/audio/audio_renderer_mixer_manager.cc",
     "media/audio/audio_renderer_mixer_manager.h",
-    "media/audio/audio_renderer_sink_cache.h",
     "media/audio/audio_renderer_sink_cache_impl.cc",
     "media/audio/audio_renderer_sink_cache_impl.h",
     "media/audio_decoder.cc",
diff --git a/content/renderer/gpu_benchmarking_extension.cc b/content/renderer/gpu_benchmarking_extension.cc
index 1ac2fba98..2e1ad18 100644
--- a/content/renderer/gpu_benchmarking_extension.cc
+++ b/content/renderer/gpu_benchmarking_extension.cc
@@ -469,8 +469,8 @@
   const int kContentHeight = 735;    // 10.21 inch
   blink::WebPrintParams params(blink::WebSize(kContentWidth, kContentHeight));
   params.printer_dpi = 300;
-  int page_count = frame->PrintBegin(params);
-  for (int i = 0; i < page_count; ++i) {
+  uint32_t page_count = frame->PrintBegin(params);
+  for (uint32_t i = 0; i < page_count; ++i) {
     SkCanvas* sk_canvas = doc->beginPage(kPageWidth, kPageHeight);
     cc::SkiaPaintCanvas canvas(sk_canvas);
     cc::PaintCanvasAutoRestore auto_restore(&canvas, true);
diff --git a/content/renderer/media/audio/audio_renderer_sink_cache_impl.cc b/content/renderer/media/audio/audio_renderer_sink_cache_impl.cc
index c0aa202..15d1eb3 100644
--- a/content/renderer/media/audio/audio_renderer_sink_cache_impl.cc
+++ b/content/renderer/media/audio/audio_renderer_sink_cache_impl.cc
@@ -90,7 +90,7 @@
 };
 
 // static
-void AudioRendererSinkCache::ObserveFrame(RenderFrame* frame) {
+void AudioRendererSinkCacheImpl::ObserveFrame(RenderFrame* frame) {
   new AudioRendererSinkCacheImpl::FrameObserver(frame);
 }
 
diff --git a/content/renderer/media/audio/audio_renderer_sink_cache_impl.h b/content/renderer/media/audio/audio_renderer_sink_cache_impl.h
index c09697ed..f2ba401 100644
--- a/content/renderer/media/audio/audio_renderer_sink_cache_impl.h
+++ b/content/renderer/media/audio/audio_renderer_sink_cache_impl.h
@@ -5,7 +5,7 @@
 #ifndef CONTENT_RENDERER_MEDIA_AUDIO_AUDIO_RENDERER_SINK_CACHE_IMPL_H_
 #define CONTENT_RENDERER_MEDIA_AUDIO_AUDIO_RENDERER_SINK_CACHE_IMPL_H_
 
-#include "content/renderer/media/audio/audio_renderer_sink_cache.h"
+#include "third_party/blink/public/web/modules/media/audio/audio_renderer_sink_cache.h"
 
 #include <string>
 #include <vector>
@@ -20,9 +20,11 @@
 
 namespace content {
 
+class RenderFrame;
+
 // AudioRendererSinkCache implementation.
 class CONTENT_EXPORT AudioRendererSinkCacheImpl
-    : public AudioRendererSinkCache {
+    : public blink::AudioRendererSinkCache {
  public:
   class FrameObserver;
 
@@ -32,6 +34,14 @@
           const blink::LocalFrameToken& frame_token,
           const media::AudioSinkParameters& params)>;
 
+  // If called, the cache will drop sinks belonging to the specified frame on
+  // navigation.
+  //
+  // TODO(https://crbug.com/787252): Move the declaration back to
+  // AudioRendererSinkCache when this header moves to
+  // blink/renderer/modules/media/audio.
+  static void ObserveFrame(RenderFrame* frame);
+
   // |cleanup_task_runner| will be used to delete sinks when they are unused,
   // AudioRendererSinkCacheImpl must outlive any tasks posted to it. Since
   // the sink cache is normally a process-wide singleton, this isn't a problem.
@@ -42,7 +52,7 @@
 
   ~AudioRendererSinkCacheImpl() final;
 
-  // AudioSinkCache implementation:
+  // AudioRendererSinkCache implementation:
   media::OutputDeviceInfo GetSinkInfo(
       const blink::LocalFrameToken& source_frame_token,
       const base::UnguessableToken& session_id,
diff --git a/content/renderer/media/audio/audio_renderer_sink_cache_unittest.cc b/content/renderer/media/audio/audio_renderer_sink_cache_unittest.cc
index 9e81d17..58289b6 100644
--- a/content/renderer/media/audio/audio_renderer_sink_cache_unittest.cc
+++ b/content/renderer/media/audio/audio_renderer_sink_cache_unittest.cc
@@ -372,7 +372,7 @@
   // Release the sink on the second thread.
   PostAndWaitUntilDone(
       thread2,
-      base::BindOnce(&AudioRendererSinkCache::ReleaseSink,
+      base::BindOnce(&blink::AudioRendererSinkCache::ReleaseSink,
                      base::Unretained(cache_.get()), base::RetainedRef(sink)));
 
   EXPECT_EQ(0, sink_count());
diff --git a/content/renderer/media/media_factory.cc b/content/renderer/media/media_factory.cc
index 0015471..4f1a3a8 100644
--- a/content/renderer/media/media_factory.cc
+++ b/content/renderer/media/media_factory.cc
@@ -380,7 +380,7 @@
                                      sink_id.Utf8()));
 
   const blink::web_pref::WebPreferences webkit_preferences =
-      render_frame_->GetWebkitPreferences();
+      render_frame_->GetBlinkPreferences();
   bool embedded_media_experience_enabled = false;
 #if defined(OS_ANDROID)
   embedded_media_experience_enabled =
diff --git a/content/renderer/pepper/pepper_in_process_resource_creation.cc b/content/renderer/pepper/pepper_in_process_resource_creation.cc
index bd311fdc..c5f1956 100644
--- a/content/renderer/pepper/pepper_in_process_resource_creation.cc
+++ b/content/renderer/pepper/pepper_in_process_resource_creation.cc
@@ -58,7 +58,7 @@
   // GPU process whether these features are blacklisted or not.
   gpu::GpuFeatureInfo gpu_feature_info;
   ppapi::Preferences prefs(PpapiPreferencesBuilder::Build(
-      host_impl_->GetRenderViewForInstance(instance)->GetWebkitPreferences(),
+      host_impl_->GetRenderViewForInstance(instance)->GetBlinkPreferences(),
       gpu_feature_info));
   return (new BrowserFontResource_Trusted(
               host_impl_->in_process_router()->GetPluginConnection(instance),
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc
index 863a35f..88683fb 100644
--- a/content/renderer/pepper/pepper_plugin_instance_impl.cc
+++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc
@@ -2539,7 +2539,7 @@
   if (!render_frame_)
     return PP_MakeUndefined();
   return StringVar::StringToPPVar(
-      render_frame_->render_view()->webkit_preferences().default_encoding);
+      render_frame_->render_view()->GetBlinkPreferences().default_encoding);
 }
 
 void PepperPluginInstanceImpl::SetPluginToHandleFindRequests(
diff --git a/content/renderer/pepper/plugin_module.cc b/content/renderer/pepper/plugin_module.cc
index b04ad58e..e9fd105 100644
--- a/content/renderer/pepper/plugin_module.cc
+++ b/content/renderer/pepper/plugin_module.cc
@@ -733,7 +733,7 @@
 
   if (!dispatcher->Init(channel_handle, &GetInterface,
                         ppapi::Preferences(PpapiPreferencesBuilder::Build(
-                            render_frame->render_view()->webkit_preferences(),
+                            render_frame->render_view()->GetBlinkPreferences(),
                             gpu_feature_info)),
                         hung_filter.get(), task_runner)) {
     return nullptr;
diff --git a/content/renderer/pepper/ppb_graphics_3d_impl.cc b/content/renderer/pepper/ppb_graphics_3d_impl.cc
index 9ab8d16..27b0e0a7 100644
--- a/content/renderer/pepper/ppb_graphics_3d_impl.cc
+++ b/content/renderer/pepper/ppb_graphics_3d_impl.cc
@@ -218,7 +218,7 @@
     return false;
 
   const blink::web_pref::WebPreferences& prefs =
-      render_frame->GetWebkitPreferences();
+      render_frame->GetBlinkPreferences();
 
   // 3D access might be disabled.
   if (!prefs.pepper_3d_enabled)
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 0dcb9632c..40f800d 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -109,7 +109,7 @@
 #include "content/renderer/loader/web_url_request_util.h"
 #include "content/renderer/loader/web_worker_fetch_context_impl.h"
 #include "content/renderer/media/audio/audio_device_factory.h"
-#include "content/renderer/media/audio/audio_renderer_sink_cache.h"
+#include "content/renderer/media/audio/audio_renderer_sink_cache_impl.h"
 #include "content/renderer/media/media_permission_dispatcher.h"
 #include "content/renderer/mhtml_handle_writer.h"
 #include "content/renderer/mojo/blink_interface_registry_impl.h"
@@ -2051,7 +2051,7 @@
                                   GetBrowserInterfaceBroker());
   }
 
-  AudioRendererSinkCache::ObserveFrame(this);
+  AudioRendererSinkCacheImpl::ObserveFrame(this);
 
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
@@ -2828,8 +2828,8 @@
   return frame_;
 }
 
-const blink::web_pref::WebPreferences& RenderFrameImpl::GetWebkitPreferences() {
-  return render_view_->GetWebkitPreferences();
+const blink::web_pref::WebPreferences& RenderFrameImpl::GetBlinkPreferences() {
+  return render_view_->GetBlinkPreferences();
 }
 
 const blink::mojom::RendererPreferences&
@@ -5301,10 +5301,10 @@
   // This check is very similar to RenderFrameHostImpl::CanCommitOrigin, but
   // adapted to the renderer process side.
   if (!params->origin.opaque() && params->url.IsStandard() &&
-      render_view_->GetWebkitPreferences().web_security_enabled) {
+      render_view_->GetBlinkPreferences().web_security_enabled) {
     // Exclude file: URLs when settings allow them access any origin.
     if (params->origin.scheme() != url::kFileScheme ||
-        !render_view_->GetWebkitPreferences()
+        !render_view_->GetBlinkPreferences()
              .allow_universal_access_from_file_urls) {
       if (!params->origin.IsSameOriginWith(url::Origin::Create(params->url))) {
         base::debug::CrashKeyString* url = base::debug::AllocateCrashKeyString(
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index cfd1569..8d93428 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -421,7 +421,7 @@
   std::unique_ptr<AXTreeSnapshotter> CreateAXTreeSnapshotter() override;
   int GetRoutingID() override;
   blink::WebLocalFrame* GetWebFrame() override;
-  const blink::web_pref::WebPreferences& GetWebkitPreferences() override;
+  const blink::web_pref::WebPreferences& GetBlinkPreferences() override;
   int ShowContextMenu(ContextMenuClient* client,
                       const UntrustworthyContextMenuParams& params) override;
   void CancelContextMenu(int request_id) override;
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index e162bc5..4a32bf7 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -75,6 +75,7 @@
 #include "third_party/blink/public/common/origin_trials/origin_trial_policy.h"
 #include "third_party/blink/public/common/origin_trials/trial_token_validator.h"
 #include "third_party/blink/public/common/page/page_zoom.h"
+#include "third_party/blink/public/common/switches.h"
 #include "third_party/blink/public/common/widget/device_emulation_params.h"
 #include "third_party/blink/public/mojom/frame/frame_owner_properties.mojom.h"
 #include "third_party/blink/public/mojom/loader/request_context_frame_type.mojom.h"
@@ -3061,7 +3062,7 @@
 
 TEST_F(RenderViewImplBlinkSettingsTest, CommandLine) {
   base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kBlinkSettings, "viewportEnabled=true");
+      blink::switches::kBlinkSettings, "viewportEnabled=true");
   DoSetUp();
   EXPECT_TRUE(settings()->ViewportEnabled());
 }
@@ -3088,7 +3089,7 @@
   prefs.shrinks_viewport_contents_to_fit = true;
   prefs.default_minimum_page_scale_factor = 0.1f;
   prefs.default_maximum_page_scale_factor = 5.5f;
-  view()->SetWebkitPreferences(prefs);
+  view()->SetBlinkPreferences(prefs);
 
   EXPECT_EQ(1.f, view()->GetWebView()->PageScaleFactor());
   EXPECT_EQ(1.f, view()->GetWebView()->MinimumPageScaleFactor());
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 0386a51..d43a6a7 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -93,6 +93,7 @@
 #include "third_party/blink/public/common/dom_storage/session_storage_namespace_id.h"
 #include "third_party/blink/public/common/frame/user_activation_update_source.h"
 #include "third_party/blink/public/common/input/web_input_event.h"
+#include "third_party/blink/public/common/switches.h"
 #include "third_party/blink/public/common/web_preferences/web_preferences.h"
 #include "third_party/blink/public/platform/file_path_conversion.h"
 #include "third_party/blink/public/platform/modules/video_capture/web_video_capture_impl_manager.h"
@@ -263,136 +264,6 @@
 
 namespace {
 
-typedef void (*SetFontFamilyWrapper)(blink::WebSettings*,
-                                     const base::string16&,
-                                     UScriptCode);
-
-void SetStandardFontFamilyWrapper(WebSettings* settings,
-                                  const base::string16& font,
-                                  UScriptCode script) {
-  settings->SetStandardFontFamily(WebString::FromUTF16(font), script);
-}
-
-void SetFixedFontFamilyWrapper(WebSettings* settings,
-                               const base::string16& font,
-                               UScriptCode script) {
-  settings->SetFixedFontFamily(WebString::FromUTF16(font), script);
-}
-
-void SetSerifFontFamilyWrapper(WebSettings* settings,
-                               const base::string16& font,
-                               UScriptCode script) {
-  settings->SetSerifFontFamily(WebString::FromUTF16(font), script);
-}
-
-void SetSansSerifFontFamilyWrapper(WebSettings* settings,
-                                   const base::string16& font,
-                                   UScriptCode script) {
-  settings->SetSansSerifFontFamily(WebString::FromUTF16(font), script);
-}
-
-void SetCursiveFontFamilyWrapper(WebSettings* settings,
-                                 const base::string16& font,
-                                 UScriptCode script) {
-  settings->SetCursiveFontFamily(WebString::FromUTF16(font), script);
-}
-
-void SetFantasyFontFamilyWrapper(WebSettings* settings,
-                                 const base::string16& font,
-                                 UScriptCode script) {
-  settings->SetFantasyFontFamily(WebString::FromUTF16(font), script);
-}
-
-void SetPictographFontFamilyWrapper(WebSettings* settings,
-                                    const base::string16& font,
-                                    UScriptCode script) {
-  settings->SetPictographFontFamily(WebString::FromUTF16(font), script);
-}
-
-// If |scriptCode| is a member of a family of "similar" script codes, returns
-// the script code in that family that is used by WebKit for font selection
-// purposes.  For example, USCRIPT_KATAKANA_OR_HIRAGANA and USCRIPT_JAPANESE are
-// considered equivalent for the purposes of font selection.  WebKit uses the
-// script code USCRIPT_KATAKANA_OR_HIRAGANA.  So, if |scriptCode| is
-// USCRIPT_JAPANESE, the function returns USCRIPT_KATAKANA_OR_HIRAGANA.  WebKit
-// uses different scripts than the ones in Chrome pref names because the version
-// of ICU included on certain ports does not have some of the newer scripts.  If
-// |scriptCode| is not a member of such a family, returns |scriptCode|.
-UScriptCode GetScriptForWebSettings(UScriptCode scriptCode) {
-  switch (scriptCode) {
-    case USCRIPT_HIRAGANA:
-    case USCRIPT_KATAKANA:
-    case USCRIPT_JAPANESE:
-      return USCRIPT_KATAKANA_OR_HIRAGANA;
-    case USCRIPT_KOREAN:
-      return USCRIPT_HANGUL;
-    default:
-      return scriptCode;
-  }
-}
-
-void ApplyFontsFromMap(const blink::web_pref::ScriptFontFamilyMap& map,
-                       SetFontFamilyWrapper setter,
-                       WebSettings* settings) {
-  for (auto it = map.begin(); it != map.end(); ++it) {
-    int32_t script = u_getPropertyValueEnum(UCHAR_SCRIPT, (it->first).c_str());
-    if (script >= 0 && script < USCRIPT_CODE_LIMIT) {
-      UScriptCode code = static_cast<UScriptCode>(script);
-      (*setter)(settings, it->second, GetScriptForWebSettings(code));
-    }
-  }
-}
-
-void ApplyCommandLineToSettings(WebSettings* settings) {
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
-
-  settings->SetThreadedScrollingEnabled(
-      !command_line.HasSwitch(switches::kDisableThreadedScrolling));
-
-  WebSettings::SelectionStrategyType selection_strategy;
-  if (command_line.GetSwitchValueASCII(switches::kTouchTextSelectionStrategy) ==
-      "direction")
-    selection_strategy = WebSettings::SelectionStrategyType::kDirection;
-  else
-    selection_strategy = WebSettings::SelectionStrategyType::kCharacter;
-  settings->SetSelectionStrategy(selection_strategy);
-
-  std::string passive_listeners_default =
-      command_line.GetSwitchValueASCII(switches::kPassiveListenersDefault);
-  if (!passive_listeners_default.empty()) {
-    WebSettings::PassiveEventListenerDefault passive_default =
-        WebSettings::PassiveEventListenerDefault::kFalse;
-    if (passive_listeners_default == "true")
-      passive_default = WebSettings::PassiveEventListenerDefault::kTrue;
-    else if (passive_listeners_default == "forcealltrue")
-      passive_default = WebSettings::PassiveEventListenerDefault::kForceAllTrue;
-    settings->SetPassiveEventListenerDefault(passive_default);
-  }
-
-  std::string network_quiet_timeout =
-      command_line.GetSwitchValueASCII(switches::kNetworkQuietTimeout);
-  if (!network_quiet_timeout.empty()) {
-    double network_quiet_timeout_seconds = 0.0;
-    if (base::StringToDouble(network_quiet_timeout,
-                             &network_quiet_timeout_seconds))
-      settings->SetNetworkQuietTimeout(network_quiet_timeout_seconds);
-  }
-
-  if (command_line.HasSwitch(switches::kBlinkSettings)) {
-    std::vector<std::string> blink_settings = base::SplitString(
-        command_line.GetSwitchValueASCII(switches::kBlinkSettings), ",",
-        base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-    for (const std::string& setting : blink_settings) {
-      size_t pos = setting.find('=');
-      settings->SetFromStrings(
-          blink::WebString::FromLatin1(setting.substr(0, pos)),
-          blink::WebString::FromLatin1(
-              pos == std::string::npos ? "" : setting.substr(pos + 1)));
-    }
-  }
-}
-
 content::mojom::WindowContainerType WindowFeaturesToContainerType(
     const blink::WebWindowFeatures& window_features) {
   if (window_features.background) {
@@ -414,7 +285,6 @@
           params.renderer_wide_named_frame_lookup),
       widgets_never_composited_(params.never_composited),
       compositor_deps_(compositor_deps),
-      webkit_preferences_(params.web_preferences),
       session_storage_namespace_id_(params.session_storage_namespace_id) {
   DCHECK(!session_storage_namespace_id_.empty())
       << "Session storage namespace must be populated.";
@@ -451,8 +321,7 @@
 
   bool local_main_frame = params->main_frame_routing_id != MSG_ROUTING_NONE;
 
-  ApplyWebPreferences(webkit_preferences_, GetWebView());
-  ApplyCommandLineToSettings(GetWebView()->GetSettings());
+  webview_->SetWebPreferences(params->web_preferences);
 
   if (local_main_frame) {
     main_render_frame_ = RenderFrameImpl::CreateMainFrame(
@@ -546,415 +415,6 @@
 }
 
 /*static*/
-void RenderView::ApplyWebPreferences(
-    const blink::web_pref::WebPreferences& prefs,
-    WebView* web_view) {
-  WebSettings* settings = web_view->GetSettings();
-  ApplyFontsFromMap(prefs.standard_font_family_map,
-                    SetStandardFontFamilyWrapper, settings);
-  ApplyFontsFromMap(prefs.fixed_font_family_map,
-                    SetFixedFontFamilyWrapper, settings);
-  ApplyFontsFromMap(prefs.serif_font_family_map,
-                    SetSerifFontFamilyWrapper, settings);
-  ApplyFontsFromMap(prefs.sans_serif_font_family_map,
-                    SetSansSerifFontFamilyWrapper, settings);
-  ApplyFontsFromMap(prefs.cursive_font_family_map,
-                    SetCursiveFontFamilyWrapper, settings);
-  ApplyFontsFromMap(prefs.fantasy_font_family_map,
-                    SetFantasyFontFamilyWrapper, settings);
-  ApplyFontsFromMap(prefs.pictograph_font_family_map,
-                    SetPictographFontFamilyWrapper, settings);
-  settings->SetDefaultFontSize(prefs.default_font_size);
-  settings->SetDefaultFixedFontSize(prefs.default_fixed_font_size);
-  settings->SetMinimumFontSize(prefs.minimum_font_size);
-  settings->SetMinimumLogicalFontSize(prefs.minimum_logical_font_size);
-  settings->SetDefaultTextEncodingName(
-      WebString::FromASCII(prefs.default_encoding));
-  settings->SetJavaScriptEnabled(prefs.javascript_enabled);
-  settings->SetWebSecurityEnabled(prefs.web_security_enabled);
-  settings->SetLoadsImagesAutomatically(prefs.loads_images_automatically);
-  settings->SetImagesEnabled(prefs.images_enabled);
-  settings->SetPluginsEnabled(prefs.plugins_enabled);
-  settings->SetDOMPasteAllowed(prefs.dom_paste_enabled);
-  settings->SetTextAreasAreResizable(prefs.text_areas_are_resizable);
-  settings->SetAllowScriptsToCloseWindows(prefs.allow_scripts_to_close_windows);
-  settings->SetDownloadableBinaryFontsEnabled(prefs.remote_fonts_enabled);
-  settings->SetJavaScriptCanAccessClipboard(
-      prefs.javascript_can_access_clipboard);
-  WebRuntimeFeatures::EnableXSLT(prefs.xslt_enabled);
-  settings->SetDNSPrefetchingEnabled(prefs.dns_prefetching_enabled);
-  blink::WebNetworkStateNotifier::SetSaveDataEnabled(prefs.data_saver_enabled);
-  settings->SetLocalStorageEnabled(prefs.local_storage_enabled);
-  settings->SetSyncXHRInDocumentsEnabled(prefs.sync_xhr_in_documents_enabled);
-  WebRuntimeFeatures::EnableDatabase(prefs.databases_enabled);
-  settings->SetOfflineWebApplicationCacheEnabled(
-      prefs.application_cache_enabled);
-  settings->SetShouldProtectAgainstIpcFlooding(
-      !prefs.disable_ipc_flooding_protection);
-  settings->SetHyperlinkAuditingEnabled(prefs.hyperlink_auditing_enabled);
-  settings->SetCookieEnabled(prefs.cookie_enabled);
-  settings->SetNavigateOnDragDrop(prefs.navigate_on_drag_drop);
-
-  // By default, allow_universal_access_from_file_urls is set to false and thus
-  // we mitigate attacks from local HTML files by not granting file:// URLs
-  // universal access. Only test shell will enable this.
-  settings->SetAllowUniversalAccessFromFileURLs(
-      prefs.allow_universal_access_from_file_urls);
-  settings->SetAllowFileAccessFromFileURLs(
-      prefs.allow_file_access_from_file_urls);
-
-  settings->SetWebGL1Enabled(prefs.webgl1_enabled);
-  settings->SetWebGL2Enabled(prefs.webgl2_enabled);
-
-  // Enable WebGL errors to the JS console if requested.
-  settings->SetWebGLErrorsToConsoleEnabled(
-      prefs.webgl_errors_to_console_enabled);
-
-  settings->SetHideScrollbars(prefs.hide_scrollbars);
-
-  // Enable gpu-accelerated 2d canvas if requested on the command line.
-  WebRuntimeFeatures::EnableAccelerated2dCanvas(
-      prefs.accelerated_2d_canvas_enabled);
-
-  // Enable new canvas 2d api features
-  WebRuntimeFeatures::EnableNewCanvas2DAPI(prefs.new_canvas_2d_api_enabled);
-
-  // Disable antialiasing for 2d canvas if requested on the command line.
-  settings->SetAntialiased2dCanvasEnabled(
-      !prefs.antialiased_2d_canvas_disabled);
-
-  // Disable antialiasing of clips for 2d canvas if requested on the command
-  // line.
-  settings->SetAntialiasedClips2dCanvasEnabled(
-      prefs.antialiased_clips_2d_canvas_enabled);
-
-  // Tabs to link is not part of the settings. WebCore calls
-  // ChromeClient::tabsToLinks which is part of the glue code.
-  web_view->SetTabsToLinks(prefs.tabs_to_links);
-
-  settings->SetAllowRunningOfInsecureContent(
-      prefs.allow_running_insecure_content);
-  settings->SetDisableReadingFromCanvas(prefs.disable_reading_from_canvas);
-  settings->SetStrictMixedContentChecking(prefs.strict_mixed_content_checking);
-
-  settings->SetStrictlyBlockBlockableMixedContent(
-      prefs.strictly_block_blockable_mixed_content);
-
-  settings->SetStrictMixedContentCheckingForPlugin(
-      prefs.block_mixed_plugin_content);
-
-  settings->SetStrictPowerfulFeatureRestrictions(
-      prefs.strict_powerful_feature_restrictions);
-  settings->SetAllowGeolocationOnInsecureOrigins(
-      prefs.allow_geolocation_on_insecure_origins);
-  settings->SetPasswordEchoEnabled(prefs.password_echo_enabled);
-  settings->SetShouldPrintBackgrounds(prefs.should_print_backgrounds);
-  settings->SetShouldClearDocumentBackground(
-      prefs.should_clear_document_background);
-  settings->SetEnableScrollAnimator(prefs.enable_scroll_animator);
-  settings->SetPrefersReducedMotion(prefs.prefers_reduced_motion);
-
-  WebRuntimeFeatures::EnableTouchEventFeatureDetection(
-      prefs.touch_event_feature_detection_enabled);
-  settings->SetMaxTouchPoints(prefs.pointer_events_max_touch_points);
-  settings->SetAvailablePointerTypes(prefs.available_pointer_types);
-  settings->SetPrimaryPointerType(
-      static_cast<blink::PointerType>(prefs.primary_pointer_type));
-  settings->SetAvailableHoverTypes(prefs.available_hover_types);
-  settings->SetPrimaryHoverType(
-      static_cast<blink::HoverType>(prefs.primary_hover_type));
-  settings->SetBarrelButtonForDragEnabled(prefs.barrel_button_for_drag_enabled);
-
-  settings->SetEditingBehavior(
-      static_cast<WebSettings::EditingBehavior>(prefs.editing_behavior));
-
-  settings->SetSupportsMultipleWindows(prefs.supports_multiple_windows);
-
-  settings->SetMainFrameClipsContent(!prefs.record_whole_document);
-
-  settings->SetSmartInsertDeleteEnabled(prefs.smart_insert_delete_enabled);
-
-  settings->SetSpatialNavigationEnabled(prefs.spatial_navigation_enabled);
-  // Spatnav depends on KeyboardFocusableScrollers. The WebUI team has
-  // disabled KFS because they need more time to update their custom elements,
-  // crbug.com/907284. Meanwhile, we pre-ship KFS to spatnav users.
-  if (prefs.spatial_navigation_enabled)
-    WebRuntimeFeatures::EnableKeyboardFocusableScrollers(true);
-
-  settings->SetSelectionIncludesAltImageText(true);
-
-  settings->SetV8CacheOptions(
-      static_cast<WebSettings::V8CacheOptions>(prefs.v8_cache_options));
-
-  settings->SetImageAnimationPolicy(
-      static_cast<WebSettings::ImageAnimationPolicy>(prefs.animation_policy));
-
-  settings->SetPresentationRequiresUserGesture(
-      prefs.user_gesture_required_for_presentation);
-
-  if (prefs.text_tracks_enabled) {
-    settings->SetTextTrackKindUserPreference(
-        WebSettings::TextTrackKindUserPreference::kCaptions);
-  } else {
-    settings->SetTextTrackKindUserPreference(
-        WebSettings::TextTrackKindUserPreference::kDefault);
-  }
-  settings->SetTextTrackBackgroundColor(
-      WebString::FromASCII(prefs.text_track_background_color));
-  settings->SetTextTrackTextColor(
-      WebString::FromASCII(prefs.text_track_text_color));
-  settings->SetTextTrackTextSize(
-      WebString::FromASCII(prefs.text_track_text_size));
-  settings->SetTextTrackTextShadow(
-      WebString::FromASCII(prefs.text_track_text_shadow));
-  settings->SetTextTrackFontFamily(
-      WebString::FromASCII(prefs.text_track_font_family));
-  settings->SetTextTrackFontStyle(
-      WebString::FromASCII(prefs.text_track_font_style));
-  settings->SetTextTrackFontVariant(
-      WebString::FromASCII(prefs.text_track_font_variant));
-  settings->SetTextTrackMarginPercentage(prefs.text_track_margin_percentage);
-  settings->SetTextTrackWindowColor(
-      WebString::FromASCII(prefs.text_track_window_color));
-  settings->SetTextTrackWindowPadding(
-      WebString::FromASCII(prefs.text_track_window_padding));
-  settings->SetTextTrackWindowRadius(
-      WebString::FromASCII(prefs.text_track_window_radius));
-
-  // Needs to happen before SetDefaultPageScaleLimits below since that'll
-  // recalculate the final page scale limits and that depends on this setting.
-  settings->SetShrinksViewportContentToFit(
-      prefs.shrinks_viewport_contents_to_fit);
-
-  // Needs to happen before SetIgnoreViewportTagScaleLimits below.
-  web_view->SetDefaultPageScaleLimits(prefs.default_minimum_page_scale_factor,
-                                      prefs.default_maximum_page_scale_factor);
-
-  settings->SetFullscreenSupported(prefs.fullscreen_supported);
-  settings->SetTextAutosizingEnabled(prefs.text_autosizing_enabled);
-  settings->SetDoubleTapToZoomEnabled(prefs.double_tap_to_zoom_enabled);
-  blink::WebNetworkStateNotifier::SetNetworkQualityWebHoldback(
-      static_cast<blink::WebEffectiveConnectionType>(
-          prefs.network_quality_estimator_web_holdback));
-
-  settings->SetDontSendKeyEventsToJavascript(
-      prefs.dont_send_key_events_to_javascript);
-  settings->SetWebAppScope(WebString::FromASCII(prefs.web_app_scope.spec()));
-
-#if defined(OS_ANDROID)
-  settings->SetAllowCustomScrollbarInMainFrame(false);
-  settings->SetAccessibilityFontScaleFactor(prefs.font_scale_factor);
-  settings->SetDeviceScaleAdjustment(prefs.device_scale_adjustment);
-  web_view->SetIgnoreViewportTagScaleLimits(prefs.force_enable_zoom);
-  settings->SetAutoZoomFocusedNodeToLegibleScale(true);
-  settings->SetDefaultVideoPosterURL(
-      WebString::FromASCII(prefs.default_video_poster_url.spec()));
-  settings->SetSupportDeprecatedTargetDensityDPI(
-      prefs.support_deprecated_target_density_dpi);
-  settings->SetUseLegacyBackgroundSizeShorthandBehavior(
-      prefs.use_legacy_background_size_shorthand_behavior);
-  settings->SetWideViewportQuirkEnabled(prefs.wide_viewport_quirk);
-  settings->SetUseWideViewport(prefs.use_wide_viewport);
-  settings->SetForceZeroLayoutHeight(prefs.force_zero_layout_height);
-  settings->SetViewportMetaMergeContentQuirk(
-      prefs.viewport_meta_merge_content_quirk);
-  settings->SetViewportMetaNonUserScalableQuirk(
-      prefs.viewport_meta_non_user_scalable_quirk);
-  settings->SetViewportMetaZeroValuesQuirk(
-      prefs.viewport_meta_zero_values_quirk);
-  settings->SetClobberUserAgentInitialScaleQuirk(
-      prefs.clobber_user_agent_initial_scale_quirk);
-  settings->SetIgnoreMainFrameOverflowHiddenQuirk(
-      prefs.ignore_main_frame_overflow_hidden_quirk);
-  settings->SetReportScreenSizeInPhysicalPixelsQuirk(
-      prefs.report_screen_size_in_physical_pixels_quirk);
-  settings->SetShouldReuseGlobalForUnownedMainFrame(
-      prefs.reuse_global_for_unowned_main_frame);
-  settings->SetPreferHiddenVolumeControls(true);
-  settings->SetSpellCheckEnabledByDefault(prefs.spellcheck_enabled_by_default);
-
-  WebRuntimeFeatures::EnableVideoFullscreenOrientationLock(
-      prefs.video_fullscreen_orientation_lock_enabled);
-  WebRuntimeFeatures::EnableVideoRotateToFullscreen(
-      prefs.video_rotate_to_fullscreen_enabled);
-  settings->SetEmbeddedMediaExperienceEnabled(
-      prefs.embedded_media_experience_enabled);
-  settings->SetImmersiveModeEnabled(prefs.immersive_mode_enabled);
-  settings->SetDoNotUpdateSelectionOnMutatingSelectionRange(
-      prefs.do_not_update_selection_on_mutating_selection_range);
-  WebRuntimeFeatures::EnableCSSHexAlphaColor(prefs.css_hex_alpha_color_enabled);
-  WebRuntimeFeatures::EnableScrollTopLeftInterop(
-      prefs.scroll_top_left_interop_enabled);
-  WebRuntimeFeatures::EnableSurfaceEmbeddingFeatures(
-      !prefs.disable_features_depending_on_viz);
-  WebRuntimeFeatures::EnableAcceleratedSmallCanvases(
-      !prefs.disable_accelerated_small_canvases);
-  if (prefs.reenable_web_components_v0) {
-    WebRuntimeFeatures::EnableShadowDOMV0(true);
-    WebRuntimeFeatures::EnableCustomElementsV0(true);
-    WebRuntimeFeatures::EnableHTMLImports(true);
-  }
-#endif  // defined(OS_ANDROID)
-  settings->SetForceDarkModeEnabled(prefs.force_dark_mode_enabled);
-
-  settings->SetAccessibilityAlwaysShowFocus(prefs.always_show_focus);
-
-  switch (prefs.autoplay_policy) {
-    case blink::web_pref::AutoplayPolicy::kNoUserGestureRequired:
-      settings->SetAutoplayPolicy(
-          WebSettings::AutoplayPolicy::kNoUserGestureRequired);
-      break;
-    case blink::web_pref::AutoplayPolicy::kUserGestureRequired:
-      settings->SetAutoplayPolicy(
-          WebSettings::AutoplayPolicy::kUserGestureRequired);
-      break;
-    case blink::web_pref::AutoplayPolicy::kDocumentUserActivationRequired:
-      settings->SetAutoplayPolicy(
-          WebSettings::AutoplayPolicy::kDocumentUserActivationRequired);
-      break;
-  }
-
-  settings->SetViewportEnabled(prefs.viewport_enabled);
-  settings->SetViewportMetaEnabled(prefs.viewport_meta_enabled);
-  settings->SetViewportStyle(
-      static_cast<blink::WebViewportStyle>(prefs.viewport_style));
-
-  settings->SetLoadWithOverviewMode(prefs.initialize_at_minimum_page_scale);
-  settings->SetMainFrameResizesAreOrientationChanges(
-      prefs.main_frame_resizes_are_orientation_changes);
-
-  settings->SetShowContextMenuOnMouseUp(prefs.context_menu_on_mouse_up);
-  settings->SetAlwaysShowContextMenuOnTouch(
-      prefs.always_show_context_menu_on_touch);
-  settings->SetSmoothScrollForFindEnabled(prefs.smooth_scroll_for_find_enabled);
-
-  settings->SetHideDownloadUI(prefs.hide_download_ui);
-
-  settings->SetPresentationReceiver(prefs.presentation_receiver);
-
-  settings->SetMediaControlsEnabled(prefs.media_controls_enabled);
-
-  settings->SetLowPriorityIframesThreshold(
-      static_cast<blink::WebEffectiveConnectionType>(
-          prefs.low_priority_iframes_threshold));
-
-  settings->SetPictureInPictureEnabled(
-      prefs.picture_in_picture_enabled &&
-      MediaFactory::GetVideoSurfaceLayerMode() !=
-          blink::WebMediaPlayer::SurfaceLayerMode::kNever);
-
-  settings->SetDataSaverHoldbackWebApi(
-      prefs.data_saver_holdback_web_api_enabled);
-
-  settings->SetLazyLoadEnabled(prefs.lazy_load_enabled);
-  settings->SetPreferredColorScheme(prefs.preferred_color_scheme);
-
-  for (const auto& ect_distance_pair :
-       prefs.lazy_frame_loading_distance_thresholds_px) {
-    switch (ect_distance_pair.first) {
-      case net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN:
-        settings->SetLazyFrameLoadingDistanceThresholdPxUnknown(
-            ect_distance_pair.second);
-        continue;
-      case net::EFFECTIVE_CONNECTION_TYPE_OFFLINE:
-        settings->SetLazyFrameLoadingDistanceThresholdPxOffline(
-            ect_distance_pair.second);
-        continue;
-      case net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G:
-        settings->SetLazyFrameLoadingDistanceThresholdPxSlow2G(
-            ect_distance_pair.second);
-        continue;
-      case net::EFFECTIVE_CONNECTION_TYPE_2G:
-        settings->SetLazyFrameLoadingDistanceThresholdPx2G(
-            ect_distance_pair.second);
-        continue;
-      case net::EFFECTIVE_CONNECTION_TYPE_3G:
-        settings->SetLazyFrameLoadingDistanceThresholdPx3G(
-            ect_distance_pair.second);
-        continue;
-      case net::EFFECTIVE_CONNECTION_TYPE_4G:
-        settings->SetLazyFrameLoadingDistanceThresholdPx4G(
-            ect_distance_pair.second);
-        continue;
-      case net::EFFECTIVE_CONNECTION_TYPE_LAST:
-        continue;
-    }
-    NOTREACHED();
-  }
-
-  for (const auto& ect_distance_pair :
-       prefs.lazy_image_loading_distance_thresholds_px) {
-    switch (ect_distance_pair.first) {
-      case net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN:
-        settings->SetLazyImageLoadingDistanceThresholdPxUnknown(
-            ect_distance_pair.second);
-        continue;
-      case net::EFFECTIVE_CONNECTION_TYPE_OFFLINE:
-        settings->SetLazyImageLoadingDistanceThresholdPxOffline(
-            ect_distance_pair.second);
-        continue;
-      case net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G:
-        settings->SetLazyImageLoadingDistanceThresholdPxSlow2G(
-            ect_distance_pair.second);
-        continue;
-      case net::EFFECTIVE_CONNECTION_TYPE_2G:
-        settings->SetLazyImageLoadingDistanceThresholdPx2G(
-            ect_distance_pair.second);
-        continue;
-      case net::EFFECTIVE_CONNECTION_TYPE_3G:
-        settings->SetLazyImageLoadingDistanceThresholdPx3G(
-            ect_distance_pair.second);
-        continue;
-      case net::EFFECTIVE_CONNECTION_TYPE_4G:
-        settings->SetLazyImageLoadingDistanceThresholdPx4G(
-            ect_distance_pair.second);
-        continue;
-      case net::EFFECTIVE_CONNECTION_TYPE_LAST:
-        continue;
-    }
-    NOTREACHED();
-  }
-
-  for (const auto& fully_load_k_pair : prefs.lazy_image_first_k_fully_load) {
-    switch (fully_load_k_pair.first) {
-      case net::EFFECTIVE_CONNECTION_TYPE_OFFLINE:
-        continue;
-      case net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN:
-        settings->SetLazyImageFirstKFullyLoadUnknown(fully_load_k_pair.second);
-        continue;
-      case net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G:
-        settings->SetLazyImageFirstKFullyLoadSlow2G(fully_load_k_pair.second);
-        continue;
-      case net::EFFECTIVE_CONNECTION_TYPE_2G:
-        settings->SetLazyImageFirstKFullyLoad2G(fully_load_k_pair.second);
-        continue;
-      case net::EFFECTIVE_CONNECTION_TYPE_3G:
-        settings->SetLazyImageFirstKFullyLoad3G(fully_load_k_pair.second);
-        continue;
-      case net::EFFECTIVE_CONNECTION_TYPE_4G:
-        settings->SetLazyImageFirstKFullyLoad4G(fully_load_k_pair.second);
-        continue;
-      case net::EFFECTIVE_CONNECTION_TYPE_LAST:
-        continue;
-    }
-    NOTREACHED();
-  }
-
-  settings->SetTouchDragDropEnabled(prefs.touch_drag_drop_enabled);
-  settings->SetTouchDragEndContextMenu(prefs.touch_dragend_context_menu);
-
-#if defined(OS_MAC)
-  web_view->SetMaximumLegibleScale(prefs.default_maximum_page_scale_factor);
-#endif
-
-#if defined(OS_WIN)
-  WebRuntimeFeatures::EnableMiddleClickAutoscroll(true);
-#endif
-
-  WebRuntimeFeatures::EnableTranslateService(prefs.translate_service_available);
-}
-
-/*static*/
 RenderViewImpl* RenderViewImpl::Create(
     CompositorDependencies* compositor_deps,
     mojom::CreateViewParamsPtr params,
@@ -1017,14 +477,14 @@
 }
 
 bool RenderViewImpl::SupportsMultipleWindowsForWidget() {
-  return webkit_preferences_.supports_multiple_windows;
+  return webview_->GetWebPreferences().supports_multiple_windows;
 }
 
 bool RenderViewImpl::ShouldAckSyntheticInputImmediately() {
   // TODO(bokan): The RequestPresentation API appears not to function in VR. As
   // a short term workaround for https://crbug.com/940063, ACK input
   // immediately rather than using RequestPresentation.
-  if (webkit_preferences_.immersive_mode_enabled)
+  if (webview_->GetWebPreferences().immersive_mode_enabled)
     return true;
   return false;
 }
@@ -1237,7 +697,7 @@
 
   view_params->window_was_created_with_opener = true;
   view_params->renderer_preferences = renderer_preferences_.Clone();
-  view_params->web_preferences = webkit_preferences_;
+  view_params->web_preferences = webview_->GetWebPreferences();
   view_params->view_id = reply->route_id;
   view_params->main_frame_frame_token = reply->main_frame_frame_token;
   view_params->main_frame_routing_id = reply->main_frame_route_id;
@@ -1531,11 +991,11 @@
   return webview_->ZoomLevel();
 }
 
-const blink::web_pref::WebPreferences& RenderViewImpl::GetWebkitPreferences() {
-  return webkit_preferences_;
+const blink::web_pref::WebPreferences& RenderViewImpl::GetBlinkPreferences() {
+  return webview_->GetWebPreferences();
 }
 
-void RenderViewImpl::SetWebkitPreferences(
+void RenderViewImpl::SetBlinkPreferences(
     const blink::web_pref::WebPreferences& preferences) {
   OnUpdateWebPreferences(preferences);
 }
@@ -1550,9 +1010,7 @@
 
 void RenderViewImpl::OnUpdateWebPreferences(
     const blink::web_pref::WebPreferences& prefs) {
-  webkit_preferences_ = prefs;
-  ApplyWebPreferences(webkit_preferences_, GetWebView());
-  ApplyCommandLineToSettings(GetWebView()->GetSettings());
+  webview_->SetWebPreferences(prefs);
 }
 
 void RenderViewImpl::OnSetRendererPrefs(
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index 88f4dad..63c3e9b 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -137,10 +137,6 @@
   // or not.
   bool widgets_never_composited() const { return widgets_never_composited_; }
 
-  const blink::web_pref::WebPreferences& webkit_preferences() const {
-    return webkit_preferences_;
-  }
-
   const blink::mojom::RendererPreferences& renderer_preferences() const {
     return renderer_preferences_;
   }
@@ -241,8 +237,8 @@
   RenderFrameImpl* GetMainRenderFrame() override;
   int GetRoutingID() override;
   float GetZoomLevel() override;
-  const blink::web_pref::WebPreferences& GetWebkitPreferences() override;
-  void SetWebkitPreferences(
+  const blink::web_pref::WebPreferences& GetBlinkPreferences() override;
+  void SetBlinkPreferences(
       const blink::web_pref::WebPreferences& preferences) override;
   blink::WebView* GetWebView() override;
   bool GetContentStateImmediately() override;
@@ -456,7 +452,6 @@
 
   // Settings ------------------------------------------------------------------
 
-  blink::web_pref::WebPreferences webkit_preferences_;
   blink::mojom::RendererPreferences renderer_preferences_;
   // These are observing changes in |renderer_preferences_|. This is used for
   // keeping WorkerFetchContext in sync.
diff --git a/content/test/data/page_with_webotp.html b/content/test/data/page_with_webotp.html
new file mode 100644
index 0000000..415146b
--- /dev/null
+++ b/content/test/data/page_with_webotp.html
@@ -0,0 +1,9 @@
+<input autocomplete="one-time-code">
+<script>
+  const ac = document.querySelector('input[autocomplete="one-time-code"]');
+  navigator.credentials.get({
+    otp: {transport:['sms']}
+  })
+  .then(content => ac.value = content.code);
+</script>
+
diff --git a/content/web_test/renderer/pixel_dump.cc b/content/web_test/renderer/pixel_dump.cc
index 51c5f4a..5f80c47 100644
--- a/content/web_test/renderer/pixel_dump.cc
+++ b/content/web_test/renderer/pixel_dump.cc
@@ -46,7 +46,7 @@
 
   blink::WebSize page_size_in_pixels = frame_widget->Size();
 
-  int page_count = web_frame->PrintBegin(page_size_in_pixels);
+  uint32_t page_count = web_frame->PrintBegin(page_size_in_pixels);
   blink::WebSize spool_size =
       web_frame->SpoolSizeInPixelsForTesting(page_size_in_pixels, page_count);
 
diff --git a/content/web_test/renderer/test_runner.cc b/content/web_test/renderer/test_runner.cc
index d1a4e8c..c174e23 100644
--- a/content/web_test/renderer/test_runner.cc
+++ b/content/web_test/renderer/test_runner.cc
@@ -2771,12 +2771,12 @@
                                           RenderFrame* frame) {
   RenderView* render_view = frame->GetRenderView();
   blink::web_pref::WebPreferences web_prefs =
-      render_view->GetWebkitPreferences();
+      render_view->GetBlinkPreferences();
 
   // Turns the TestPreferences into WebPreferences.
   ExportWebTestSpecificPreferences(test_prefs, &web_prefs);
 
-  render_view->SetWebkitPreferences(web_prefs);
+  render_view->SetBlinkPreferences(web_prefs);
 
   GetWebTestControlHostRemote()->OverridePreferences(web_prefs);
 }
diff --git a/content/web_test/renderer/web_frame_test_proxy.cc b/content/web_test/renderer/web_frame_test_proxy.cc
index 7abf315..faea3aa 100644
--- a/content/web_test/renderer/web_frame_test_proxy.cc
+++ b/content/web_test/renderer/web_frame_test_proxy.cc
@@ -266,7 +266,7 @@
     blink::WebTestingSupport::ResetInternalsObject(GetWebFrame());
     // Resetting the internals object also overrides the WebPreferences, so we
     // have to sync them to WebKit again.
-    render_view()->SetWebkitPreferences(render_view()->GetWebkitPreferences());
+    render_view()->SetBlinkPreferences(render_view()->GetBlinkPreferences());
 
     GetLocalRootWebWidgetTestProxy()->GetWebViewTestProxy()->Reset();
   }
diff --git a/docs/linux/ozone_drm.md b/docs/linux/ozone_drm.md
index 1df8ff0..2bfa2df7 100644
--- a/docs/linux/ozone_drm.md
+++ b/docs/linux/ozone_drm.md
@@ -33,12 +33,13 @@
 [Building Chromium on a corporate Linux
 workstation](https://companydoc.corp.google.com/company/teams/chrome/build_instructions.md?cl=head)
 
-We want to build on linux on top of Ozone with gbm platform. The
-following instructions builds chromium targets along with minigbm
-that lives in the chromium tree `src/third_party/minigbm`. Currently,
-there is no builder for this configuration so while this worked
-(mostly) when this document was written, some experimentation may
-be necessary.
+We want to build on linux on top of Ozone with the DRM 
+(Direct Render Manager) platform which is backed by GBM 
+(Generic Buffer Management). The following instructions builds 
+chromium targets along with minigbm  that lives in the chromium 
+tree `src/third_party/minigbm`. Currently, there is no builder for
+this configuration so while this worked (mostly) when this document 
+was written, some experimentation may be necessary.
 
 Set the gn args for your output dir target `out/Nouveau` with:
 
@@ -48,8 +49,8 @@
 dcheck_always_on = true
 use_ozone = true
 target_os = "chromeos"
-ozone_platform_gbm = true
-ozone_platform = "gbm"
+ozone_platform_drm = true
+ozone_platform = "drm"
 use_system_minigbm = false
 target_sysroot = "//build/linux/debian_jessie_amd64-sysroot"
 is_debug = false
@@ -78,7 +79,7 @@
 $ sudo usermod -a -G video $USER
 $ sudo usermod -a -G audio $USER
 $ newgrp video
-$ negrrp plugdev
+$ newgrp plugdev
 $ newgrp audio
 $ # Stop pulseaudio if running:
 $ pactl exit
@@ -87,7 +88,7 @@
 Run chrome: (Set `CHROMIUM_SRC` to the directory containing your Chrome checkout.)
 
 ```
-$ sudo chvt 8; EGL_PLATFORM=surfaceless $CHROMIUM_SRC/out/Nouveau/chrome --ozone-platform=gbm --force-system-compositor-mode --login-profile=user --user-data-dir=$HOME/.config/google-chrome-gbm --use-gl=egl --enable-wayland-server --login-manager --ash-constrain-pointer-to-root --default-tile-width=512 --default-tile-height=512 --system-developer-mode --crosh-command=/bin/bash
+$ sudo chvt 8; EGL_PLATFORM=surfaceless $CHROMIUM_SRC/out/Nouveau/chrome --ozone-platform=drm --force-system-compositor-mode --login-profile=user --user-data-dir=$HOME/.config/google-chrome-gbm --use-gl=egl --enable-wayland-server --login-manager --ash-constrain-pointer-to-root --default-tile-width=512 --default-tile-height=512 --system-developer-mode --crosh-command=/bin/bash
 ```
 
 Login to Chrome settings should synchronize.
diff --git a/docs/ozone_overview.md b/docs/ozone_overview.md
index c04e78a..02ad2934 100644
--- a/docs/ozone_overview.md
+++ b/docs/ozone_overview.md
@@ -184,8 +184,8 @@
 
 You can turn properly implemented ozone platforms on and off by setting the
 corresponding flags in your GN configuration. For example
-`ozone_platform_headless=false ozone_platform_gbm=false` will turn off the
-headless and DRM/GBM platforms.
+`ozone_platform_headless=false ozone_platform_drm=false` will turn off the
+headless and DRM (GBM) platforms.
 This will result in a smaller binary and faster builds. To turn ALL platforms
 off by default, set `ozone_auto_platforms=false`.
 
@@ -198,16 +198,16 @@
 ## Running with Ozone
 
 Specify the platform you want to use at runtime using the `--ozone-platform`
-flag. For example, to run `content_shell` with the GBM platform:
+flag. For example, to run `content_shell` with the DRM (GBM) platform:
 
 ``` shell
-content_shell --ozone-platform=gbm
+content_shell --ozone-platform=drm
 ```
 
 Caveats:
 
 * `content_shell` always runs at 800x600 resolution.
-* For the GBM platform, you may need to terminate your X server (or any other
+* For the DRM (GBM) platform, you may need to terminate your X server (or any other
   display server) prior to testing.
 * During development, you may need to configure
   [sandboxing](linux/sandboxing.md) or to disable it.
diff --git a/headless/app/headless_shell.cc b/headless/app/headless_shell.cc
index 9de53a6..2e2a397 100644
--- a/headless/app/headless_shell.cc
+++ b/headless/app/headless_shell.cc
@@ -692,7 +692,7 @@
 
     // Renderer flags
     command_line.AppendSwitch(cc::switches::kDisableThreadedAnimation);
-    command_line.AppendSwitch(::switches::kDisableThreadedScrolling);
+    command_line.AppendSwitch(blink::switches::kDisableThreadedScrolling);
     command_line.AppendSwitch(cc::switches::kDisableCheckerImaging);
   }
 
diff --git a/headless/lib/DEPS b/headless/lib/DEPS
index 64a9481..225bf27 100644
--- a/headless/lib/DEPS
+++ b/headless/lib/DEPS
@@ -21,6 +21,7 @@
     "+components/viz/common/switches.h",
     "+pdf",
     "+printing",
+    "+third_party/blink/public/common/switches.h",
     "+third_party/skia/include",
   ]
 }
diff --git a/headless/lib/browser/headless_print_manager.cc b/headless/lib/browser/headless_print_manager.cc
index 96ee143..768d2025 100644
--- a/headless/lib/browser/headless_print_manager.cc
+++ b/headless/lib/browser/headless_print_manager.cc
@@ -72,15 +72,15 @@
 HeadlessPrintManager::PageRangeStatus
 HeadlessPrintManager::PageRangeTextToPages(base::StringPiece page_range_text,
                                            bool ignore_invalid_page_ranges,
-                                           int pages_count,
-                                           std::vector<int>* pages) {
+                                           uint32_t pages_count,
+                                           std::vector<uint32_t>* pages) {
   printing::PageRanges page_ranges;
   for (const auto& range_string :
        base::SplitStringPiece(page_range_text, ",", base::TRIM_WHITESPACE,
                               base::SPLIT_WANT_NONEMPTY)) {
     printing::PageRange range;
     if (range_string.find("-") == base::StringPiece::npos) {
-      if (!base::StringToInt(range_string, &range.from))
+      if (!base::StringToUint(range_string, &range.from))
         return SYNTAX_ERROR;
       range.to = range.from;
     } else if (range_string == "-") {
@@ -88,18 +88,18 @@
       range.to = pages_count;
     } else if (base::StartsWith(range_string, "-")) {
       range.from = 1;
-      if (!base::StringToInt(range_string.substr(1), &range.to))
+      if (!base::StringToUint(range_string.substr(1), &range.to))
         return SYNTAX_ERROR;
     } else if (base::EndsWith(range_string, "-")) {
       range.to = pages_count;
-      if (!base::StringToInt(range_string.substr(0, range_string.length() - 1),
-                             &range.from))
+      if (!base::StringToUint(range_string.substr(0, range_string.length() - 1),
+                              &range.from))
         return SYNTAX_ERROR;
     } else {
       auto tokens = base::SplitStringPiece(
           range_string, "-", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
-      if (tokens.size() != 2 || !base::StringToInt(tokens[0], &range.from) ||
-          !base::StringToInt(tokens[1], &range.to))
+      if (tokens.size() != 2 || !base::StringToUint(tokens[0], &range.from) ||
+          !base::StringToUint(tokens[1], &range.to))
         return SYNTAX_ERROR;
     }
 
diff --git a/headless/lib/browser/headless_print_manager.h b/headless/lib/browser/headless_print_manager.h
index cd762d5f..d636357 100644
--- a/headless/lib/browser/headless_print_manager.h
+++ b/headless/lib/browser/headless_print_manager.h
@@ -77,8 +77,8 @@
   HEADLESS_EXPORT static PageRangeStatus PageRangeTextToPages(
       base::StringPiece page_range_text,
       bool ignore_invalid_page_ranges,
-      int pages_count,
-      std::vector<int>* pages);
+      uint32_t pages_count,
+      std::vector<uint32_t>* pages);
 
   // Prints the current document immediately. Since the rendering is
   // asynchronous, the actual printing will not be completed on the return of
diff --git a/headless/lib/browser/headless_printing_unittest.cc b/headless/lib/browser/headless_printing_unittest.cc
index 7810ac1..25b78e2 100644
--- a/headless/lib/browser/headless_printing_unittest.cc
+++ b/headless/lib/browser/headless_printing_unittest.cc
@@ -15,8 +15,8 @@
 
 TEST(PageRangeTextToPagesTest, General) {
   using PM = HeadlessPrintManager;
-  std::vector<int> pages;
-  std::vector<int> expected_pages;
+  std::vector<uint32_t> pages;
+  std::vector<uint32_t> expected_pages;
 
   // "-" is full range of pages.
   PM::PageRangeStatus status = PM::PageRangeTextToPages("-", false, 10, &pages);
diff --git a/headless/lib/headless_content_main_delegate.cc b/headless/lib/headless_content_main_delegate.cc
index 230fa99..6e6e76a 100644
--- a/headless/lib/headless_content_main_delegate.cc
+++ b/headless/lib/headless_content_main_delegate.cc
@@ -492,10 +492,10 @@
         ::switches::kRunAllCompositorStagesBeforeDraw,
         ::switches::kDisableNewContentRenderingTimeout,
         cc::switches::kDisableThreadedAnimation,
-        ::switches::kDisableThreadedScrolling,
         // Animtion-only BeginFrames are only supported when updates from the
         // impl-thread are disabled, see go/headless-rendering.
         cc::switches::kDisableCheckerImaging,
+        blink::switches::kDisableThreadedScrolling,
         // Ensure that image animations don't resync their animation timestamps
         // when looping back around.
         blink::switches::kDisableImageAnimationResync,
diff --git a/headless/lib/headless_web_contents_browsertest.cc b/headless/lib/headless_web_contents_browsertest.cc
index 58ed7acc..8be63e4 100644
--- a/headless/lib/headless_web_contents_browsertest.cc
+++ b/headless/lib/headless_web_contents_browsertest.cc
@@ -39,6 +39,7 @@
 #include "printing/buildflags/buildflags.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/switches.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/codec/png_codec.h"
@@ -844,7 +845,7 @@
     command_line->AppendSwitch(::switches::kDisableNewContentRenderingTimeout);
     command_line->AppendSwitch(cc::switches::kDisableCheckerImaging);
     command_line->AppendSwitch(cc::switches::kDisableThreadedAnimation);
-    command_line->AppendSwitch(::switches::kDisableThreadedScrolling);
+    command_line->AppendSwitch(blink::switches::kDisableThreadedScrolling);
   }
 
   void OnCreateTargetResult(
diff --git a/headless/test/headless_protocol_browsertest.cc b/headless/test/headless_protocol_browsertest.cc
index a377922..a850825 100644
--- a/headless/test/headless_protocol_browsertest.cc
+++ b/headless/test/headless_protocol_browsertest.cc
@@ -301,7 +301,7 @@
         // impl-thread are disabled, see go/headless-rendering.
         cc::switches::kDisableThreadedAnimation,
         cc::switches::kDisableCheckerImaging,
-        switches::kDisableThreadedScrolling,
+        blink::switches::kDisableThreadedScrolling,
 
         // Ensure that image animations don't resync their animation timestamps
         // when looping back around.
diff --git a/infra/config/generated/cr-buildbucket-dev.cfg b/infra/config/generated/cr-buildbucket-dev.cfg
index eecd51e..289398a 100644
--- a/infra/config/generated/cr-buildbucket-dev.cfg
+++ b/infra/config/generated/cr-buildbucket-dev.cfg
@@ -136,7 +136,7 @@
       swarming_host: "chromium-swarm-dev.appspot.com"
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       recipe {
         name: "swarming/staging"
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg
index 80559927..8c3d3ea 100644
--- a/infra/config/generated/cr-buildbucket.cfg
+++ b/infra/config/generated/cr-buildbucket.cfg
@@ -3290,7 +3290,7 @@
       dimensions: "builder:Libfuzzer Upload Mac ASan"
       dimensions: "cores:24"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -4622,7 +4622,7 @@
       dimensions: "builder:Mac ASAN Release"
       dimensions: "cores:4"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -4650,7 +4650,7 @@
       dimensions: "builder:Mac ASAN Release Media"
       dimensions: "cores:4"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -4677,7 +4677,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "builder:Mac ASan 64 Builder"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -4705,7 +4705,7 @@
       dimensions: "builder:Mac ASan 64 Tests (1)"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -5332,7 +5332,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "builder:Mac deterministic"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -11404,7 +11404,7 @@
       dimensions: "builder:mac-archive-dbg"
       dimensions: "cores:4"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -11432,7 +11432,7 @@
       dimensions: "builder:mac-archive-rel"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -11545,7 +11545,7 @@
       dimensions: "builder:mac-hermetic-upgrade-rel"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -11712,7 +11712,7 @@
       dimensions: "builderless:1"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -15763,7 +15763,7 @@
       dimensions: "builder:Chromium Mac Goma RBE Staging"
       dimensions: "cores:4"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -15785,7 +15785,7 @@
       dimensions: "builder:Chromium Mac Goma RBE Staging (clobber)"
       dimensions: "cores:4"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -15807,7 +15807,7 @@
       dimensions: "builder:Chromium Mac Goma RBE Staging (dbg)"
       dimensions: "cores:4"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -15829,7 +15829,7 @@
       dimensions: "builder:Chromium Mac Goma RBE ToT"
       dimensions: "cores:4"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -15851,7 +15851,7 @@
       dimensions: "builder:Chromium Mac Goma Staging"
       dimensions: "cores:4"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -16079,7 +16079,7 @@
       dimensions: "builder:Mac Builder (dbg) Goma Canary"
       dimensions: "cores:4"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -16101,7 +16101,7 @@
       dimensions: "builder:Mac Builder (dbg) Goma Canary (clobber)"
       dimensions: "cores:4"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -16123,7 +16123,7 @@
       dimensions: "builder:Mac Builder (dbg) Goma Latest Client"
       dimensions: "cores:4"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -16145,7 +16145,7 @@
       dimensions: "builder:Mac Builder (dbg) Goma Latest Client (clobber)"
       dimensions: "cores:4"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -16167,7 +16167,7 @@
       dimensions: "builder:Mac Builder (dbg) Goma RBE Canary (clobber)"
       dimensions: "cores:4"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -16189,7 +16189,7 @@
       dimensions: "builder:Mac Builder (dbg) Goma RBE Latest Client (clobber)"
       dimensions: "cores:4"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -16211,7 +16211,7 @@
       dimensions: "builder:Mac Builder Goma Canary"
       dimensions: "cores:4"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -16233,7 +16233,7 @@
       dimensions: "builder:Mac Builder Goma Latest Client"
       dimensions: "cores:4"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -17033,7 +17033,7 @@
       dimensions: "builder:mac-archive-rel-goma-canary"
       dimensions: "cores:4"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -17055,7 +17055,7 @@
       dimensions: "builder:mac-archive-rel-goma-canary-localoutputcache"
       dimensions: "cores:4"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -17077,7 +17077,7 @@
       dimensions: "builder:mac-archive-rel-goma-latest"
       dimensions: "cores:4"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -17099,7 +17099,7 @@
       dimensions: "builder:mac-archive-rel-goma-latest-localoutputcache"
       dimensions: "cores:4"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -17121,7 +17121,7 @@
       dimensions: "builder:mac-archive-rel-goma-rbe-canary"
       dimensions: "cores:4"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -17143,7 +17143,7 @@
       dimensions: "builder:mac-archive-rel-goma-rbe-latest"
       dimensions: "cores:4"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -25313,7 +25313,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "builderless:1"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.try"
       dimensions: "ssd:1"
       exe {
@@ -25349,7 +25349,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "builderless:1"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.try"
       dimensions: "ssd:1"
       exe {
@@ -25888,7 +25888,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "builderless:1"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.try"
       dimensions: "ssd:1"
       exe {
@@ -29205,7 +29205,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "builderless:1"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.try"
       dimensions: "ssd:1"
       exe {
@@ -29241,7 +29241,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "builderless:1"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13|Mac-10.15"
+      dimensions: "os:Mac-10.13"
       dimensions: "pool:luci.chromium.try"
       dimensions: "ssd:1"
       exe {
diff --git a/infra/config/lib/builders.star b/infra/config/lib/builders.star
index 919e5d72..eae577b 100644
--- a/infra/config/lib/builders.star
+++ b/infra/config/lib/builders.star
@@ -65,8 +65,7 @@
     MAC_10_14 = os_enum("Mac-10.14", os_category.MAC),
     MAC_10_15 = os_enum("Mac-10.15", os_category.MAC),
     MAC_11_0 = os_enum("Mac-11.0", os_category.MAC),
-    # TODO(crbug/1121185): Remove 10.13 once builders have been migrated to 10.15.
-    MAC_DEFAULT = os_enum("Mac-10.13|Mac-10.15", os_category.MAC),
+    MAC_DEFAULT = os_enum("Mac-10.13", os_category.MAC),
     MAC_ANY = os_enum("Mac", os_category.MAC),
     WINDOWS_7 = os_enum("Windows-7", os_category.WINDOWS),
     WINDOWS_8_1 = os_enum("Windows-8.1", os_category.WINDOWS),
diff --git a/infra/config/subprojects/chromium/try.star b/infra/config/subprojects/chromium/try.star
index da0d6b39..cb50864d 100644
--- a/infra/config/subprojects/chromium/try.star
+++ b/infra/config/subprojects/chromium/try.star
@@ -1115,7 +1115,7 @@
     branch_selector = branches.STANDARD_RELEASES,
     goma_jobs = goma.jobs.J150,
     main_list_view = settings.main_list_view_name,
-    os = os.MAC_DEFAULT,
+    os = os.MAC_10_13,
     tryjob = try_.job(),
 )
 
@@ -1167,7 +1167,7 @@
     name = "mac_chromium_compile_dbg_ng",
     branch_selector = branches.STANDARD_RELEASES,
     goma_jobs = goma.jobs.J150,
-    os = os.MAC_DEFAULT,
+    os = os.MAC_10_13,
     main_list_view = settings.main_list_view_name,
     tryjob = try_.job(cancel_stale = False),
 )
diff --git a/infra/config/subprojects/chromium/versioned/m85/buckets/try.star b/infra/config/subprojects/chromium/versioned/m85/buckets/try.star
index dfa6346..fae363a1 100644
--- a/infra/config/subprojects/chromium/versioned/m85/buckets/try.star
+++ b/infra/config/subprojects/chromium/versioned/m85/buckets/try.star
@@ -445,14 +445,14 @@
 try_.chromium_mac_builder(
     name = "mac-rel",
     goma_jobs = goma.jobs.J150,
-    os = os.MAC_DEFAULT,
+    os = os.MAC_10_13,
     tryjob = try_.job(),
 )
 
 try_.chromium_mac_builder(
     name = "mac_chromium_compile_dbg_ng",
     goma_jobs = goma.jobs.J150,
-    os = os.MAC_DEFAULT,
+    os = os.MAC_10_13,
     tryjob = try_.job(),
 )
 
diff --git a/ios/chrome/test/perf/BUILD.gn b/ios/chrome/test/perf/BUILD.gn
deleted file mode 100644
index b79acf0a..0000000
--- a/ios/chrome/test/perf/BUILD.gn
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-source_set("eg_tests") {
-  configs += [ "//build/config/compiler:enable_arc" ]
-  testonly = true
-  sources = [ "chrome_perf_egtest.mm" ]
-  deps = [
-    "//ios/chrome/test/app:test_support",
-    "//ios/chrome/test/earl_grey:test_support",
-    "//ios/testing/perf:startup",
-  ]
-}
diff --git a/ios/chrome/test/perf/chrome_perf_egtest.mm b/ios/chrome/test/perf/chrome_perf_egtest.mm
deleted file mode 100644
index c90e37d..0000000
--- a/ios/chrome/test/perf/chrome_perf_egtest.mm
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import <XCTest/XCTest.h>
-
-#import "ios/testing/perf/startupLoggers.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-// Test class for chrome performance tests.
-@interface ChromePerfTestCase : XCTestCase
-@end
-
-@implementation ChromePerfTestCase
-
-- (void)testChromeColdStartup {
-  XCTAssertTrue(startup_loggers::LogData(@"testChromeColdStartup"));
-}
-
-@end
diff --git a/media/capture/video/chromeos/camera_3a_controller.cc b/media/capture/video/chromeos/camera_3a_controller.cc
index 19cb895a..dc93a18e 100644
--- a/media/capture/video/chromeos/camera_3a_controller.cc
+++ b/media/capture/video/chromeos/camera_3a_controller.cc
@@ -379,6 +379,24 @@
   DVLOG(1) << "Setting AF mode to: " << af_mode_;
 }
 
+void Camera3AController::SetAutoWhiteBalanceMode(
+    cros::mojom::AndroidControlAwbMode mode) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  if (!available_awb_modes_.count(mode)) {
+    LOG(WARNING) << "Don't support awb mode:" << mode;
+    return;
+  }
+
+  SetCaptureMetadata(
+      cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AWB_LOCK,
+      cros::mojom::AndroidControlAwbLock::ANDROID_CONTROL_AWB_LOCK_OFF);
+  awb_mode_ = mode;
+  Set3AMode(cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AWB_MODE,
+            base::checked_cast<uint8_t>(awb_mode_));
+  DVLOG(1) << "Setting AWB mode to: " << awb_mode_;
+}
+
 bool Camera3AController::IsPointOfInterestSupported() {
   return point_of_interest_supported_;
 }
@@ -522,7 +540,7 @@
          tag == cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AE_MODE ||
          tag == cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AWB_MODE);
 
-  SetCaptureMetadata(tag, target_mode);
+  SetRepeatingCaptureMetadata(tag, target_mode);
 
   switch (tag) {
     case cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE:
diff --git a/media/capture/video/chromeos/camera_3a_controller.h b/media/capture/video/chromeos/camera_3a_controller.h
index 717e90f..3a62006b 100644
--- a/media/capture/video/chromeos/camera_3a_controller.h
+++ b/media/capture/video/chromeos/camera_3a_controller.h
@@ -42,6 +42,9 @@
   // Enable the auto-focus mode suitable for video recording.
   void SetAutoFocusModeForVideoRecording();
 
+  // Set auto white balance mode.
+  void SetAutoWhiteBalanceMode(cros::mojom::AndroidControlAwbMode mode);
+
   bool IsPointOfInterestSupported();
 
   // Set point of interest. The coordinate system is based on the active
diff --git a/media/capture/video/chromeos/camera_3a_controller_unittest.cc b/media/capture/video/chromeos/camera_3a_controller_unittest.cc
index 3852a0f..520117f 100644
--- a/media/capture/video/chromeos/camera_3a_controller_unittest.cc
+++ b/media/capture/video/chromeos/camera_3a_controller_unittest.cc
@@ -207,17 +207,17 @@
                 AddResultMetadataObserver(_))
         .Times(1);
     EXPECT_CALL(*mock_capture_metadata_dispatcher_,
-                SetCaptureMetadata(
+                SetRepeatingCaptureMetadata(
                     cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE,
                     cros::mojom::EntryType::TYPE_BYTE, 1, _))
         .Times(1);
     EXPECT_CALL(*mock_capture_metadata_dispatcher_,
-                SetCaptureMetadata(
+                SetRepeatingCaptureMetadata(
                     cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AE_MODE,
                     cros::mojom::EntryType::TYPE_BYTE, 1, _))
         .Times(1);
     EXPECT_CALL(*mock_capture_metadata_dispatcher_,
-                SetCaptureMetadata(
+                SetRepeatingCaptureMetadata(
                     cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AWB_MODE,
                     cros::mojom::EntryType::TYPE_BYTE, 1, _))
         .Times(1);
@@ -249,7 +249,7 @@
                   cros::mojom::EntryType::TYPE_BYTE, 1, af_trigger_cancel))
       .Times(1);
   EXPECT_CALL(*mock_capture_metadata_dispatcher_,
-              SetCaptureMetadata(
+              SetRepeatingCaptureMetadata(
                   cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE,
                   cros::mojom::EntryType::TYPE_BYTE, 1, af_mode))
       .Times(1);
@@ -363,7 +363,7 @@
                   cros::mojom::EntryType::TYPE_BYTE, 1, af_trigger))
       .Times(1);
   EXPECT_CALL(*mock_capture_metadata_dispatcher_,
-              SetCaptureMetadata(
+              SetRepeatingCaptureMetadata(
                   cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE,
                   cros::mojom::EntryType::TYPE_BYTE, 1, af_mode))
       .Times(1);
@@ -391,7 +391,7 @@
                   cros::mojom::EntryType::TYPE_BYTE, 1, af_trigger))
       .Times(1);
   EXPECT_CALL(*mock_capture_metadata_dispatcher_,
-              SetCaptureMetadata(
+              SetRepeatingCaptureMetadata(
                   cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE,
                   cros::mojom::EntryType::TYPE_BYTE, 1, af_mode))
       .Times(1);
@@ -415,7 +415,7 @@
                   cros::mojom::EntryType::TYPE_BYTE, 1, af_trigger))
       .Times(1);
   EXPECT_CALL(*mock_capture_metadata_dispatcher_,
-              SetCaptureMetadata(
+              SetRepeatingCaptureMetadata(
                   cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE,
                   cros::mojom::EntryType::TYPE_BYTE, 1, af_mode))
       .Times(1);
@@ -445,7 +445,7 @@
                   cros::mojom::EntryType::TYPE_BYTE, 1, af_trigger))
       .Times(1);
   EXPECT_CALL(*mock_capture_metadata_dispatcher_,
-              SetCaptureMetadata(
+              SetRepeatingCaptureMetadata(
                   cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE,
                   cros::mojom::EntryType::TYPE_BYTE, 1, af_mode))
       .Times(1);
@@ -473,7 +473,7 @@
                   cros::mojom::EntryType::TYPE_BYTE, 1, af_trigger))
       .Times(1);
   EXPECT_CALL(*mock_capture_metadata_dispatcher_,
-              SetCaptureMetadata(
+              SetRepeatingCaptureMetadata(
                   cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE,
                   cros::mojom::EntryType::TYPE_BYTE, 1, af_mode))
       .Times(1);
@@ -497,7 +497,7 @@
                   cros::mojom::EntryType::TYPE_BYTE, 1, af_trigger))
       .Times(1);
   EXPECT_CALL(*mock_capture_metadata_dispatcher_,
-              SetCaptureMetadata(
+              SetRepeatingCaptureMetadata(
                   cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE,
                   cros::mojom::EntryType::TYPE_BYTE, 1, af_mode))
       .Times(1);
diff --git a/media/capture/video/chromeos/camera_device_delegate.cc b/media/capture/video/chromeos/camera_device_delegate.cc
index 38a795ec..4664908 100644
--- a/media/capture/video/chromeos/camera_device_delegate.cc
+++ b/media/capture/video/chromeos/camera_device_delegate.cc
@@ -13,6 +13,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/no_destructor.h"
 #include "base/numerics/ranges.h"
 #include "base/posix/safe_strerror.h"
 #include "base/strings/string_number_conversions.h"
@@ -46,6 +47,38 @@
 constexpr char kTiltRange[] = "com.google.control.tiltRange";
 constexpr char kZoom[] = "com.google.control.zoom";
 constexpr char kZoomRange[] = "com.google.control.zoomRange";
+constexpr int32_t kColorTemperatureStep = 100;
+
+using AwbModeTemperatureMap = std::map<uint8_t, int32_t>;
+
+const AwbModeTemperatureMap& GetAwbModeTemperatureMap() {
+  // https://source.android.com/devices/camera/camera3_3Amodes#auto-wb
+  static const base::NoDestructor<AwbModeTemperatureMap> kAwbModeTemperatureMap(
+      {
+          {static_cast<uint8_t>(cros::mojom::AndroidControlAwbMode::
+                                    ANDROID_CONTROL_AWB_MODE_INCANDESCENT),
+           2700},
+          {static_cast<uint8_t>(cros::mojom::AndroidControlAwbMode::
+                                    ANDROID_CONTROL_AWB_MODE_FLUORESCENT),
+           5000},
+          {static_cast<uint8_t>(cros::mojom::AndroidControlAwbMode::
+                                    ANDROID_CONTROL_AWB_MODE_WARM_FLUORESCENT),
+           3000},
+          {static_cast<uint8_t>(cros::mojom::AndroidControlAwbMode::
+                                    ANDROID_CONTROL_AWB_MODE_DAYLIGHT),
+           5500},
+          {static_cast<uint8_t>(cros::mojom::AndroidControlAwbMode::
+                                    ANDROID_CONTROL_AWB_MODE_CLOUDY_DAYLIGHT),
+           6500},
+          {static_cast<uint8_t>(cros::mojom::AndroidControlAwbMode::
+                                    ANDROID_CONTROL_AWB_MODE_TWILIGHT),
+           15000},
+          {static_cast<uint8_t>(cros::mojom::AndroidControlAwbMode::
+                                    ANDROID_CONTROL_AWB_MODE_SHADE),
+           7500},
+      });
+  return *kAwbModeTemperatureMap;
+}
 
 std::pair<int32_t, int32_t> GetTargetFrameRateRange(
     const cros::mojom::CameraMetadataPtr& static_metadata,
@@ -253,6 +286,7 @@
 
   result_metadata_frame_number_for_photo_state_ = 0;
   result_metadata_frame_number_ = 0;
+  is_set_awb_mode_ = false;
   is_set_brightness_ = false;
   is_set_contrast_ = false;
   is_set_pan_ = false;
@@ -260,6 +294,7 @@
   is_set_sharpness_ = false;
   is_set_tilt_ = false;
   is_set_zoom_ = false;
+
   chrome_capture_params_ = params;
   device_context_ = device_context;
   device_context_->SetState(CameraDeviceContext::State::kStarting);
@@ -447,6 +482,33 @@
         set_vendor_int(kZoom, settings->has_zoom, settings->zoom, is_set_zoom_);
   }
 
+  if (settings->has_white_balance_mode &&
+      settings->white_balance_mode == mojom::MeteringMode::MANUAL &&
+      settings->has_color_temperature) {
+    const AwbModeTemperatureMap& map = GetAwbModeTemperatureMap();
+    cros::mojom::AndroidControlAwbMode awb_mode =
+        cros::mojom::AndroidControlAwbMode::ANDROID_CONTROL_AWB_MODE_AUTO;
+    auto awb_available_modes = GetMetadataEntryAsSpan<uint8_t>(
+        static_metadata_,
+        cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AWB_AVAILABLE_MODES);
+    int32_t min_diff = std::numeric_limits<int32_t>::max();
+    for (const auto& mode : awb_available_modes) {
+      auto it = map.find(mode);
+      // Find the nearest awb mode
+      int32_t diff = std::abs(settings->color_temperature - it->second);
+      if (diff < min_diff) {
+        awb_mode = static_cast<cros::mojom::AndroidControlAwbMode>(mode);
+        min_diff = diff;
+      }
+    }
+    camera_3a_controller_->SetAutoWhiteBalanceMode(awb_mode);
+    is_set_awb_mode_ = true;
+  } else if (is_set_awb_mode_) {
+    camera_3a_controller_->SetAutoWhiteBalanceMode(
+        cros::mojom::AndroidControlAwbMode::ANDROID_CONTROL_AWB_MODE_AUTO);
+    is_set_awb_mode_ = false;
+  }
+
   bool is_resolution_specified = settings->has_width && settings->has_height;
   bool should_reconfigure_streams =
       is_resolution_specified && (current_blob_resolution_.IsEmpty() ||
@@ -1180,6 +1242,14 @@
         gfx::Rect(rect[0], rect[1], rect[2], rect[3]);
   }
 
+  result_metadata_.awb_mode.reset();
+  auto awb_mode = GetMetadataEntryAsSpan<uint8_t>(
+      result_metadata,
+      cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AWB_MODE);
+  if (awb_mode.size() == 1) {
+    result_metadata_.awb_mode = awb_mode[0];
+  }
+
   result_metadata_frame_number_ = frame_number;
   // We need to wait the new result metadata for new settings.
   if (result_metadata_frame_number_ >
@@ -1273,6 +1343,45 @@
     use_digital_zoom_ = false;
   }
 
+  auto awb_available_modes = GetMetadataEntryAsSpan<uint8_t>(
+      static_metadata_,
+      cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AWB_AVAILABLE_MODES);
+
+  // Only enable white balance control when there are more than 1 control modes.
+  if (awb_available_modes.size() > 1 && result_metadata_.awb_mode) {
+    photo_state->supported_white_balance_modes.push_back(
+        mojom::MeteringMode::MANUAL);
+    photo_state->supported_white_balance_modes.push_back(
+        mojom::MeteringMode::CONTINUOUS);
+    const AwbModeTemperatureMap& map = GetAwbModeTemperatureMap();
+    int32_t current_temperature = 0;
+    if (result_metadata_.awb_mode ==
+        static_cast<uint8_t>(
+            cros::mojom::AndroidControlAwbMode::ANDROID_CONTROL_AWB_MODE_AUTO))
+      photo_state->current_white_balance_mode = mojom::MeteringMode::CONTINUOUS;
+    else {
+      // Need to find current color temperature.
+      photo_state->current_white_balance_mode = mojom::MeteringMode::MANUAL;
+      current_temperature = map.at(result_metadata_.awb_mode.value());
+    }
+
+    int32_t min = std::numeric_limits<int32_t>::max();
+    int32_t max = std::numeric_limits<int32_t>::min();
+    for (const auto& mode : awb_available_modes) {
+      auto it = map.find(mode);
+      if (it == map.end())
+        continue;
+      if (it->second < min)
+        min = it->second;
+      else if (it->second > max)
+        max = it->second;
+    }
+    photo_state->color_temperature->min = min;
+    photo_state->color_temperature->max = max;
+    photo_state->color_temperature->step = kColorTemperatureStep;
+    photo_state->color_temperature->current = current_temperature;
+  }
+
   std::move(callback).Run(std::move(photo_state));
 }
 
diff --git a/media/capture/video/chromeos/camera_device_delegate.h b/media/capture/video/chromeos/camera_device_delegate.h
index 638e1d9b..78868a5 100644
--- a/media/capture/video/chromeos/camera_device_delegate.h
+++ b/media/capture/video/chromeos/camera_device_delegate.h
@@ -42,6 +42,7 @@
   ResultMetadata();
   ~ResultMetadata();
 
+  base::Optional<uint8_t> awb_mode;
   base::Optional<int32_t> brightness;
   base::Optional<int32_t> contrast;
   base::Optional<int32_t> pan;
@@ -240,6 +241,7 @@
   CameraAppDeviceImpl* camera_app_device_;  // Weak.
 
   // States of SetPhotoOptions
+  bool is_set_awb_mode_;
   bool is_set_brightness_;
   bool is_set_contrast_;
   bool is_set_pan_;
diff --git a/media/gpu/vaapi/BUILD.gn b/media/gpu/vaapi/BUILD.gn
index a3d25db1..883761e1 100644
--- a/media/gpu/vaapi/BUILD.gn
+++ b/media/gpu/vaapi/BUILD.gn
@@ -172,7 +172,7 @@
     "//ui/gfx:memory_buffer",
     "//ui/gl",
   ]
-  if (ozone_platform_gbm) {
+  if (ozone_platform_drm) {
     deps += [ "//ui/ozone" ]
   }
 
diff --git a/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
deleted file mode 100644
index 60f514d..0000000
--- a/mojo/public/tools/bindings/chromium_bindings_configuration.gni
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-_typemap_imports = [ "//chrome/typemaps.gni" ]
-
-_typemaps = []
-foreach(typemap_import, _typemap_imports) {
-  # Avoid reassignment error by assigning to empty scope first.
-  _imported = {
-  }
-  _imported = read_file(typemap_import, "scope")
-  _typemaps += _imported.typemaps
-}
-
-typemaps = []
-foreach(typemap, _typemaps) {
-  typemaps += [
-    {
-      filename = typemap
-      config = read_file(typemap, "scope")
-    },
-  ]
-}
-
-component_macro_suffix = ""
diff --git a/mojo/public/tools/bindings/format_typemap_generator_args.py b/mojo/public/tools/bindings/format_typemap_generator_args.py
deleted file mode 100755
index 7ac4af5f..0000000
--- a/mojo/public/tools/bindings/format_typemap_generator_args.py
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-from __future__ import print_function
-
-import sys
-
-# This utility converts mojom dependencies into their corresponding typemap
-# paths and formats them to be consumed by generate_type_mappings.py.
-
-
-def FormatTypemap(typemap_filename):
-  # A simple typemap is valid Python with a minor alteration.
-  with open(typemap_filename) as f:
-    typemap_content = f.read().replace('=\n', '=')
-  typemap = {}
-  exec typemap_content in typemap
-
-  for header in typemap.get('public_headers', []):
-    yield 'public_headers=%s' % header
-  for header in typemap.get('traits_headers', []):
-    yield 'traits_headers=%s' % header
-  for header in typemap.get('type_mappings', []):
-    yield 'type_mappings=%s' % header
-
-
-def main():
-  typemaps = sys.argv[1:]
-  print(' '.join('--start-typemap %s' % ' '.join(FormatTypemap(typemap))
-                 for typemap in typemaps))
-
-
-if __name__ == '__main__':
-  sys.exit(main())
diff --git a/mojo/public/tools/bindings/generate_type_mappings.py b/mojo/public/tools/bindings/generate_type_mappings.py
index 64ca048..a009664 100755
--- a/mojo/public/tools/bindings/generate_type_mappings.py
+++ b/mojo/public/tools/bindings/generate_type_mappings.py
@@ -75,14 +75,6 @@
     return json.load(f)['c++']
 
 
-def ParseTypemapArgs(args):
-  typemaps = [s for s in '\n'.join(args).split('--start-typemap\n') if s]
-  result = {}
-  for typemap in typemaps:
-    result.update(ParseTypemap(typemap))
-  return result
-
-
 def LoadCppTypemapConfig(path):
   configs = {}
   with open(path) as f:
@@ -102,52 +94,6 @@
         }
   return configs
 
-
-def ParseTypemap(typemap):
-  values = {'type_mappings': [], 'public_headers': [], 'traits_headers': []}
-  for line in typemap.split('\n'):
-    if not line:
-      continue
-    key, _, value = line.partition('=')
-    values[key].append(value.lstrip('/'))
-  result = {}
-  mapping_pattern = \
-      re.compile(r"""^([^=]+)           # mojom type
-                     =
-                     ([^[]+)            # native type
-                     (?:\[([^]]+)\])?$  # optional attribute in square brackets
-                 """, re.X)
-  for typename in values['type_mappings']:
-    match_result = mapping_pattern.match(typename)
-    assert match_result, (
-        "Cannot parse entry in the \"type_mappings\" section: %s" % typename)
-
-    mojom_type = match_result.group(1)
-    native_type = match_result.group(2)
-    attributes = []
-    if match_result.group(3):
-      attributes = match_result.group(3).split(',')
-
-    assert mojom_type not in result, (
-        "Cannot map multiple native types (%s, %s) to the same mojom type: %s" %
-        (result[mojom_type]['typename'], native_type, mojom_type))
-
-    result[mojom_type] = {
-        'public_headers': values['public_headers'],
-        'traits_headers': values['traits_headers'],
-        'typename': native_type,
-
-        # Attributes supported for individual mappings.
-        'copyable_pass_by_value': 'copyable_pass_by_value' in attributes,
-        'force_serialize': 'force_serialize' in attributes,
-        'hashable': 'hashable' in attributes,
-        'move_only': 'move_only' in attributes,
-        'non_copyable_non_movable': 'non_copyable_non_movable' in attributes,
-        'nullable_is_same_type': 'nullable_is_same_type' in attributes,
-    }
-  return result
-
-
 def main():
   parser = argparse.ArgumentParser(
       description=__doc__,
@@ -170,10 +116,10 @@
                       type=str,
                       required=True,
                       help='The path to which to write the generated JSON.')
-  params, typemap_params = parser.parse_known_args()
-  typemaps = ParseTypemapArgs(typemap_params)
+  params, _ = parser.parse_known_args()
+  typemaps = {}
   if params.cpp_config_path:
-    typemaps.update(LoadCppTypemapConfig(params.cpp_config_path))
+    typemaps = LoadCppTypemapConfig(params.cpp_config_path)
   missing = [path for path in params.dependency if not os.path.exists(path)]
   if missing:
     raise IOError('Missing dependencies: %s' % ', '.join(missing))
diff --git a/mojo/public/tools/bindings/mojom.gni b/mojo/public/tools/bindings/mojom.gni
index d5c389e..a676fae 100644
--- a/mojo/public/tools/bindings/mojom.gni
+++ b/mojo/public/tools/bindings/mojom.gni
@@ -140,43 +140,6 @@
   message_scrambling_inputs = []
 }
 
-if (enable_mojom_typemapping) {
-  _bindings_configuration_files =
-      [ "//mojo/public/tools/bindings/chromium_bindings_configuration.gni" ]
-  _bindings_configurations = []
-  foreach(config_file, _bindings_configuration_files) {
-    _bindings_configurations += [ read_file(config_file, "scope") ]
-  }
-  foreach(configuration, _bindings_configurations) {
-    # Check that the mojom field of each typemap refers to a mojom that exists.
-    foreach(typemap, configuration.typemaps) {
-      _typemap_config = {
-      }
-      _typemap_config = typemap.config
-      read_file(_typemap_config.mojom, "")
-    }
-  }
-} else {
-  _bindings_configuration_files = []
-  _bindings_configurations = [
-    {
-      typemaps = []
-      component_macro_suffix = ""
-    },
-  ]
-}
-
-if (!is_ios) {
-  _bindings_configurations += [
-    {
-      variant = "blink"
-      component_macro_suffix = "_BLINK"
-      for_blink = true
-      typemaps = []
-    },
-  ]
-}
-
 # Generates targets for building C++, JavaScript and Java bindings from mojom
 # files. The output files will go under the generated file directory tree with
 # the same path as each input file.
@@ -995,12 +958,22 @@
   }
 
   # Generate code for variants.
-  if (!defined(invoker.disable_variants) || !invoker.disable_variants) {
-    enabled_configurations = _bindings_configurations
+  default_variant = {
+    component_macro_suffix = ""
+  }
+  if ((!defined(invoker.disable_variants) || !invoker.disable_variants) &&
+      !is_ios) {
+    blink_variant = {
+      variant = "blink"
+      component_macro_suffix = "_BLINK"
+      for_blink = true
+    }
+    enabled_configurations = [
+      default_variant,
+      blink_variant,
+    ]
   } else {
-    first_config = _bindings_configurations[0]
-    assert(!defined(first_config.variant))
-    enabled_configurations = [ first_config ]
+    enabled_configurations = [ default_variant ]
   }
   foreach(bindings_configuration, enabled_configurations) {
     cpp_only = false
@@ -1089,7 +1062,6 @@
     type_mappings_target_name = "${target_name}${variant_suffix}__type_mappings"
     type_mappings_path =
         "$target_gen_dir/${target_name}${variant_suffix}__type_mappings"
-    active_typemaps = []
     if (sources_list != []) {
       generator_cpp_output_suffixes = []
       variant_dash_suffix = ""
@@ -1104,17 +1076,6 @@
         "${variant_dash_suffix}.cc",
         "${variant_dash_suffix}.h",
       ]
-      foreach(source, sources_list) {
-        # TODO(sammc): Use a map instead of a linear scan when GN supports maps.
-        foreach(typemap, bindings_configuration.typemaps) {
-          _typemap_config = {
-          }
-          _typemap_config = typemap.config
-          if (get_path_info(source, "abspath") == _typemap_config.mojom) {
-            active_typemaps += [ typemap ]
-          }
-        }
-      }
 
       generator_target_name = "${target_name}${variant_suffix}__generator"
       action(generator_target_name) {
@@ -1260,18 +1221,6 @@
           public_deps += [ "${full_name}_mojolpm" ]
         }
 
-        foreach(typemap, active_typemaps) {
-          _typemap_config = {
-          }
-          _typemap_config = typemap.config
-
-          if (defined(_typemap_config.deps)) {
-            deps += _typemap_config.deps
-          }
-          if (defined(_typemap_config.public_deps)) {
-            public_deps += _typemap_config.public_deps
-          }
-        }
         foreach(config, cpp_typemap_configs) {
           if (defined(config.traits_deps)) {
             deps += config.traits_deps
@@ -1321,8 +1270,8 @@
     }
 
     action(type_mappings_target_name) {
-      inputs = _bindings_configuration_files + mojom_generator_sources +
-               jinja2_sources + [ _typemap_stamp_filename ]
+      inputs =
+          mojom_generator_sources + jinja2_sources + [ _typemap_stamp_filename ]
       outputs = [ type_mappings_path ]
       script = "$mojom_generator_root/generate_type_mappings.py"
       deps = [ ":$_typemap_validator_target_name" ]
@@ -1349,46 +1298,12 @@
         ]
       }
 
-      if (sources_list != []) {
-        # TODO(sammc): Pass the typemap description in a file to avoid command
-        # line length limitations.
-        typemap_description = []
-        foreach(typemap, active_typemaps) {
-          _typemap_config = {
-          }
-          _typemap_config = typemap.config
-
-          typemap_description += [ "--start-typemap" ]
-          if (defined(_typemap_config.public_headers)) {
-            foreach(value, _typemap_config.public_headers) {
-              typemap_description += [ "public_headers=$value" ]
-            }
-          }
-          if (defined(_typemap_config.traits_headers)) {
-            foreach(value, _typemap_config.traits_headers) {
-              typemap_description += [ "traits_headers=$value" ]
-            }
-          }
-          foreach(value, _typemap_config.type_mappings) {
-            typemap_description += [ "type_mappings=$value" ]
-          }
-
-          # The typemap configuration files are not actually used as inputs here
-          # but this establishes a necessary build dependency to ensure that
-          # typemap changes force a rebuild of affected targets.
-          if (defined(typemap.filename)) {
-            inputs += [ typemap.filename ]
-          }
-        }
-        args += typemap_description
-
-        # Newer GN-based typemaps are aggregated into a single config.
-        inputs += [ _typemap_config_filename ]
-        args += [
-          "--cpp-typemap-config",
-          rebase_path(_typemap_config_filename, root_build_dir),
-        ]
-      }
+      # Newer GN-based typemaps are aggregated into a single config.
+      inputs += [ _typemap_config_filename ]
+      args += [
+        "--cpp-typemap-config",
+        rebase_path(_typemap_config_filename, root_build_dir),
+      ]
     }
 
     group("${target_name}${variant_suffix}_headers") {
@@ -1493,20 +1408,6 @@
           public_deps += invoker.component_deps
         }
       }
-      foreach(typemap, active_typemaps) {
-        _typemap_config = {
-        }
-        _typemap_config = typemap.config
-        if (defined(_typemap_config.sources)) {
-          sources += _typemap_config.sources
-        }
-        if (defined(_typemap_config.public_deps)) {
-          public_deps += _typemap_config.public_deps
-        }
-        if (defined(_typemap_config.deps)) {
-          deps += _typemap_config.deps
-        }
-      }
       foreach(config, cpp_typemap_configs) {
         if (defined(config.traits_sources)) {
           sources += config.traits_sources
diff --git a/mojo/public/tools/chrome_ipc/generate_mojom.py b/mojo/public/tools/chrome_ipc/generate_mojom.py
deleted file mode 100755
index 68cc0fa..0000000
--- a/mojo/public/tools/chrome_ipc/generate_mojom.py
+++ /dev/null
@@ -1,453 +0,0 @@
-#! /usr/bin/env python
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-"""A generator of mojom interfaces and typemaps from Chrome IPC messages.
-
-For example,
-generate_mojom.py content/common/file_utilities_messages.h
-    --output_mojom=content/common/file_utilities.mojom
-    --output_typemap=content/common/file_utilities.typemap
-"""
-
-import argparse
-import logging
-import os
-import re
-import subprocess
-import sys
-
-_MESSAGE_PATTERN = re.compile(
-    r'(?:\n|^)IPC_(SYNC_)?MESSAGE_(ROUTED|CONTROL)(\d_)?(\d)')
-_VECTOR_PATTERN = re.compile(r'std::(vector|set)<(.*)>')
-_MAP_PATTERN = re.compile(r'std::map<(.*), *(.*)>')
-_NAMESPACE_PATTERN = re.compile(r'([a-z_]*?)::([A-Z].*)')
-
-_unused_arg_count = 0
-
-
-def _git_grep(pattern, paths_pattern):
-  try:
-    args = ['git', 'grep', '-l', '-e', pattern, '--'] + paths_pattern
-    result = subprocess.check_output(args).strip().splitlines()
-    logging.debug('%s => %s', ' '.join(args), result)
-    return result
-  except subprocess.CalledProcessError:
-    logging.debug('%s => []', ' '.join(args))
-    return []
-
-
-def _git_multigrep(patterns, paths):
-  """Find a list of files that match all of the provided patterns."""
-  if isinstance(paths, str):
-    paths = [paths]
-  if isinstance(patterns, str):
-    patterns = [patterns]
-  for pattern in patterns:
-    # Search only the files that matched previous patterns.
-    paths = _git_grep(pattern, paths)
-    if not paths:
-      return []
-  return paths
-
-
-class Typemap(object):
-
-  def __init__(self, typemap_files):
-    self._typemap_files = typemap_files
-    self._custom_mappings = {}
-    self._new_custom_mappings = {}
-    self._imports = set()
-    self._public_includes = set()
-    self._traits_includes = set()
-    self._enums = set()
-
-  def load_typemaps(self):
-    for typemap in self._typemap_files:
-      self.load_typemap(typemap)
-
-  def load_typemap(self, path):
-    typemap = {}
-    with open(path) as f:
-      content = f.read().replace('=\n', '=')
-    exec content in typemap
-    for mapping in typemap['type_mappings']:
-      mojom, native = mapping.split('=')
-      self._custom_mappings[native] = {'name': mojom,
-                                       'mojom': typemap['mojom'].strip('/')}
-
-  def generate_typemap(self, output_mojom, input_filename, namespace):
-    new_mappings = sorted(self._format_new_mappings(namespace))
-    if not new_mappings:
-      return
-    yield """# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-"""
-    yield 'mojom = "//%s"' % output_mojom
-    yield 'public_headers = [%s\n]' % ''.join(
-        '\n  "//%s",' % include for include in sorted(self._public_includes))
-    yield 'traits_headers = [%s\n]' % ''.join(
-        '\n  "//%s",' % include
-        for include in sorted(self._traits_includes.union([os.path.normpath(
-            input_filename)])))
-    yield 'deps = [ "//ipc" ]'
-    yield 'type_mappings = [\n  %s\n]' % '\n  '.join(new_mappings)
-
-  def _format_new_mappings(self, namespace):
-    for native, mojom in self._new_custom_mappings.items():
-      yield '"%s.%s=::%s",' % (namespace, mojom, native)
-
-  def format_new_types(self):
-    for native_type, typename in self._new_custom_mappings.items():
-      if native_type in self._enums:
-        yield '[Native]\nenum %s;\n' % typename
-      else:
-        yield '[Native]\nstruct %s;\n' % typename
-
-  _BUILTINS = {
-      'bool': 'bool',
-      'int': 'int32',
-      'unsigned': 'uint32',
-      'char': 'uint8',
-      'unsigned char': 'uint8',
-      'short': 'int16',
-      'unsigned short': 'uint16',
-      'int8_t': 'int8',
-      'int16_t': 'int16',
-      'int32_t': 'int32',
-      'int64_t': 'int64',
-      'uint8_t': 'uint8',
-      'uint16_t': 'uint16',
-      'uint32_t': 'uint32',
-      'uint64_t': 'uint64',
-      'float': 'float',
-      'double': 'double',
-      'std::string': 'string',
-      'base::string16': 'string',
-      'base::FilePath::StringType': 'string',
-      'base::SharedMemoryHandle': 'handle<shared_memory>',
-      'IPC::PlatformFileForTransit': 'handle',
-      'base::FileDescriptor': 'handle',
-  }
-
-  def lookup_type(self, typename):
-    try:
-      return self._BUILTINS[typename]
-    except KeyError:
-      pass
-
-    vector_match = _VECTOR_PATTERN.search(typename)
-    if vector_match:
-      return 'array<%s>' % self.lookup_type(vector_match.groups()[1].strip())
-    map_match = _MAP_PATTERN.search(typename)
-    if map_match:
-      return 'map<%s, %s>' % tuple(self.lookup_type(t.strip())
-                                   for t in map_match.groups())
-    try:
-      result = self._custom_mappings[typename]['name']
-      mojom = self._custom_mappings[typename].get('mojom', None)
-      if mojom:
-        self._imports.add(mojom)
-      return result
-    except KeyError:
-      pass
-
-    match = _NAMESPACE_PATTERN.match(typename)
-    if match:
-      namespace, name = match.groups()
-    else:
-      namespace = ''
-      name = typename
-    namespace = namespace.replace('::', '.')
-    cpp_name = name
-    name = name.replace('::', '')
-
-    if name.endswith('Params'):
-      try:
-        _, name = name.rsplit('Msg_')
-      except ValueError:
-        try:
-          _, name = name.split('_', 1)
-        except ValueError:
-          pass
-
-    if namespace.endswith('.mojom'):
-      generated_mojom_name = '%s.%s' % (namespace, name)
-    elif not namespace:
-      generated_mojom_name = 'mojom.%s' % name
-    else:
-      generated_mojom_name = '%s.mojom.%s' % (namespace, name)
-
-    self._new_custom_mappings[typename] = name
-    self._add_includes(namespace, cpp_name, typename)
-    generated_mojom_name = name
-    self._custom_mappings[typename] = {'name': generated_mojom_name}
-    return generated_mojom_name
-
-  def _add_includes(self, namespace, name, fullname):
-    name_components = name.split('::')
-    is_enum = False
-    for i in xrange(len(name_components)):
-      subname = '::'.join(name_components[i:])
-      extra_names = name_components[:i] + [subname]
-      patterns = [r'\(struct\|class\|enum\)[A-Z_ ]* %s {' % s
-                  for s in extra_names]
-      if namespace:
-        patterns.extend(r'namespace %s' % namespace_component
-                        for namespace_component in namespace.split('.'))
-      includes = _git_multigrep(patterns, '*.h')
-      if includes:
-        if _git_grep(r'enum[A-Z_ ]* %s {' % subname, includes):
-          self._enums.add(fullname)
-          is_enum = True
-        logging.info('%s => public_headers = %s', fullname, includes)
-        self._public_includes.update(includes)
-        break
-
-    if is_enum:
-      patterns = ['IPC_ENUM_TRAITS[A-Z_]*(%s' % fullname]
-    else:
-      patterns = [r'\(IPC_STRUCT_TRAITS_BEGIN(\|ParamTraits<\)%s' % fullname]
-    includes = _git_multigrep(
-        patterns,
-        ['*messages.h', '*struct_traits.h', 'ipc/ipc_message_utils.h'])
-    if includes:
-      logging.info('%s => traits_headers = %s', fullname, includes)
-      self._traits_includes.update(includes)
-
-  def format_imports(self):
-    for import_name in sorted(self._imports):
-      yield 'import "%s";' % import_name
-    if self._imports:
-      yield ''
-
-
-class Argument(object):
-
-  def __init__(self, typename, name):
-    self.typename = typename.strip()
-    self.name = name.strip().replace('\n', '').replace(' ', '_').lower()
-    if not self.name:
-      global _unused_arg_count
-      self.name = 'unnamed_arg%d' % _unused_arg_count
-      _unused_arg_count += 1
-
-  def format(self, typemaps):
-    return '%s %s' % (typemaps.lookup_type(self.typename), self.name)
-
-
-class Message(object):
-
-  def __init__(self, match, content):
-    self.sync = bool(match[0])
-    self.routed = match[1] == 'ROUTED'
-    self.args = []
-    self.response_args = []
-    if self.sync:
-      num_expected_args = int(match[2][:-1])
-      num_expected_response_args = int(match[3])
-    else:
-      num_expected_args = int(match[3])
-      num_expected_response_args = 0
-    body = content.split(',')
-    name = body[0].strip()
-    try:
-      self.group, self.name = name.split('Msg_')
-    except ValueError:
-      try:
-        self.group, self.name = name.split('_')
-      except ValueError:
-        self.group = 'UnnamedInterface'
-        self.name = name
-    self.group = '%s%s' % (self.group, match[1].title())
-    args = list(self.parse_args(','.join(body[1:])))
-    if len(args) != num_expected_args + num_expected_response_args:
-      raise Exception('Incorrect number of args parsed for %s' % (name))
-    self.args = args[:num_expected_args]
-    self.response_args = args[num_expected_args:]
-
-  def parse_args(self, args_str):
-    args_str = args_str.strip()
-    if not args_str:
-      return
-    looking_for_type = False
-    type_start = 0
-    comment_start = None
-    comment_end = None
-    type_end = None
-    angle_bracket_nesting = 0
-    i = 0
-    while i < len(args_str):
-      if args_str[i] == ',' and not angle_bracket_nesting:
-        looking_for_type = True
-        if type_end is None:
-          type_end = i
-      elif args_str[i:i + 2] == '/*':
-        if type_end is None:
-          type_end = i
-        comment_start = i + 2
-        comment_end = args_str.index('*/', i + 2)
-        i = comment_end + 1
-      elif args_str[i:i + 2] == '//':
-        if type_end is None:
-          type_end = i
-        comment_start = i + 2
-        comment_end = args_str.index('\n', i + 2)
-        i = comment_end
-      elif args_str[i] == '<':
-        angle_bracket_nesting += 1
-      elif args_str[i] == '>':
-        angle_bracket_nesting -= 1
-      elif looking_for_type and args_str[i].isalpha():
-        if comment_start is not None and comment_end is not None:
-          yield Argument(args_str[type_start:type_end],
-                         args_str[comment_start:comment_end])
-        else:
-          yield Argument(args_str[type_start:type_end], '')
-        type_start = i
-        type_end = None
-        comment_start = None
-        comment_end = None
-        looking_for_type = False
-      i += 1
-    if comment_start is not None and comment_end is not None:
-      yield Argument(args_str[type_start:type_end],
-                     args_str[comment_start:comment_end])
-    else:
-      yield Argument(args_str[type_start:type_end], '')
-
-  def format(self, typemaps):
-    result = '%s(%s)' % (self.name, ','.join('\n      %s' % arg.format(typemaps)
-                                             for arg in self.args))
-    if self.sync:
-      result += ' => (%s)' % (',\n'.join('\n      %s' % arg.format(typemaps)
-                                         for arg in self.response_args))
-      result = '[Sync]\n  %s' % result
-    return '%s;' % result
-
-
-class Generator(object):
-
-  def __init__(self, input_name, output_namespace):
-    self._input_name = input_name
-    with open(input_name) as f:
-      self._content = f.read()
-    self._namespace = output_namespace
-    self._typemaps = Typemap(self._find_typemaps())
-    self._interface_definitions = []
-
-  def _get_messages(self):
-    for m in _MESSAGE_PATTERN.finditer(self._content):
-      i = m.end() + 1
-      while i < len(self._content):
-        if self._content[i:i + 2] == '/*':
-          i = self._content.index('*/', i + 2) + 1
-        elif self._content[i] == ')':
-          yield Message(m.groups(), self._content[m.end() + 1:i])
-          break
-        i += 1
-
-  def _extract_messages(self):
-    grouped_messages = {}
-    for m in self._get_messages():
-      grouped_messages.setdefault(m.group, []).append(m)
-    self._typemaps.load_typemaps()
-    for interface, messages in grouped_messages.items():
-      self._interface_definitions.append(self._format_interface(interface,
-                                                                messages))
-
-  def count(self):
-    grouped_messages = {}
-    for m in self._get_messages():
-      grouped_messages.setdefault(m.group, []).append(m)
-    return sum(len(messages) for messages in grouped_messages.values())
-
-  def generate_mojom(self):
-    self._extract_messages()
-    if not self._interface_definitions:
-      return
-    yield """// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-"""
-    yield 'module %s;\n' % self._namespace
-    for import_statement in self._typemaps.format_imports():
-      yield import_statement
-    for typemap in self._typemaps.format_new_types():
-      yield typemap
-    for interface in self._interface_definitions:
-      yield interface
-      yield ''
-
-  def generate_typemap(self, output_mojom, input_filename):
-    return '\n'.join(self._typemaps.generate_typemap(
-        output_mojom, input_filename, self._namespace)).strip()
-
-  @staticmethod
-  def _find_typemaps():
-    return subprocess.check_output(
-        ['git', 'ls-files', '*.typemap']).strip().split('\n')
-
-  def _format_interface(self, name, messages):
-    return 'interface %s {\n  %s\n};' % (name,
-                                         '\n  '.join(m.format(self._typemaps)
-                                                     for m in messages))
-
-
-def parse_args():
-  parser = argparse.ArgumentParser(description=__doc__)
-  parser.add_argument('input', help='input messages.h file')
-  parser.add_argument(
-      '--output_namespace',
-      default='mojom',
-      help='the mojom module name to use in the generated mojom file '
-      '(default: %(default)s)')
-  parser.add_argument('--output_mojom', help='output mojom path')
-  parser.add_argument('--output_typemap', help='output typemap path')
-  parser.add_argument(
-      '--count',
-      action='store_true',
-      default=False,
-      help='count the number of messages in the input instead of generating '
-      'a mojom file')
-  parser.add_argument('-v',
-                      '--verbose',
-                      action='store_true',
-                      help='enable logging')
-  parser.add_argument('-vv', action='store_true', help='enable debug logging')
-  return parser.parse_args()
-
-
-def main():
-  args = parse_args()
-  if args.vv:
-    logging.basicConfig(level=logging.DEBUG)
-  elif args.verbose:
-    logging.basicConfig(level=logging.INFO)
-  generator = Generator(args.input, args.output_namespace)
-  if args.count:
-    count = generator.count()
-    if count:
-      print('%d %s' % (generator.count(), args.input))
-    return
-  mojom = '\n'.join(generator.generate_mojom()).strip()
-  if not mojom:
-    return
-  typemap = generator.generate_typemap(args.output_mojom, args.input)
-
-  if args.output_mojom:
-    with open(args.output_mojom, 'w') as f:
-      f.write(mojom)
-  else:
-    print(mojom)
-  if typemap:
-    if args.output_typemap:
-      with open(args.output_typemap, 'w') as f:
-        f.write(typemap)
-    else:
-      print(typemap)
-
-
-if __name__ == '__main__':
-  sys.exit(main())
diff --git a/net/dns/BUILD.gn b/net/dns/BUILD.gn
index 4a7e19e..b8da0cde 100644
--- a/net/dns/BUILD.gn
+++ b/net/dns/BUILD.gn
@@ -182,6 +182,11 @@
   # Restricted access so we can keep track of all usage external to the
   # network stack and network service.
   friend = [
+    # DNS Config and Overrides for Chrome browser.
+    # TODO (ericorth): Make DnsConfig(Overrides) public so //chrome/browser does
+    # not need to depend on host_resolver.
+    "//chrome/browser",
+
     # chromecast/browser/url_request_context_factory.cc
     # URLRequestContext creation for chromecast.
     "//chromecast/browser",
diff --git a/pdf/ppapi_migration/url_loader.cc b/pdf/ppapi_migration/url_loader.cc
index ce47d89..c960aaf6 100644
--- a/pdf/ppapi_migration/url_loader.cc
+++ b/pdf/ppapi_migration/url_loader.cc
@@ -4,13 +4,15 @@
 
 #include "pdf/ppapi_migration/url_loader.h"
 
+#include <stddef.h>
 #include <stdint.h>
 
+#include <algorithm>
 #include <utility>
 
 #include "base/bind.h"
 #include "base/callback.h"
-#include "base/check.h"
+#include "base/check_op.h"
 #include "base/memory/weak_ptr.h"
 #include "base/notreached.h"
 #include "pdf/ppapi_migration/callback.h"
@@ -23,8 +25,14 @@
 #include "ppapi/cpp/url_request_info.h"
 #include "ppapi/cpp/url_response_info.h"
 #include "ppapi/cpp/var.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
+#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/public/platform/web_url.h"
+#include "third_party/blink/public/platform/web_url_request.h"
+#include "third_party/blink/public/platform/web_url_response.h"
 #include "third_party/blink/public/web/web_associated_url_loader.h"
 #include "third_party/blink/public/web/web_associated_url_loader_options.h"
+#include "url/gurl.h"
 
 namespace chrome_pdf {
 
@@ -50,27 +58,42 @@
 
 BlinkUrlLoader::~BlinkUrlLoader() = default;
 
+// Modeled on `content::PepperURLLoaderHost::OnHostMsgGrantUniversalAccess()`.
 void BlinkUrlLoader::GrantUniversalAccess() {
-  DCHECK(!blink_loader_);
+  DCHECK_EQ(state_, LoadingState::kWaitingToOpen);
   grant_universal_access_ = true;
 }
 
 // Modeled on `content::PepperURLLoaderHost::OnHostMsgOpen()`.
 void BlinkUrlLoader::Open(const UrlRequest& request, ResultCallback callback) {
+  DCHECK_EQ(state_, LoadingState::kWaitingToOpen);
+  DCHECK(callback);
+  state_ = LoadingState::kOpening;
+  open_callback_ = std::move(callback);
+
   if (!client_) {
-    std::move(callback).Run(PP_ERROR_FAILED);
+    AbortLoad(PP_ERROR_FAILED);
     return;
   }
 
+  // Modeled on `content::CreateWebURLRequest()`.
+  blink::WebURLRequest blink_request;
+  blink_request.SetUrl(GURL(request.url));
+  blink_request.SetHttpMethod(blink::WebString::FromASCII(request.method));
+
+  blink_request.SetRequestContext(blink::mojom::RequestContextType::PLUGIN);
+  blink_request.SetRequestDestination(
+      network::mojom::RequestDestination::kEmbed);
+
   blink::WebAssociatedURLLoaderOptions options;
   options.grant_universal_access = grant_universal_access_;
   blink_loader_ = client_->CreateAssociatedURLLoader(options);
   if (!blink_loader_) {
-    std::move(callback).Run(PP_ERROR_FAILED);
+    AbortLoad(PP_ERROR_FAILED);
     return;
   }
 
-  NOTIMPLEMENTED();
+  blink_loader_->LoadAsynchronously(blink_request, this);
 }
 
 bool BlinkUrlLoader::GetDownloadProgress(
@@ -80,13 +103,32 @@
   return false;
 }
 
+// Modeled on `ppapi::proxy::URLLoaderResource::ReadResponseBody()`.
 void BlinkUrlLoader::ReadResponseBody(base::span<char> buffer,
                                       ResultCallback callback) {
-  NOTIMPLEMENTED();
+  // Can be in `kLoadComplete` if still reading after loading finished.
+  DCHECK(state_ == LoadingState::kStreamingData ||
+         state_ == LoadingState::kLoadComplete)
+      << static_cast<int>(state_);
+
+  if (buffer.empty()) {
+    std::move(callback).Run(PP_ERROR_BADARGUMENT);
+    return;
+  }
+
+  DCHECK(!read_callback_);
+  DCHECK(callback);
+  read_callback_ = std::move(callback);
+  client_buffer_ = buffer;
+
+  if (!buffer_.empty() || state_ == LoadingState::kLoadComplete)
+    RunReadCallback();
 }
 
+// Modeled on `ppapi::proxy::URLLoadResource::Close()`.
 void BlinkUrlLoader::Close() {
-  NOTIMPLEMENTED();
+  if (state_ != LoadingState::kLoadComplete)
+    AbortLoad(PP_ERROR_ABORTED);
 }
 
 bool BlinkUrlLoader::WillFollowRedirect(
@@ -102,8 +144,14 @@
   NOTREACHED();
 }
 
+// Modeled on `content::PepperURLLoaderHost::DidReceiveResponse()`.
 void BlinkUrlLoader::DidReceiveResponse(const blink::WebURLResponse& response) {
-  NOTIMPLEMENTED();
+  DCHECK_EQ(state_, LoadingState::kOpening);
+
+  mutable_response().status_code = response.HttpStatusCode();
+
+  state_ = LoadingState::kStreamingData;
+  std::move(open_callback_).Run(PP_OK);
 }
 
 void BlinkUrlLoader::DidDownloadData(uint64_t data_length) {
@@ -111,8 +159,16 @@
   NOTREACHED();
 }
 
+// Modeled on `content::PepperURLLoaderHost::DidReceiveData()`.
 void BlinkUrlLoader::DidReceiveData(const char* data, int data_length) {
-  NOTIMPLEMENTED();
+  DCHECK_EQ(state_, LoadingState::kStreamingData);
+
+  // It's surprisingly difficult to guarantee that this is always >0.
+  if (data_length < 1)
+    return;
+
+  buffer_.insert(buffer_.end(), data, data + data_length);
+  RunReadCallback();
 }
 
 void BlinkUrlLoader::DidReceiveCachedMetadata(const char* data,
@@ -121,14 +177,65 @@
   NOTREACHED();
 }
 
+// Modeled on `content::PepperURLLoaderHost::DidFinishLoading()`.
 void BlinkUrlLoader::DidFinishLoading() {
-  NOTIMPLEMENTED();
+  DCHECK_EQ(state_, LoadingState::kStreamingData);
+
+  SetLoadComplete(PP_OK);
+  RunReadCallback();
 }
 
 void BlinkUrlLoader::DidFail(const blink::WebURLError& error) {
   NOTIMPLEMENTED();
 }
 
+void BlinkUrlLoader::AbortLoad(int32_t result) {
+  DCHECK_LT(result, 0);
+
+  SetLoadComplete(result);
+  buffer_.clear();
+
+  if (open_callback_) {
+    DCHECK(!read_callback_);
+    std::move(open_callback_).Run(complete_result_);
+  } else if (read_callback_) {
+    RunReadCallback();
+  }
+}
+
+// Modeled on `ppapi::proxy::URLLoaderResource::FillUserBuffer()`.
+void BlinkUrlLoader::RunReadCallback() {
+  if (!read_callback_)
+    return;
+
+  DCHECK(!client_buffer_.empty());
+  int32_t num_bytes = std::min(
+      {buffer_.size(), client_buffer_.size(), static_cast<size_t>(INT32_MAX)});
+  if (num_bytes > 0) {
+    auto read_begin = buffer_.begin();
+    auto read_end = read_begin + num_bytes;
+    std::copy(read_begin, read_end, client_buffer_.data());
+    buffer_.erase(read_begin, read_end);
+  } else {
+    DCHECK_EQ(state_, LoadingState::kLoadComplete);
+    num_bytes = complete_result_;
+    DCHECK_LE(num_bytes, 0);
+    static_assert(PP_OK == 0, "PP_OK should be equivalent to 0 bytes");
+  }
+
+  client_buffer_ = {};
+  std::move(read_callback_).Run(num_bytes);
+}
+
+void BlinkUrlLoader::SetLoadComplete(int32_t result) {
+  DCHECK_NE(state_, LoadingState::kLoadComplete);
+  DCHECK_LE(result, 0);
+
+  state_ = LoadingState::kLoadComplete;
+  complete_result_ = result;
+  blink_loader_.reset();
+}
+
 PepperUrlLoader::PepperUrlLoader(pp::InstanceHandle plugin_instance)
     : plugin_instance_(plugin_instance), pepper_loader_(plugin_instance) {}
 
diff --git a/pdf/ppapi_migration/url_loader.h b/pdf/ppapi_migration/url_loader.h
index 60db83f..4dd7e04 100644
--- a/pdf/ppapi_migration/url_loader.h
+++ b/pdf/ppapi_migration/url_loader.h
@@ -10,6 +10,8 @@
 #include <memory>
 #include <string>
 
+#include "base/callback.h"
+#include "base/containers/circular_deque.h"
 #include "base/containers/span.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
@@ -152,10 +154,43 @@
   void DidFail(const blink::WebURLError& error) override;
 
  private:
+  enum class LoadingState {
+    // Before calling `Open()`.
+    kWaitingToOpen,
+
+    // After calling `Open()`, but before `DidReceiveResponse()` or `DidFail()`.
+    kOpening,
+
+    // After `DidReceiveResponse()`, but before `DidFinishLoading()` or
+    // `DidFail()`. Zero or more calls allowed to `DidReceiveData()`.
+    kStreamingData,
+
+    // After `DidFinishLoading()` or `DidFail()`, or forced by `Close()`.
+    // Details about how the load completed are in `complete_result_`.
+    kLoadComplete,
+  };
+
+  // Aborts the load with `result`. Runs callback if pending.
+  void AbortLoad(int32_t result);
+
+  // Runs callback for `ReadResponseBody()` if pending.
+  void RunReadCallback();
+
+  void SetLoadComplete(int32_t result);
+
   base::WeakPtr<Client> client_;
   bool grant_universal_access_ = false;
 
+  LoadingState state_ = LoadingState::kWaitingToOpen;
+  int32_t complete_result_ = 0;
+
   std::unique_ptr<blink::WebAssociatedURLLoader> blink_loader_;
+
+  ResultCallback open_callback_;
+
+  base::circular_deque<char> buffer_;
+  ResultCallback read_callback_;
+  base::span<char> client_buffer_;
 };
 
 // A Pepper URL loader.
diff --git a/pdf/ppapi_migration/url_loader_unittest.cc b/pdf/ppapi_migration/url_loader_unittest.cc
index e55deea..21b2a53 100644
--- a/pdf/ppapi_migration/url_loader_unittest.cc
+++ b/pdf/ppapi_migration/url_loader_unittest.cc
@@ -9,6 +9,7 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/containers/span.h"
 #include "base/memory/weak_ptr.h"
 #include "base/single_thread_task_runner.h"
 #include "base/test/mock_callback.h"
@@ -16,19 +17,28 @@
 #include "ppapi/c/pp_errors.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
+#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/public/platform/web_url.h"
 #include "third_party/blink/public/platform/web_url_request.h"
+#include "third_party/blink/public/platform/web_url_response.h"
 #include "third_party/blink/public/web/web_associated_url_loader.h"
 #include "third_party/blink/public/web/web_associated_url_loader_client.h"
 #include "third_party/blink/public/web/web_associated_url_loader_options.h"
+#include "url/gurl.h"
 
 namespace chrome_pdf {
 namespace {
 
 using ::testing::_;
+using ::testing::Each;
+using ::testing::ElementsAreArray;
 using ::testing::Invoke;
 using ::testing::NiceMock;
 using ::testing::ReturnNull;
 
+constexpr base::span<const char> kFakeData = "fake data";
+
 class MockWebAssociatedURLLoader : public blink::WebAssociatedURLLoader {
  public:
   // blink::WebAssociatedURLLoader:
@@ -69,6 +79,9 @@
     ON_CALL(mock_client_, CreateAssociatedURLLoader(_))
         .WillByDefault(
             Invoke(this, &BlinkUrlLoaderTest::FakeCreateAssociatedURLLoader));
+    ON_CALL(*mock_url_loader_, LoadAsynchronously(_, _))
+        .WillByDefault(
+            Invoke(this, &BlinkUrlLoaderTest::FakeLoadAsynchronously));
     loader_ = std::make_unique<BlinkUrlLoader>(mock_client_.GetWeakPtr());
   }
 
@@ -79,13 +92,20 @@
     return std::move(mock_url_loader_);
   }
 
+  void FakeLoadAsynchronously(const blink::WebURLRequest& request,
+                              blink::WebAssociatedURLLoaderClient* client) {
+    saved_request_.CopyFrom(request);
+    EXPECT_EQ(loader_.get(), client);
+  }
+
   NiceMock<MockBlinkUrlLoaderClient> mock_client_;
-  base::MockCallback<ResultCallback> mock_callback_;
+  NiceMock<base::MockCallback<ResultCallback>> mock_callback_;
   std::unique_ptr<BlinkUrlLoader> loader_;
 
-  std::unique_ptr<MockWebAssociatedURLLoader> mock_url_loader_ =
-      std::make_unique<MockWebAssociatedURLLoader>();
+  std::unique_ptr<NiceMock<MockWebAssociatedURLLoader>> mock_url_loader_ =
+      std::make_unique<NiceMock<MockWebAssociatedURLLoader>>();
   blink::WebAssociatedURLLoaderOptions saved_options_;
+  blink::WebURLRequest saved_request_;
 };
 
 TEST_F(BlinkUrlLoaderTest, GrantUniversalAccess) {
@@ -96,14 +116,26 @@
 
 TEST_F(BlinkUrlLoaderTest, Open) {
   EXPECT_CALL(mock_client_, CreateAssociatedURLLoader(_));
+  EXPECT_CALL(*mock_url_loader_, LoadAsynchronously(_, _));
   EXPECT_CALL(mock_callback_, Run(_)).Times(0);
 
-  loader_->Open(UrlRequest(), mock_callback_.Get());
+  UrlRequest request;
+  request.url = "http://example.com/fake.pdf";
+  request.method = "FAKE";
+  loader_->Open(request, mock_callback_.Get());
+
   EXPECT_FALSE(saved_options_.grant_universal_access);
+  EXPECT_EQ(GURL("http://example.com/fake.pdf"), GURL(saved_request_.Url()));
+  EXPECT_EQ("FAKE", saved_request_.HttpMethod().Ascii());
+  EXPECT_EQ(blink::mojom::RequestContextType::PLUGIN,
+            saved_request_.GetRequestContext());
+  EXPECT_EQ(network::mojom::RequestDestination::kEmbed,
+            saved_request_.GetRequestDestination());
 }
 
 TEST_F(BlinkUrlLoaderTest, OpenWithInvalidatedClient) {
   EXPECT_CALL(mock_client_, CreateAssociatedURLLoader(_)).Times(0);
+  EXPECT_CALL(*mock_url_loader_, LoadAsynchronously(_, _)).Times(0);
   EXPECT_CALL(mock_callback_, Run(PP_ERROR_FAILED));
 
   mock_client_.InvalidateWeakPtrs();
@@ -113,10 +145,230 @@
 TEST_F(BlinkUrlLoaderTest, OpenWithFailingCreateAssociatedURLLoader) {
   EXPECT_CALL(mock_client_, CreateAssociatedURLLoader(_))
       .WillOnce(ReturnNull());
+  EXPECT_CALL(*mock_url_loader_, LoadAsynchronously(_, _)).Times(0);
   EXPECT_CALL(mock_callback_, Run(PP_ERROR_FAILED));
 
   loader_->Open(UrlRequest(), mock_callback_.Get());
 }
 
+TEST_F(BlinkUrlLoaderTest, DidReceiveResponse) {
+  loader_->Open(UrlRequest(), mock_callback_.Get());
+  EXPECT_CALL(mock_callback_, Run(PP_OK));
+
+  blink::WebURLResponse response;
+  response.SetHttpStatusCode(204);
+  loader_->DidReceiveResponse(response);
+
+  EXPECT_EQ(204, loader_->response().status_code);
+}
+
+TEST_F(BlinkUrlLoaderTest, DidReceiveData) {
+  char buffer[kFakeData.size()] = {};
+  loader_->Open(UrlRequest(), mock_callback_.Get());
+  loader_->DidReceiveResponse(blink::WebURLResponse());
+  loader_->ReadResponseBody(buffer, mock_callback_.Get());
+  EXPECT_CALL(mock_callback_, Run(kFakeData.size()));
+
+  loader_->DidReceiveData(kFakeData.data(), kFakeData.size());
+
+  EXPECT_THAT(buffer, ElementsAreArray(kFakeData));
+}
+
+TEST_F(BlinkUrlLoaderTest, DidReceiveDataWithZeroLength) {
+  char buffer[kFakeData.size()] = {};
+  loader_->Open(UrlRequest(), mock_callback_.Get());
+  loader_->DidReceiveResponse(blink::WebURLResponse());
+  loader_->ReadResponseBody(buffer, mock_callback_.Get());
+  EXPECT_CALL(mock_callback_, Run(_)).Times(0);
+
+  loader_->DidReceiveData(kFakeData.data(), 0);
+
+  EXPECT_THAT(buffer, Each(0));
+}
+
+TEST_F(BlinkUrlLoaderTest, ReadResponseBody) {
+  loader_->Open(UrlRequest(), mock_callback_.Get());
+  loader_->DidReceiveResponse(blink::WebURLResponse());
+  loader_->DidReceiveData(kFakeData.data(), kFakeData.size());
+  EXPECT_CALL(mock_callback_, Run(kFakeData.size()));
+
+  char buffer[kFakeData.size()] = {};
+  loader_->ReadResponseBody(buffer, mock_callback_.Get());
+
+  EXPECT_THAT(buffer, ElementsAreArray(kFakeData));
+
+  // Verify no more data returned on next call.
+  EXPECT_CALL(mock_callback_, Run(_)).Times(0);
+  loader_->ReadResponseBody(buffer, mock_callback_.Get());
+}
+
+TEST_F(BlinkUrlLoaderTest, ReadResponseBodyWithoutData) {
+  loader_->Open(UrlRequest(), mock_callback_.Get());
+  loader_->DidReceiveResponse(blink::WebURLResponse());
+  EXPECT_CALL(mock_callback_, Run(_)).Times(0);
+
+  char buffer[kFakeData.size()] = {};
+  loader_->ReadResponseBody(buffer, mock_callback_.Get());
+
+  EXPECT_THAT(buffer, Each(0));
+}
+
+TEST_F(BlinkUrlLoaderTest, ReadResponseBodyWithEmptyBuffer) {
+  loader_->Open(UrlRequest(), mock_callback_.Get());
+  loader_->DidReceiveResponse(blink::WebURLResponse());
+  EXPECT_CALL(mock_callback_, Run(PP_ERROR_BADARGUMENT));
+
+  loader_->ReadResponseBody(base::span<char>(), mock_callback_.Get());
+}
+
+TEST_F(BlinkUrlLoaderTest, ReadResponseBodyWithSmallerBuffer) {
+  static constexpr size_t kTailSize = 1;
+  static constexpr size_t kBufferSize = kFakeData.size() - kTailSize;
+
+  loader_->Open(UrlRequest(), mock_callback_.Get());
+  loader_->DidReceiveResponse(blink::WebURLResponse());
+  loader_->DidReceiveData(kFakeData.data(), kFakeData.size());
+  EXPECT_CALL(mock_callback_, Run(kBufferSize));
+
+  char buffer[kBufferSize] = {};
+  loader_->ReadResponseBody(buffer, mock_callback_.Get());
+
+  EXPECT_THAT(buffer, ElementsAreArray(kFakeData.first(kBufferSize)));
+
+  // Verify remaining data returned on next call.
+  char tail_buffer[kTailSize];
+  EXPECT_CALL(mock_callback_, Run(kTailSize));
+  loader_->ReadResponseBody(tail_buffer, mock_callback_.Get());
+  EXPECT_THAT(tail_buffer, ElementsAreArray(kFakeData.subspan(kBufferSize)));
+}
+
+TEST_F(BlinkUrlLoaderTest, ReadResponseBodyWithBiggerBuffer) {
+  loader_->Open(UrlRequest(), mock_callback_.Get());
+  loader_->DidReceiveResponse(blink::WebURLResponse());
+  loader_->DidReceiveData(kFakeData.data(), kFakeData.size());
+  EXPECT_CALL(mock_callback_, Run(kFakeData.size()));
+
+  char buffer[kFakeData.size() + 1] = {};
+  loader_->ReadResponseBody(buffer, mock_callback_.Get());
+
+  base::span<char> buffer_span = buffer;
+  EXPECT_THAT(buffer_span.first(kFakeData.size()), ElementsAreArray(kFakeData));
+  EXPECT_THAT(buffer_span.subspan(kFakeData.size()), Each(0));
+
+  // Verify no more data returned on next call.
+  EXPECT_CALL(mock_callback_, Run(_)).Times(0);
+  loader_->ReadResponseBody(buffer, mock_callback_.Get());
+}
+
+TEST_F(BlinkUrlLoaderTest, ReadResponseBodyWhileLoadComplete) {
+  loader_->Open(UrlRequest(), mock_callback_.Get());
+  loader_->DidReceiveResponse(blink::WebURLResponse());
+  loader_->DidReceiveData(kFakeData.data(), kFakeData.size());
+  loader_->DidFinishLoading();
+  EXPECT_CALL(mock_callback_, Run(kFakeData.size()));
+
+  char buffer[kFakeData.size()] = {};
+  loader_->ReadResponseBody(buffer, mock_callback_.Get());
+
+  EXPECT_THAT(buffer, ElementsAreArray(kFakeData));
+
+  // Verify no more data returned on next call.
+  char tail_buffer[kFakeData.size()] = {};
+  EXPECT_CALL(mock_callback_, Run(0));
+  loader_->ReadResponseBody(tail_buffer, mock_callback_.Get());
+  EXPECT_THAT(tail_buffer, Each(0));
+}
+
+TEST_F(BlinkUrlLoaderTest, ReadResponseBodyWhileLoadCompleteWithoutData) {
+  loader_->Open(UrlRequest(), mock_callback_.Get());
+  loader_->DidReceiveResponse(blink::WebURLResponse());
+  loader_->DidFinishLoading();
+  EXPECT_CALL(mock_callback_, Run(0));
+
+  char buffer[kFakeData.size()] = {};
+  loader_->ReadResponseBody(buffer, mock_callback_.Get());
+
+  EXPECT_THAT(buffer, Each(0));
+}
+
+TEST_F(BlinkUrlLoaderTest, ReadResponseBodyWhileLoadCompleteWithError) {
+  loader_->Open(UrlRequest(), mock_callback_.Get());
+  loader_->DidReceiveResponse(blink::WebURLResponse());
+  loader_->DidReceiveData(kFakeData.data(), kFakeData.size());
+  loader_->Close();
+  EXPECT_CALL(mock_callback_, Run(PP_ERROR_ABORTED));
+
+  char buffer[kFakeData.size()] = {};
+  loader_->ReadResponseBody(buffer, mock_callback_.Get());
+
+  EXPECT_THAT(buffer, Each(0));
+}
+
+TEST_F(BlinkUrlLoaderTest, DidFinishLoading) {
+  loader_->Open(UrlRequest(), mock_callback_.Get());
+  loader_->DidReceiveResponse(blink::WebURLResponse());
+  EXPECT_CALL(mock_callback_, Run(_)).Times(0);
+
+  loader_->DidFinishLoading();
+}
+
+TEST_F(BlinkUrlLoaderTest, DidFinishLoadingWithPendingCallback) {
+  char buffer[1];
+  loader_->Open(UrlRequest(), mock_callback_.Get());
+  loader_->DidReceiveResponse(blink::WebURLResponse());
+  loader_->ReadResponseBody(buffer, mock_callback_.Get());
+  EXPECT_CALL(mock_callback_, Run(0));  // Result represents read bytes.
+
+  loader_->DidFinishLoading();
+}
+
+TEST_F(BlinkUrlLoaderTest, CloseWhileWaitingToOpen) {
+  EXPECT_CALL(mock_callback_, Run(_)).Times(0);
+
+  loader_->Close();
+}
+
+TEST_F(BlinkUrlLoaderTest, CloseWhileOpening) {
+  loader_->Open(UrlRequest(), mock_callback_.Get());
+  EXPECT_CALL(mock_callback_, Run(PP_ERROR_ABORTED));
+
+  loader_->Close();
+}
+
+TEST_F(BlinkUrlLoaderTest, CloseWhileStreamingData) {
+  loader_->Open(UrlRequest(), mock_callback_.Get());
+  loader_->DidReceiveResponse(blink::WebURLResponse());
+  EXPECT_CALL(mock_callback_, Run(_)).Times(0);
+
+  loader_->Close();
+}
+
+TEST_F(BlinkUrlLoaderTest, CloseWhileStreamingDataWithPendingCallback) {
+  char buffer[1];
+  loader_->Open(UrlRequest(), mock_callback_.Get());
+  loader_->DidReceiveResponse(blink::WebURLResponse());
+  loader_->ReadResponseBody(buffer, mock_callback_.Get());
+  EXPECT_CALL(mock_callback_, Run(PP_ERROR_ABORTED));
+
+  loader_->Close();
+}
+
+TEST_F(BlinkUrlLoaderTest, CloseWhileLoadComplete) {
+  loader_->Open(UrlRequest(), mock_callback_.Get());
+  loader_->DidReceiveResponse(blink::WebURLResponse());
+  loader_->DidFinishLoading();
+  EXPECT_CALL(mock_callback_, Run(_)).Times(0);
+
+  loader_->Close();
+}
+
+TEST_F(BlinkUrlLoaderTest, CloseAgain) {
+  loader_->Open(UrlRequest(), mock_callback_.Get());
+  loader_->Close();
+  EXPECT_CALL(mock_callback_, Run(_)).Times(0);
+
+  loader_->Close();
+}
+
 }  // namespace
 }  // namespace chrome_pdf
diff --git a/printing/page_number.cc b/printing/page_number.cc
index 14c02c4..ff3f361 100644
--- a/printing/page_number.cc
+++ b/printing/page_number.cc
@@ -13,14 +13,15 @@
 
 namespace printing {
 
-PageNumber::PageNumber(const PrintSettings& settings, int document_page_count) {
+PageNumber::PageNumber(const PrintSettings& settings,
+                       uint32_t document_page_count) {
   Init(settings, document_page_count);
 }
 
 PageNumber::PageNumber()
     : ranges_(nullptr),
-      page_number_(-1),
-      page_range_index_(-1),
+      page_number_(kInvalidPageIndex),
+      page_range_index_(kInvalidPageIndex),
       document_page_count_(0) {}
 
 void PageNumber::operator=(const PageNumber& other) {
@@ -30,7 +31,8 @@
   document_page_count_ = other.document_page_count_;
 }
 
-void PageNumber::Init(const PrintSettings& settings, int document_page_count) {
+void PageNumber::Init(const PrintSettings& settings,
+                      uint32_t document_page_count) {
   DCHECK(document_page_count);
   ranges_ = settings.ranges().empty() ? NULL : &settings.ranges();
   document_page_count_ = document_page_count;
@@ -41,16 +43,16 @@
     if (document_page_count) {
       page_number_ = 0;
     } else {
-      page_number_ = -1;
+      page_number_ = kInvalidPageIndex;
     }
-    page_range_index_ = -1;
+    page_range_index_ = kInvalidPageIndex;
   }
 }
 
 int PageNumber::operator++() {
   if (!ranges_) {
     // Switch to next page.
-    if (++page_number_ == document_page_count_) {
+    if (++page_number_ >= document_page_count_) {
       // Finished.
       *this = npos();
     }
@@ -61,7 +63,7 @@
     if (page_number_ > (*ranges_)[page_range_index_].to) {
       DCHECK(ranges_->size() <=
              static_cast<size_t>(std::numeric_limits<int>::max()));
-      if (++page_range_index_ == static_cast<int>(ranges_->size())) {
+      if (++page_range_index_ == ranges_->size()) {
         // Finished.
         *this = npos();
       } else {
@@ -69,7 +71,7 @@
       }
     }
   }
-  return ToInt();
+  return ToUint();
 }
 
 bool PageNumber::operator==(const PageNumber& other) const {
diff --git a/printing/page_number.h b/printing/page_number.h
index 9f566ae..d8e0453 100644
--- a/printing/page_number.h
+++ b/printing/page_number.h
@@ -18,7 +18,7 @@
 class PRINTING_EXPORT PageNumber {
  public:
   // Initializes the page to the first page in the settings's range or 0.
-  PageNumber(const PrintSettings& settings, int document_page_count);
+  PageNumber(const PrintSettings& settings, uint32_t document_page_count);
 
   PageNumber();
 
@@ -26,10 +26,10 @@
 
   // Initializes the page to the first page in the setting's range or 0. It
   // initialize to npos if the range is empty and document_page_count is 0.
-  void Init(const PrintSettings& settings, int document_page_count);
+  void Init(const PrintSettings& settings, uint32_t document_page_count);
 
   // Converts to a page numbers.
-  int ToInt() const { return page_number_; }
+  uint32_t ToUint() const { return page_number_; }
 
   // Calculates the next page in the serie.
   int operator++();
@@ -46,15 +46,15 @@
   // The page range to follow.
   const PageRanges* ranges_;
 
-  // The next page to be printed. -1 when not printing.
-  int page_number_;
+  // The next page to be printed. |kInvalidPageIndex| when not printing.
+  uint32_t page_number_;
 
-  // The next page to be printed. -1 when not used. Valid only if
-  // document()->settings().range.empty() is false.
-  int page_range_index_;
+  // The next page to be printed. |kInvalidPageIndex| when not used. Valid only
+  // if document()->settings().range.empty() is false.
+  uint32_t page_range_index_;
 
   // Number of expected pages in the document. Used when ranges_ is NULL.
-  int document_page_count_;
+  uint32_t document_page_count_;
 };
 
 // Debug output support.
@@ -62,7 +62,7 @@
 inline typename std::basic_ostream<E, T>& operator<<(
     typename std::basic_ostream<E, T>& ss,
     const PageNumber& page) {
-  return ss << page.ToInt();
+  return ss << page.ToUint();
 }
 
 }  // namespace printing
diff --git a/printing/page_number_unittest.cc b/printing/page_number_unittest.cc
index ece1e0f6..6cd3450 100644
--- a/printing/page_number_unittest.cc
+++ b/printing/page_number_unittest.cc
@@ -11,18 +11,18 @@
   printing::PageNumber page;
   EXPECT_EQ(printing::PageNumber::npos(), page);
   page.Init(settings, 3);
-  EXPECT_EQ(0, page.ToInt());
+  EXPECT_EQ(0u, page.ToUint());
   EXPECT_NE(printing::PageNumber::npos(), page);
   ++page;
-  EXPECT_EQ(1, page.ToInt());
+  EXPECT_EQ(1u, page.ToUint());
   EXPECT_NE(printing::PageNumber::npos(), page);
 
   printing::PageNumber page_copy(page);
-  EXPECT_EQ(1, page_copy.ToInt());
-  EXPECT_EQ(1, page.ToInt());
+  EXPECT_EQ(1u, page_copy.ToUint());
+  EXPECT_EQ(1u, page.ToUint());
   ++page;
-  EXPECT_EQ(1, page_copy.ToInt());
-  EXPECT_EQ(2, page.ToInt());
+  EXPECT_EQ(1u, page_copy.ToUint());
+  EXPECT_EQ(2u, page.ToUint());
   ++page;
   EXPECT_EQ(printing::PageNumber::npos(), page);
   ++page;
diff --git a/printing/page_range.cc b/printing/page_range.cc
index 22aea0f..ee015d93 100644
--- a/printing/page_range.cc
+++ b/printing/page_range.cc
@@ -11,19 +11,19 @@
 namespace printing {
 
 // static
-std::vector<int> PageRange::GetPages(const PageRanges& ranges) {
+std::vector<uint32_t> PageRange::GetPages(const PageRanges& ranges) {
   // TODO(vitalybuka): crbug.com/95548 Remove this method as part fix.
-  std::set<int> pages;
+  std::set<uint32_t> pages;
   for (const PageRange& range : ranges) {
     // Ranges are inclusive.
-    for (int i = range.from; i <= range.to; ++i) {
+    for (uint32_t i = range.from; i <= range.to; ++i) {
       static constexpr size_t kMaxNumberOfPages = 100000;
       pages.insert(i);
       if (pages.size() >= kMaxNumberOfPages)
-        return std::vector<int>(pages.begin(), pages.end());
+        return std::vector<uint32_t>(pages.begin(), pages.end());
     }
   }
-  return std::vector<int>(pages.begin(), pages.end());
+  return std::vector<uint32_t>(pages.begin(), pages.end());
 }
 
 }  // namespace printing
diff --git a/printing/page_range.h b/printing/page_range.h
index f432604..0d262a6 100644
--- a/printing/page_range.h
+++ b/printing/page_range.h
@@ -17,15 +17,15 @@
 
 // Print range is inclusive. To select one page, set from == to.
 struct PRINTING_EXPORT PageRange {
-  int from;
-  int to;
+  uint32_t from;
+  uint32_t to;
 
   bool operator==(const PageRange& rhs) const {
     return from == rhs.from && to == rhs.to;
   }
 
   // Retrieves the sorted list of unique pages in the page ranges.
-  static std::vector<int> GetPages(const PageRanges& ranges);
+  static std::vector<uint32_t> GetPages(const PageRanges& ranges);
 };
 
 }  // namespace printing
diff --git a/printing/page_range_unittest.cc b/printing/page_range_unittest.cc
index 5370e971..88fee12 100644
--- a/printing/page_range_unittest.cc
+++ b/printing/page_range_unittest.cc
@@ -17,21 +17,21 @@
   range.from = 2;
   range.to = 5;
   ranges.push_back(range);
-  std::vector<int> pages(printing::PageRange::GetPages(ranges));
+  std::vector<uint32_t> pages(printing::PageRange::GetPages(ranges));
   ASSERT_EQ(8U, pages.size());
-  EXPECT_EQ(1, pages[0]);
-  EXPECT_EQ(2, pages[1]);
-  EXPECT_EQ(3, pages[2]);
-  EXPECT_EQ(4, pages[3]);
-  EXPECT_EQ(5, pages[4]);
-  EXPECT_EQ(10, pages[5]);
-  EXPECT_EQ(11, pages[6]);
-  EXPECT_EQ(12, pages[7]);
+  EXPECT_EQ(1u, pages[0]);
+  EXPECT_EQ(2u, pages[1]);
+  EXPECT_EQ(3u, pages[2]);
+  EXPECT_EQ(4u, pages[3]);
+  EXPECT_EQ(5u, pages[4]);
+  EXPECT_EQ(10u, pages[5]);
+  EXPECT_EQ(11u, pages[6]);
+  EXPECT_EQ(12u, pages[7]);
 }
 
 TEST(PageRangeTest, Empty) {
   printing::PageRanges ranges;
-  std::vector<int> pages(printing::PageRange::GetPages(ranges));
+  std::vector<uint32_t> pages(printing::PageRange::GetPages(ranges));
   EXPECT_TRUE(pages.empty());
 }
 
@@ -41,6 +41,6 @@
   range.from = 1;
   range.to = 2000000000;
   ranges.push_back(range);
-  std::vector<int> pages(printing::PageRange::GetPages(ranges));
+  std::vector<uint32_t> pages(printing::PageRange::GetPages(ranges));
   EXPECT_FALSE(pages.empty());
 }
diff --git a/printing/print_job_constants.cc b/printing/print_job_constants.cc
index 04c91fa..8a41b26 100644
--- a/printing/print_job_constants.cc
+++ b/printing/print_job_constants.cc
@@ -4,6 +4,8 @@
 
 #include "printing/print_job_constants.h"
 
+#include <limits>
+
 namespace printing {
 
 // True if this is the first preview request.
@@ -209,6 +211,9 @@
 // Whether to show PDF in view provided by OS. Implemented for MacOS only.
 const char kSettingOpenPDFInPreview[] = "OpenPDFInPreview";
 
+const uint32_t kInvalidPageIndex = std::numeric_limits<int>::max();
+const uint32_t kMaxPageCount = std::numeric_limits<int>::max();
+
 #if defined(USE_CUPS)
 const char kBlack[] = "Black";
 const char kCMYK[] = "CMYK";
diff --git a/printing/print_job_constants.h b/printing/print_job_constants.h
index 6945af9..03d7f70 100644
--- a/printing/print_job_constants.h
+++ b/printing/print_job_constants.h
@@ -5,6 +5,8 @@
 #ifndef PRINTING_PRINT_JOB_CONSTANTS_H_
 #define PRINTING_PRINT_JOB_CONSTANTS_H_
 
+#include <stdint.h>
+
 #include "printing/printing_export.h"
 
 namespace printing {
@@ -80,6 +82,9 @@
 PRINTING_EXPORT extern const int COMPLETE_PREVIEW_DOCUMENT_INDEX;
 PRINTING_EXPORT extern const char kSettingOpenPDFInPreview[];
 
+PRINTING_EXPORT extern const uint32_t kInvalidPageIndex;
+PRINTING_EXPORT extern const uint32_t kMaxPageCount;
+
 #if defined(USE_CUPS)
 // Printer color models
 PRINTING_EXPORT extern const char kBlack[];
diff --git a/printing/printed_document.cc b/printing/printed_document.cc
index bf5f49a..5ed3e08 100644
--- a/printing/printed_document.cc
+++ b/printing/printed_document.cc
@@ -126,7 +126,7 @@
   mutable_.converting_pdf_ = true;
 }
 
-void PrintedDocument::SetPage(int page_number,
+void PrintedDocument::SetPage(uint32_t page_number,
                               std::unique_ptr<MetafilePlayer> metafile,
                               float shrink,
                               const gfx::Size& page_size,
@@ -148,7 +148,7 @@
   }
 }
 
-scoped_refptr<PrintedPage> PrintedDocument::GetPage(int page_number) {
+scoped_refptr<PrintedPage> PrintedDocument::GetPage(uint32_t page_number) {
   scoped_refptr<PrintedPage> page;
   {
     base::AutoLock lock(lock_);
@@ -198,7 +198,7 @@
     return false;
 
   for (; page != PageNumber::npos(); ++page) {
-    PrintedPages::const_iterator it = mutable_.pages_.find(page.ToInt());
+    PrintedPages::const_iterator it = mutable_.pages_.find(page.ToUint());
     if (it == mutable_.pages_.end() || !it->second.get() ||
         !it->second->metafile()) {
       return false;
@@ -210,25 +210,25 @@
 #endif
 }
 
-void PrintedDocument::set_page_count(int max_page) {
+void PrintedDocument::set_page_count(uint32_t max_page) {
   base::AutoLock lock(lock_);
-  DCHECK_EQ(0, mutable_.page_count_);
+  DCHECK_EQ(0u, mutable_.page_count_);
   mutable_.page_count_ = max_page;
   if (immutable_.settings_->ranges().empty()) {
     mutable_.expected_page_count_ = max_page;
   } else {
     // If there is a range, don't bother since expected_page_count_ is already
     // initialized.
-    DCHECK_NE(mutable_.expected_page_count_, 0);
+    DCHECK_NE(mutable_.expected_page_count_, 0u);
   }
 }
 
-int PrintedDocument::page_count() const {
+uint32_t PrintedDocument::page_count() const {
   base::AutoLock lock(lock_);
   return mutable_.page_count_;
 }
 
-int PrintedDocument::expected_page_count() const {
+uint32_t PrintedDocument::expected_page_count() const {
   base::AutoLock lock(lock_);
   return mutable_.expected_page_count_;
 }
diff --git a/printing/printed_document.h b/printing/printed_document.h
index 20e3e876..7a2d1ad 100644
--- a/printing/printed_document.h
+++ b/printing/printed_document.h
@@ -51,7 +51,7 @@
   void SetConvertingPdf();
 
   // Sets a page's data. 0-based. Note: locks for a short amount of time.
-  void SetPage(int page_number,
+  void SetPage(uint32_t page_number,
                std::unique_ptr<MetafilePlayer> metafile,
                float shrink,
                const gfx::Size& page_size,
@@ -60,7 +60,7 @@
   // Retrieves a page. If the page is not available right now, it
   // requests to have this page be rendered and returns NULL.
   // Note: locks for a short amount of time.
-  scoped_refptr<PrintedPage> GetPage(int page_number);
+  scoped_refptr<PrintedPage> GetPage(uint32_t page_number);
 
   // Drop the specified page's reference for the particular page number.
   // Note: locks for a short amount of time.
@@ -94,17 +94,17 @@
   // Sets the number of pages in the document to be rendered. Can only be set
   // once.
   // Note: locks for a short amount of time.
-  void set_page_count(int max_page);
+  void set_page_count(uint32_t max_page);
 
   // Number of pages in the document.
   // Note: locks for a short amount of time.
-  int page_count() const;
+  uint32_t page_count() const;
 
   // Returns the number of expected pages to be rendered. It is a non-linear
   // series if settings().ranges is not empty. It is the same value as
   // document_page_count() otherwise.
   // Note: locks for a short amount of time.
-  int expected_page_count() const;
+  uint32_t expected_page_count() const;
 
   // Getters. All these items are immutable hence thread-safe.
   const PrintSettings& settings() const { return *immutable_.settings_; }
@@ -144,7 +144,7 @@
   ~PrintedDocument();
 
   // Array of data for each print previewed page.
-  using PrintedPages = std::map<int, scoped_refptr<PrintedPage>>;
+  using PrintedPages = std::map<uint32_t, scoped_refptr<PrintedPage>>;
 
   // Contains all the mutable stuff. All this stuff MUST be accessed with the
   // lock held.
@@ -154,10 +154,10 @@
 
     // Number of expected pages to be rendered.
     // Warning: Lock must be held when accessing this member.
-    int expected_page_count_ = 0;
+    uint32_t expected_page_count_ = 0;
 
     // The total number of pages in the document.
-    int page_count_ = 0;
+    uint32_t page_count_ = 0;
 
     std::unique_ptr<MetafilePlayer> metafile_;
 
diff --git a/printing/printed_page_win.cc b/printing/printed_page_win.cc
index b9df411..129d589 100644
--- a/printing/printed_page_win.cc
+++ b/printing/printed_page_win.cc
@@ -8,7 +8,7 @@
 
 namespace printing {
 
-PrintedPage::PrintedPage(int page_number,
+PrintedPage::PrintedPage(uint32_t page_number,
                          std::unique_ptr<MetafilePlayer> metafile,
                          const gfx::Size& page_size,
                          const gfx::Rect& page_content_rect)
diff --git a/printing/printed_page_win.h b/printing/printed_page_win.h
index ae917dd..37d1dd75 100644
--- a/printing/printed_page_win.h
+++ b/printing/printed_page_win.h
@@ -23,7 +23,7 @@
 class PRINTING_EXPORT PrintedPage
     : public base::RefCountedThreadSafe<PrintedPage> {
  public:
-  PrintedPage(int page_number,
+  PrintedPage(uint32_t page_number,
               std::unique_ptr<MetafilePlayer> metafile,
               const gfx::Size& page_size,
               const gfx::Rect& page_content_rect);
@@ -31,7 +31,7 @@
   PrintedPage& operator=(const PrintedPage&) = delete;
 
   // Getters
-  int page_number() const { return page_number_; }
+  uint32_t page_number() const { return page_number_; }
   const MetafilePlayer* metafile() const;
   const gfx::Size& page_size() const { return page_size_; }
   const gfx::Rect& page_content_rect() const { return page_content_rect_; }
@@ -46,7 +46,7 @@
   ~PrintedPage();
 
   // Page number inside the printed document.
-  const int page_number_;
+  const uint32_t page_number_;
 
   // Actual paint data.
   const std::unique_ptr<MetafilePlayer> metafile_;
diff --git a/printing/printing_features.cc b/printing/printing_features.cc
index 058e60b..cc7d82e7 100644
--- a/printing/printing_features.cc
+++ b/printing/printing_features.cc
@@ -47,5 +47,14 @@
 }
 #endif  // defined(OS_WIN)
 
+#if defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) || \
+    defined(OS_CHROMEOS)
+// Enables printing interactions with the operating system to be performed
+// out-of-process.
+const base::Feature kEnableOopPrintDrivers{"EnableOopPrintDrivers",
+                                           base::FEATURE_DISABLED_BY_DEFAULT};
+#endif  // defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) ||
+        // defined(OS_CHROMEOS)
+
 }  // namespace features
 }  // namespace printing
diff --git a/printing/printing_features.h b/printing/printing_features.h
index 3c6e97b..4f4f598 100644
--- a/printing/printing_features.h
+++ b/printing/printing_features.h
@@ -37,6 +37,12 @@
 PRINTING_EXPORT bool ShouldPrintUsingXps(bool source_is_pdf);
 #endif  // defined(OS_WIN)
 
+#if defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) || \
+    defined(OS_CHROMEOS)
+PRINTING_EXPORT extern const base::Feature kEnableOopPrintDrivers;
+#endif  // defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) ||
+        // defined(OS_CHROMEOS)
+
 }  // namespace features
 }  // namespace printing
 
diff --git a/storage/browser/quota/quota_manager.cc b/storage/browser/quota/quota_manager.cc
index 90f73d8..4bb643b 100644
--- a/storage/browser/quota/quota_manager.cc
+++ b/storage/browser/quota/quota_manager.cc
@@ -53,7 +53,7 @@
 
 // Take action on write errors if there is <= 2% disk space
 // available.
-constexpr double kStoragePressureThresholdRatio = 2;
+constexpr double kStoragePressureThresholdPercent = 2;
 
 // Limit how frequently QuotaManager polls for free disk space when
 // only using that information to identify storage pressure.
@@ -1486,7 +1486,8 @@
     origin_for_pending_storage_pressure_callback_ = std::move(origin);
     return;
   }
-  if (100 * (available_space / total_space) < kStoragePressureThresholdRatio) {
+
+  if (100 * available_space < kStoragePressureThresholdPercent * total_space) {
     storage_pressure_callback_.Run(std::move(origin));
   }
 }
diff --git a/storage/browser/quota/quota_manager_unittest.cc b/storage/browser/quota/quota_manager_unittest.cc
index b361d81..9837c45 100644
--- a/storage/browser/quota/quota_manager_unittest.cc
+++ b/storage/browser/quota/quota_manager_unittest.cc
@@ -420,6 +420,17 @@
 
   void GetUsage_WithModifyTestBody(const StorageType type);
 
+  void SetStoragePressureCallback(
+      base::RepeatingCallback<void(url::Origin)> callback) {
+    quota_manager_->SetStoragePressureCallback(std::move(callback));
+  }
+
+  void MaybeRunStoragePressureCallback(const url::Origin& origin,
+                                       int64_t total,
+                                       int64_t available) {
+    quota_manager_->MaybeRunStoragePressureCallback(origin, total, available);
+  }
+
   void set_additional_callback_count(int c) { additional_callback_count_ = c; }
   int additional_callback_count() const { return additional_callback_count_; }
   void DidGetUsageAndQuotaAdditional(QuotaStatusCode status,
@@ -2670,4 +2681,22 @@
   EXPECT_EQ(0, quota());
 }
 
+TEST_F(QuotaManagerTest, MaybeRunStoragePressureCallback) {
+  bool callback_ran = false;
+  auto cb = base::BindRepeating(
+      [](bool* callback_ran, url::Origin origin) { *callback_ran = true; },
+      &callback_ran);
+
+  SetStoragePressureCallback(std::move(cb));
+
+  int64_t kGBytes = QuotaManager::kMBytes * 1024;
+  MaybeRunStoragePressureCallback(url::Origin(), 100 * kGBytes, 2 * kGBytes);
+  task_environment_.RunUntilIdle();
+  EXPECT_FALSE(callback_ran);
+
+  MaybeRunStoragePressureCallback(url::Origin(), 100 * kGBytes, kGBytes);
+  task_environment_.RunUntilIdle();
+  EXPECT_TRUE(callback_ran);
+}
+
 }  // namespace storage
diff --git a/testing/PRESUBMIT.py b/testing/PRESUBMIT.py
index 8a8f0d7..bce5429 100644
--- a/testing/PRESUBMIT.py
+++ b/testing/PRESUBMIT.py
@@ -11,11 +11,10 @@
 
 def CommonChecks(input_api, output_api):
   output = []
-  blacklist = [r'gmock.*', r'gtest.*']
   output.extend(input_api.canned_checks.RunUnitTestsInDirectory(
       input_api, output_api, '.', [r'^.+_unittest\.py$']))
   output.extend(input_api.canned_checks.RunPylint(
-      input_api, output_api, black_list=blacklist))
+      input_api, output_api, files_to_skip=[r'gmock.*', r'gtest.*']))
   return output
 
 
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 12328a57..b2b7444 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -3201,7 +3201,7 @@
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 13
+          "shards": 10
         },
         "test": "content_browsertests",
         "test_id_prefix": "ninja://content/test:content_browsertests/"
@@ -3251,7 +3251,7 @@
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 5
+          "shards": 8
         },
         "test": "content_browsertests",
         "test_id_prefix": "ninja://content/test:content_browsertests/"
diff --git a/testing/buildbot/chromium.ci.json b/testing/buildbot/chromium.ci.json
index 9a3a3e2..e089db4d 100644
--- a/testing/buildbot/chromium.ci.json
+++ b/testing/buildbot/chromium.ci.json
@@ -52309,7 +52309,7 @@
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 13
+          "shards": 10
         },
         "test": "content_browsertests",
         "test_id_prefix": "ninja://content/test:content_browsertests/"
@@ -52359,7 +52359,7 @@
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 5
+          "shards": 8
         },
         "test": "content_browsertests",
         "test_id_prefix": "ninja://content/test:content_browsertests/"
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 0b9b99b..070a41f 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -1442,7 +1442,6 @@
   'resource_sizes_lacros_chrome': {
     "label": "//chromeos/lacros:resource_sizes_lacros_chrome",
     "type": "generated_script",
-    "script": "bin/resource_sizes_lacros_chrome",
   },
   "resource_sizes_monochrome_public_minimal_apks": {
     "label": "//chrome/android:resource_sizes_monochrome_public_minimal_apks",
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index f1bfc30..069cc1e 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -913,7 +913,7 @@
       },
       'Lollipop Phone Tester': {
         'swarming': {
-          'shards': 13,
+          'shards': 10,
         },
       },
       'Win10 Tests x64': {
@@ -2004,6 +2004,11 @@
       'android-marshmallow-x86-rel', # crbug.com/1098111
     ],
     'modifications': {
+      'Lollipop Phone Tester': {
+        'swarming': {
+          'shards': 8,
+        },
+      },
       'android-marshmallow-x86-rel-non-cq': {
         'args': [
           '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_m.content_browsertests.filter',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 874334b..9811e846 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -3345,6 +3345,21 @@
             ]
         }
     ],
+    "IOSDefaultBrowserFullscreenPromo": [
+        {
+            "platforms": [
+                "ios"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "DefaultBrowserFullscreenPromo"
+                    ]
+                }
+            ]
+        }
+    ],
     "IOSDiscoverFeed": [
         {
             "platforms": [
diff --git a/third_party/blink/common/switches.cc b/third_party/blink/common/switches.cc
index 5723a90..74b28d08 100644
--- a/third_party/blink/common/switches.cc
+++ b/third_party/blink/common/switches.cc
@@ -12,6 +12,12 @@
 // involving a command line switch.
 const char kAllowPreCommitInput[] = "allow-pre-commit-input";
 
+// Set blink settings. Format is <name>[=<value],<name>[=<value>],...
+// The names are declared in Settings.json5. For boolean type, use "true",
+// "false", or omit '=<value>' part to set to true. For enum type, use the int
+// value of the enum value. Applied after other command line flags and prefs.
+const char kBlinkSettings[] = "blink-settings";
+
 // Sets the tile size used by composited layers.
 const char kDefaultTileWidth[] = "default-tile-width";
 const char kDefaultTileHeight[] = "default-tile-height";
@@ -36,6 +42,9 @@
 // Disables RGBA_4444 textures.
 const char kDisableRGBA4444Textures[] = "disable-rgba-4444-textures";
 
+// Disable multithreaded, compositor scrolling of web content.
+const char kDisableThreadedScrolling[] = "disable-threaded-scrolling";
+
 // Disable rasterizer that writes directly to GPU memory associated with tiles.
 const char kDisableZeroCopy[] = "disable-zero-copy";
 
@@ -86,6 +95,20 @@
 // Sets the min tile height for GPU raster.
 const char kMinHeightForGpuRasterTile[] = "min-height-for-gpu-raster-tile";
 
+// Sets the timeout seconds of the network-quiet timers in IdlenessDetector.
+// Used by embedders who want to change the timeout time in order to run web
+// contents on various embedded devices and changeable network bandwidths in
+// different regions. For example, it's useful when using FirstMeaningfulPaint
+// signal to dismiss a splash screen.
+const char kNetworkQuietTimeout[] = "network-quiet-timeout";
+
+// Override the default value for the 'passive' field in javascript
+// addEventListener calls. Values are defined as:
+//  'documentonlytrue' to set the default be true only for document level nodes.
+//  'true' to set the default to be true on all nodes (when not specified).
+//  'forcealltrue' to force the value on all nodes.
+const char kPassiveListenersDefault[] = "passive-listeners-default";
+
 // Visibly render a border around layout shift rects in the web page to help
 // debug and study layout shifts.
 const char kShowLayoutShiftRegions[] = "show-layout-shift-regions";
@@ -94,6 +117,11 @@
 // and study painting behavior.
 const char kShowPaintRects[] = "show-paint-rects";
 
+// Controls how text selection granularity changes when touch text selection
+// handles are dragged. Should be "character" or "direction". If not specified,
+// the platform default is used.
+const char kTouchTextSelectionStrategy[] = "touch-selection-strategy";
+
 // Used to communicate managed policy for the UserAgentClientHint feature.
 // This feature is typically controlled by base::Feature (see
 // renderer/platform/scheduler/common/features.*) but requires an enterprise
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index 15be0cf..f0ec02f 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -278,6 +278,7 @@
     "platform/websocket_handshake_throttle.h",
     "web/blink.h",
     "web/modules/autofill/web_form_element_observer.h",
+    "web/modules/media/audio/audio_renderer_sink_cache.h",
     "web/modules/media/audio/web_audio_input_ipc_factory.h",
     "web/modules/media/audio/web_audio_output_ipc_factory.h",
     "web/modules/media/webmediaplayer_util.h",
diff --git a/third_party/blink/public/common/switches.h b/third_party/blink/public/common/switches.h
index 6dbcee3..54892bc 100644
--- a/third_party/blink/public/common/switches.h
+++ b/third_party/blink/public/common/switches.h
@@ -15,6 +15,7 @@
 // All switches in alphabetical order. The switches should be documented
 // alongside the definition of their values in the .cc file.
 BLINK_COMMON_EXPORT extern const char kAllowPreCommitInput[];
+BLINK_COMMON_EXPORT extern const char kBlinkSettings[];
 BLINK_COMMON_EXPORT extern const char kDefaultTileWidth[];
 BLINK_COMMON_EXPORT extern const char kDefaultTileHeight[];
 BLINK_COMMON_EXPORT extern const char kDisableImageAnimationResync[];
@@ -22,6 +23,7 @@
 BLINK_COMMON_EXPORT extern const char kDisablePartialRaster[];
 BLINK_COMMON_EXPORT extern const char kDisablePreferCompositingToLCDText[];
 BLINK_COMMON_EXPORT extern const char kDisableRGBA4444Textures[];
+BLINK_COMMON_EXPORT extern const char kDisableThreadedScrolling[];
 BLINK_COMMON_EXPORT extern const char kDisableZeroCopy[];
 BLINK_COMMON_EXPORT extern const char
     kEnableGpuMemoryBufferCompositorResources[];
@@ -39,8 +41,11 @@
 BLINK_COMMON_EXPORT extern const char kMaxUntiledLayerHeight[];
 BLINK_COMMON_EXPORT extern const char kMaxUntiledLayerWidth[];
 BLINK_COMMON_EXPORT extern const char kMinHeightForGpuRasterTile[];
+BLINK_COMMON_EXPORT extern const char kNetworkQuietTimeout[];
+BLINK_COMMON_EXPORT extern const char kPassiveListenersDefault[];
 BLINK_COMMON_EXPORT extern const char kShowLayoutShiftRegions[];
 BLINK_COMMON_EXPORT extern const char kShowPaintRects[];
+BLINK_COMMON_EXPORT extern const char kTouchTextSelectionStrategy[];
 
 BLINK_COMMON_EXPORT extern const char kUserAgentClientHintDisable[];
 }  // namespace switches
diff --git a/third_party/blink/public/mojom/frame/find_in_page.mojom b/third_party/blink/public/mojom/frame/find_in_page.mojom
index 5d0114a8..dc2f5f8 100644
--- a/third_party/blink/public/mojom/frame/find_in_page.mojom
+++ b/third_party/blink/public/mojom/frame/find_in_page.mojom
@@ -108,15 +108,14 @@
   // Whether this operation is the first request or a follow-up.
   bool new_session = true;
 
+  // This controls whether to find a match or to only do match counts and
+  // highlighting.
+  bool find_match = true;
+
   // Force a re-search of the frame: typically used when forcing a re-search
   // after the frame navigates.
   bool force = false;
 
-  // Whether to keep searching if the result is an exact match of the selection.
-  // This should generally be set to true unless you're starting a new find
-  // based on the selection.
-  bool find_next_if_selection_matches = true;
-
   // Signifies whether we should force text scoping to happen immediately
   // or not. Only used for testing purposes.
   bool run_synchronously_for_testing = false;
diff --git a/content/renderer/media/audio/audio_renderer_sink_cache.h b/third_party/blink/public/web/modules/media/audio/audio_renderer_sink_cache.h
similarity index 71%
rename from content/renderer/media/audio/audio_renderer_sink_cache.h
rename to third_party/blink/public/web/modules/media/audio/audio_renderer_sink_cache.h
index 83db7e3..5bf9c39 100644
--- a/content/renderer/media/audio/audio_renderer_sink_cache.h
+++ b/third_party/blink/public/web/modules/media/audio/audio_renderer_sink_cache.h
@@ -2,40 +2,38 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_RENDERER_MEDIA_AUDIO_AUDIO_RENDERER_SINK_CACHE_H_
-#define CONTENT_RENDERER_MEDIA_AUDIO_AUDIO_RENDERER_SINK_CACHE_H_
+#ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_MEDIA_AUDIO_AUDIO_RENDERER_SINK_CACHE_H_
+#define THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_MEDIA_AUDIO_AUDIO_RENDERER_SINK_CACHE_H_
 
 #include <memory>
 #include <string>
 
 #include "base/memory/scoped_refptr.h"
 #include "base/unguessable_token.h"
-#include "content/common/content_export.h"
 #include "media/base/output_device_info.h"
 #include "third_party/blink/public/common/tokens/tokens.h"
+#include "third_party/blink/public/platform/web_common.h"
 
 namespace media {
 class AudioRendererSink;
 }
 
-namespace content {
-class RenderFrame;
+namespace blink {
 
 // Caches AudioRendererSink instances, provides them to the clients for usage,
 // tracks their used/unused state, reuses them to obtain output device
 // information, garbage-collects unused sinks.
 // Must live on the main render thread. Thread safe.
-class CONTENT_EXPORT AudioRendererSinkCache {
+//
+// TODO(https://crrev.com/787252): Move this header out of the Blink public API
+// layer.
+class BLINK_MODULES_EXPORT AudioRendererSinkCache {
  public:
   virtual ~AudioRendererSinkCache() {}
 
-  // If called, the cache will drop sinks belonging to the specified frame on
-  // navigation.
-  static void ObserveFrame(RenderFrame* frame);
-
   // Returns output device information for a specified sink.
   virtual media::OutputDeviceInfo GetSinkInfo(
-      const blink::LocalFrameToken& source_frame_token,
+      const LocalFrameToken& source_frame_token,
       const base::UnguessableToken& session_id,
       const std::string& device_id) = 0;
 
@@ -43,7 +41,7 @@
   // calling ReleaseSink(). The sink must be stopped by the user before
   // deletion, but after releasing it from the cache.
   virtual scoped_refptr<media::AudioRendererSink> GetSink(
-      const blink::LocalFrameToken& source_frame_token,
+      const LocalFrameToken& source_frame_token,
       const std::string& device_id) = 0;
 
   // Notifies the cache that the sink is not in use any more. Must be
@@ -58,6 +56,6 @@
   DISALLOW_COPY_AND_ASSIGN(AudioRendererSinkCache);
 };
 
-}  // namespace content
+}  // namespace blink
 
-#endif  // CONTENT_RENDERER_MEDIA_AUDIO_AUDIO_RENDERER_SINK_CACHE_H_
+#endif  // THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_MEDIA_AUDIO_AUDIO_RENDERER_SINK_CACHE_H_
diff --git a/third_party/blink/public/web/web_local_frame.h b/third_party/blink/public/web/web_local_frame.h
index ffe7b0a..cd13223 100644
--- a/third_party/blink/public/web/web_local_frame.h
+++ b/third_party/blink/public/web/web_local_frame.h
@@ -299,13 +299,14 @@
   // CSS3 Paged Media ----------------------------------------------------
 
   // Returns the type of @page size styling for the given page.
-  virtual PageSizeType GetPageSizeType(int page_index) = 0;
+  virtual PageSizeType GetPageSizeType(uint32_t page_index) = 0;
 
   // Gets the description for the specified page. This includes preferred page
   // size and margins in pixels, assuming 96 pixels per inch. The size and
   // margins must be initialized to the default values that are used if auto is
   // specified.
-  virtual void GetPageDescription(int page_index, WebPrintPageDescription*) = 0;
+  virtual void GetPageDescription(uint32_t page_index,
+                                  WebPrintPageDescription*) = 0;
 
   // Scripting --------------------------------------------------------------
 
@@ -671,18 +672,18 @@
   // node is printed (for now only plugins are supported), instead of the entire
   // frame.
   // Returns the number of pages that can be printed at the given page size.
-  virtual int PrintBegin(const WebPrintParams&,
-                         const WebNode& constrain_to_node = WebNode()) = 0;
+  virtual uint32_t PrintBegin(const WebPrintParams&,
+                              const WebNode& constrain_to_node = WebNode()) = 0;
 
   // Returns the page shrinking factor calculated by webkit (usually
   // between 1/1.33 and 1/2). Returns 0 if the page number is invalid or
   // not in printing mode.
-  virtual float GetPrintPageShrink(int page) = 0;
+  virtual float GetPrintPageShrink(uint32_t page) = 0;
 
   // Prints one page, and returns the calculated page shrinking factor
   // (usually between 1/1.33 and 1/2).  Returns 0 if the page number is
   // invalid or not in printing mode.
-  virtual float PrintPage(int page_to_print, cc::PaintCanvas*) = 0;
+  virtual float PrintPage(uint32_t page_to_print, cc::PaintCanvas*) = 0;
 
   // Reformats the WebFrame for screen display.
   virtual void PrintEnd() = 0;
@@ -757,7 +758,7 @@
   // page-orientation.
   virtual WebSize SpoolSizeInPixelsForTesting(
       const WebSize& page_size_in_pixels,
-      int page_count) = 0;
+      uint32_t page_count) = 0;
 
   // Prints the frame into the canvas, with page boundaries drawn as one pixel
   // wide blue lines. This method exists to support web tests.
diff --git a/third_party/blink/public/web/web_settings.h b/third_party/blink/public/web/web_settings.h
index 0fe6153..65625b3c 100644
--- a/third_party/blink/public/web/web_settings.h
+++ b/third_party/blink/public/web/web_settings.h
@@ -35,6 +35,7 @@
 
 #include "third_party/blink/public/common/css/navigation_controls.h"
 #include "third_party/blink/public/common/css/preferred_color_scheme.h"
+#include "third_party/blink/public/common/web_preferences/web_preferences.h"
 #include "third_party/blink/public/platform/pointer_properties.h"
 #include "third_party/blink/public/platform/web_common.h"
 #include "third_party/blink/public/platform/web_effective_connection_type.h"
@@ -95,14 +96,6 @@
     kForceAllTrue  // Force all values to be true even when specified.
   };
 
-  // Defines the autoplay policy to be used. Should match the enum class in
-  // web_preferences.h
-  enum class AutoplayPolicy {
-    kNoUserGestureRequired = 0,
-    kUserGestureRequired,
-    kDocumentUserActivationRequired,
-  };
-
   // Sets value of a setting by its string identifier from Settings.in and
   // string representation of value. An enum's string representation is the
   // string representation of the integer value of the enum.
@@ -133,7 +126,7 @@
   virtual void SetAlwaysShowContextMenuOnTouch(bool) = 0;
   virtual void SetAntialiased2dCanvasEnabled(bool) = 0;
   virtual void SetAntialiasedClips2dCanvasEnabled(bool) = 0;
-  virtual void SetAutoplayPolicy(AutoplayPolicy) = 0;
+  virtual void SetAutoplayPolicy(web_pref::AutoplayPolicy) = 0;
   virtual void SetAutoZoomFocusedNodeToLegibleScale(bool) = 0;
   virtual void SetCaretBrowsingEnabled(bool) = 0;
   virtual void SetClobberUserAgentInitialScaleQuirk(bool) = 0;
diff --git a/third_party/blink/public/web/web_view.h b/third_party/blink/public/web/web_view.h
index 965eb09..8e8e90c 100644
--- a/third_party/blink/public/web/web_view.h
+++ b/third_party/blink/public/web/web_view.h
@@ -33,6 +33,7 @@
 
 #include "base/time/time.h"
 #include "third_party/blink/public/common/page/web_drag_operation.h"
+#include "third_party/blink/public/common/web_preferences/web_preferences.h"
 #include "third_party/blink/public/mojom/input/focus_type.mojom-shared.h"
 #include "third_party/blink/public/mojom/page/page.mojom-shared.h"
 #include "third_party/blink/public/mojom/page/page_visibility_state.mojom-shared.h"
@@ -40,6 +41,7 @@
 #include "third_party/blink/public/platform/cross_variant_mojo_util.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/platform/web_url.h"
+#include "third_party/blink/public/web/web_settings.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -477,7 +479,16 @@
   // after.
   virtual void PaintContent(cc::PaintCanvas*, const gfx::Rect& viewport) = 0;
 
-  // Suspend and resume ---------------------------------------------------
+  // Web preferences ---------------------------------------------------
+
+  // Applies blink related preferences to this view.
+  BLINK_EXPORT static void ApplyWebPreferences(
+      const web_pref::WebPreferences& prefs,
+      WebView* web_view);
+
+  virtual void SetWebPreferences(
+      const web_pref::WebPreferences& preferences) = 0;
+  virtual const web_pref::WebPreferences& GetWebPreferences() = 0;
 
   // TODO(lfg): Remove this once the refactor of WebView/WebWidget is
   // completed.
diff --git a/third_party/blink/renderer/bindings/bindings.gni b/third_party/blink/renderer/bindings/bindings.gni
index e8a85748..20ca0bb 100644
--- a/third_party/blink/renderer/bindings/bindings.gni
+++ b/third_party/blink/renderer/bindings/bindings.gni
@@ -17,6 +17,7 @@
                     "core/v8/binding_security.h",
                     "core/v8/boxed_v8_module.h",
                     "core/v8/callback_promise_adapter.h",
+                    "core/v8/classic_evaluation_result.h",
                     "core/v8/custom/v8_custom_xpath_ns_resolver.cc",
                     "core/v8/custom/v8_custom_xpath_ns_resolver.h",
                     "core/v8/custom/v8_dev_tools_host_custom.cc",
diff --git a/third_party/blink/renderer/bindings/core/v8/classic_evaluation_result.h b/third_party/blink/renderer/bindings/core/v8/classic_evaluation_result.h
new file mode 100644
index 0000000..61edac3
--- /dev/null
+++ b/third_party/blink/renderer/bindings/core/v8/classic_evaluation_result.h
@@ -0,0 +1,61 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_CLASSIC_EVALUATION_RESULT_H_
+#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_CLASSIC_EVALUATION_RESULT_H_
+
+#include "third_party/blink/renderer/bindings/core/v8/script_source_location_type.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_code_cache.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
+#include "third_party/blink/renderer/platform/loader/fetch/cached_metadata_handler.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/text/text_position.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+#include "v8/include/v8.h"
+
+namespace blink {
+
+// ClassicEvaluationResult encapsulates the result of a classic script
+// evaluation.
+// - If IsEmpty() is false:
+//     A script is evaluated successfully.
+//     No exceptions are thrown.
+//     GetValue() returns a non-Empty value.
+// - If IsEmpty() is true:
+//     Script evaluation failed (compile error, evaluation error, or so).
+//     An exception might or might not be thrown in V8.
+//     Unlike v8::MaybeLocal<>, there are cases where no exceptions are thrown
+//     to V8 while returning an Empty ClassicEvaluationResult, like when:
+//     - An exception is thrown during script evaluation but caught and passed
+//       to https://html.spec.whatwg.org/C/#report-the-error, instead of
+//       being rethrown, or
+//     - Script evaluation is skipped due to checks within Blink.
+//
+// TODO(crbug/1111134): Consider merging with ModuleEvaluationResult later.
+// Right now classic and module evaluation paths are not yet merged, and
+// top-level await (crbug/1022182) will modify ModuleEvaluationResult.
+class CORE_EXPORT ClassicEvaluationResult final {
+  STACK_ALLOCATED();
+
+ public:
+  ClassicEvaluationResult() = default;
+  explicit ClassicEvaluationResult(v8::Local<v8::Value> value) : value_(value) {
+    DCHECK(!IsEmpty());
+  }
+
+  bool IsEmpty() const { return value_.IsEmpty(); }
+  v8::Local<v8::Value> GetValue() const {
+    DCHECK(!IsEmpty());
+    return value_;
+  }
+
+ private:
+  v8::Local<v8::Value> value_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_CLASSIC_EVALUATION_RESULT_H_
diff --git a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc
index c0ed21b..b1f64a2 100644
--- a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc
+++ b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc
@@ -41,6 +41,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/v8_code_cache.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_initializer.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_script_runner.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
 #include "third_party/blink/renderer/core/events/error_event.h"
 #include "third_party/blink/renderer/core/execution_context/agent.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
@@ -54,6 +55,7 @@
 #include "third_party/blink/renderer/platform/bindings/origin_trial_features.h"
 #include "third_party/blink/renderer/platform/bindings/v8_dom_wrapper.h"
 #include "third_party/blink/renderer/platform/bindings/v8_object_constructor.h"
+#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
 #include "third_party/blink/renderer/platform/bindings/wrapper_type_info.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/heap/thread_state.h"
@@ -62,48 +64,12 @@
 
 namespace blink {
 
-class WorkerOrWorkletScriptController::ExecutionState final {
-  STACK_ALLOCATED();
-
- public:
-  explicit ExecutionState(WorkerOrWorkletScriptController* controller)
-      : had_exception(false),
-        error_event_from_imported_script_(nullptr),
-        controller_(controller),
-        outer_state_(controller->execution_state_) {
-    controller_->execution_state_ = this;
-  }
-
-  ~ExecutionState() { controller_->execution_state_ = outer_state_; }
-
-  bool had_exception;
-  String error_message;
-  std::unique_ptr<SourceLocation> location_;
-  ScriptValue exception;
-  ErrorEvent* error_event_from_imported_script_;
-
-  // A ExecutionState context is stack allocated by
-  // WorkerOrWorkletScriptController::evaluate(), with the contoller using it
-  // during script evaluation. To handle nested evaluate() uses,
-  // ExecutionStates are chained together;
-  // |outer_state_| keeps a pointer to the context object one level out
-  // (or 0, if outermost.) Upon return from evaluate(), the
-  // WorkerOrWorkletScriptController's ExecutionState is popped and the
-  // previous one restored (see above dtor.)
-  //
-  // With Oilpan, |outer_state_| isn't traced. It'll be "up the stack"
-  // and its fields will be traced when scanning the stack.
-  WorkerOrWorkletScriptController* controller_;
-  ExecutionState* outer_state_;
-};
-
 WorkerOrWorkletScriptController::WorkerOrWorkletScriptController(
     WorkerOrWorkletGlobalScope* global_scope,
     v8::Isolate* isolate)
     : global_scope_(global_scope),
       isolate_(isolate),
-      rejected_promises_(RejectedPromises::Create()),
-      execution_state_(nullptr) {
+      rejected_promises_(RejectedPromises::Create()) {
   DCHECK(isolate);
   world_ =
       DOMWrapperWorld::Create(isolate, DOMWrapperWorld::WorldType::kWorker);
@@ -345,109 +311,120 @@
       V8String(isolate_, error_message));
 }
 
-v8::Local<v8::Value> WorkerOrWorkletScriptController::EvaluateInternal(
+// https://html.spec.whatwg.org/C/#run-a-classic-script
+ClassicEvaluationResult WorkerOrWorkletScriptController::EvaluateAndReturnValue(
     const ScriptSourceCode& source_code,
     SanitizeScriptErrors sanitize_script_errors,
-    V8CacheOptions v8_cache_options) {
-  DCHECK(IsContextInitialized());
-  DCHECK(is_ready_to_evaluate_);
-
-  TRACE_EVENT1("devtools.timeline", "EvaluateScript", "data",
-               inspector_evaluate_script_event::Data(
-                   nullptr, source_code.Url(), source_code.StartPosition()));
-
-  v8::TryCatch block(isolate_);
-
-  // TODO(crbug/1114994): Plumb this from ClassicScript.
-  const KURL base_url = source_code.Url();
-
-  // Use default ReferrerScriptInfo here, as
-  // - A work{er,let} script doesn't have a nonce, and
-  // - a work{er,let} script is always "not parser inserted".
-  // TODO(crbug/1114988): After crbug/1114988 is fixed, this can be the
-  // default ScriptFetchOptions(). Currently the default ScriptFetchOptions()
-  // is not used because it has CredentialsMode::kOmit.
-  // TODO(crbug/1114989): Plumb this from ClassicScript.
-  ScriptFetchOptions script_fetch_options(
-      String(), IntegrityMetadataSet(), String(),
-      ParserDisposition::kNotParserInserted,
-      network::mojom::CredentialsMode::kSameOrigin,
-      network::mojom::ReferrerPolicy::kDefault,
-      mojom::blink::FetchImportanceMode::kImportanceAuto);
-
-  v8::MaybeLocal<v8::Value> maybe_result = V8ScriptRunner::CompileAndRunScript(
-      isolate_, script_state_, global_scope_, source_code, base_url,
-      sanitize_script_errors, script_fetch_options, v8_cache_options);
-
-  if (!block.CanContinue()) {
-    ForbidExecution();
-    return v8::Local<v8::Value>();
-  }
-
-  if (block.HasCaught()) {
-    v8::Local<v8::Message> message = block.Message();
-    execution_state_->had_exception = true;
-    execution_state_->error_message = ToCoreString(message->Get());
-    execution_state_->location_ = SourceLocation::FromMessage(
-        isolate_, message, ExecutionContext::From(script_state_));
-    execution_state_->exception =
-        ScriptValue(script_state_->GetIsolate(), block.Exception());
-    block.Reset();
-  } else {
-    execution_state_->had_exception = false;
-  }
-
-  v8::Local<v8::Value> result;
-  if (!maybe_result.ToLocal(&result))
-    return v8::Local<v8::Value>();
-
-  return result;
-}
-
-v8::Local<v8::Value> WorkerOrWorkletScriptController::EvaluateAndReturnValue(
-    const ScriptSourceCode& source_code,
-    SanitizeScriptErrors sanitize_script_errors,
-    ErrorEvent** error_event,
-    V8CacheOptions v8_cache_options) {
+    V8CacheOptions v8_cache_options,
+    RethrowErrorsOption rethrow_errors) {
   if (IsExecutionForbidden())
-    return v8::Local<v8::Value>();
+    return ClassicEvaluationResult();
 
-  ExecutionState state(this);
-  v8::Local<v8::Value> result =
-      EvaluateInternal(source_code, sanitize_script_errors, v8_cache_options);
-  if (IsExecutionForbidden())
-    return v8::Local<v8::Value>();
+  // Scope for |TRACE_EVENT1| and |v8::TryCatch| below.
+  {
+    DCHECK(IsContextInitialized());
+    DCHECK(is_ready_to_evaluate_);
 
-  if (state.had_exception) {
-    if (error_event) {
-      if (state.error_event_from_imported_script_) {
-        // Propagate inner error event outwards.
-        *error_event = state.error_event_from_imported_script_;
-        state.error_event_from_imported_script_ = nullptr;
-        return v8::Local<v8::Value>();
-      }
-      if (sanitize_script_errors == SanitizeScriptErrors::kSanitize) {
-        *error_event = ErrorEvent::CreateSanitizedError(script_state_);
-      } else {
-        *error_event =
-            ErrorEvent::Create(state.error_message, state.location_->Clone(),
-                               state.exception, world_.get());
-      }
-    } else {
-      ErrorEvent* event = nullptr;
-      if (state.error_event_from_imported_script_) {
-        event = state.error_event_from_imported_script_;
-        state.error_event_from_imported_script_ = nullptr;
-      } else {
-        event =
-            ErrorEvent::Create(state.error_message, state.location_->Clone(),
-                               state.exception, world_.get());
-      }
-      global_scope_->DispatchErrorEvent(event, sanitize_script_errors);
+    TRACE_EVENT1("devtools.timeline", "EvaluateScript", "data",
+                 inspector_evaluate_script_event::Data(
+                     nullptr, source_code.Url(), source_code.StartPosition()));
+
+    v8::TryCatch block(isolate_);
+
+    // Step 8.3. Otherwise, rethrow errors is false. Perform the following
+    // steps: [spec text]
+    // Step 8.3.1. Report the exception given by evaluationStatus.[[Value]]
+    // for script. [spec text]
+    //
+    // This will be done inside V8 (inside V8ScriptRunner::CompileAndRunScript()
+    // below) by setting TryCatch::SetVerbose(true) here.
+    if (!rethrow_errors.ShouldRethrow()) {
+      block.SetVerbose(true);
     }
-    return v8::Local<v8::Value>();
+
+    // TODO(crbug/1114994): Plumb this from ClassicScript.
+    const KURL base_url = source_code.Url();
+
+    // Use default ReferrerScriptInfo here, as
+    // - A work{er,let} script doesn't have a nonce, and
+    // - a work{er,let} script is always "not parser inserted".
+    // TODO(crbug/1114988): After crbug/1114988 is fixed, this can be the
+    // default ScriptFetchOptions(). Currently the default ScriptFetchOptions()
+    // is not used because it has CredentialsMode::kOmit.
+    // TODO(crbug/1114989): Plumb this from ClassicScript.
+    ScriptFetchOptions script_fetch_options(
+        String(), IntegrityMetadataSet(), String(),
+        ParserDisposition::kNotParserInserted,
+        network::mojom::CredentialsMode::kSameOrigin,
+        network::mojom::ReferrerPolicy::kDefault,
+        mojom::blink::FetchImportanceMode::kImportanceAuto);
+
+    v8::MaybeLocal<v8::Value> maybe_result =
+        V8ScriptRunner::CompileAndRunScript(
+            isolate_, script_state_, global_scope_, source_code, base_url,
+            sanitize_script_errors, script_fetch_options, v8_cache_options);
+
+    // TODO(crbug/1114601): Investigate whether to check CanContinue() in other
+    // script evaluation code paths.
+    if (!block.CanContinue()) {
+      ForbidExecution();
+    }
+
+    if (IsExecutionForbidden()) {
+      return ClassicEvaluationResult();
+    }
+
+    if (!block.HasCaught()) {
+      // Step 10. If evaluationStatus is a normal completion, then return
+      // evaluationStatus. [spec text]
+      v8::Local<v8::Value> result;
+      if (!maybe_result.ToLocal(&result))
+        return ClassicEvaluationResult();
+
+      return ClassicEvaluationResult(result);
+    }
+
+    DCHECK(maybe_result.IsEmpty());
+
+    if (rethrow_errors.ShouldRethrow() &&
+        sanitize_script_errors == SanitizeScriptErrors::kDoNotSanitize) {
+      // Step 8.1. If rethrow errors is true and script's muted errors is
+      // false, then: [spec text]
+      //
+      // Step 8.1.2. Rethrow evaluationStatus.[[Value]]. [spec text]
+      //
+      // We rethrow exceptions reported from importScripts() here. The
+      // original filename/lineno/colno information (which points inside of
+      // imported scripts) is kept through ReThrow(), and will be eventually
+      // reported to WorkerGlobalScope.onerror via `TryCatch::SetVerbose(true)`
+      // called at top-level worker script evaluation.
+      block.ReThrow();
+      return ClassicEvaluationResult();
+    }
   }
-  return result;
+  // |v8::TryCatch| is (and should be) exited, before ThrowException() below.
+
+  if (rethrow_errors.ShouldRethrow()) {
+    // kDoNotSanitize case is processed and early-exited above.
+    DCHECK_EQ(sanitize_script_errors, SanitizeScriptErrors::kSanitize);
+
+    // Step 8.2. If rethrow errors is true and script's muted errors is
+    // true, then: [spec text]
+    //
+    // Step 8.2.2. Throw a "NetworkError" DOMException. [spec text]
+    //
+    // We don't supply any message here to avoid leaking details of muted
+    // errors.
+    V8ThrowException::ThrowException(
+        isolate_, V8ThrowDOMException::CreateOrEmpty(
+                      isolate_, DOMExceptionCode::kNetworkError,
+                      rethrow_errors.Message()));
+    return ClassicEvaluationResult();
+  }
+
+  // #report-the-error for rethrow errors == true is already handled via
+  // |TryCatch::SetVerbose(true)| above.
+  return ClassicEvaluationResult();
 }
 
 void WorkerOrWorkletScriptController::ForbidExecution() {
@@ -481,15 +458,6 @@
   disable_eval_pending_ = error_message;
 }
 
-void WorkerOrWorkletScriptController::RethrowExceptionFromImportedScript(
-    ErrorEvent* error_event,
-    ExceptionState& exception_state) {
-  if (execution_state_)
-    execution_state_->error_event_from_imported_script_ = error_event;
-  exception_state.RethrowV8Exception(
-      error_event->error(script_state_).V8ValueFor(script_state_));
-}
-
 void WorkerOrWorkletScriptController::Trace(Visitor* visitor) const {
   visitor->Trace(global_scope_);
   visitor->Trace(script_state_);
diff --git a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h
index d901e4ae..23fc7bdfc 100644
--- a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h
+++ b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h
@@ -32,6 +32,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_WORKER_OR_WORKLET_SCRIPT_CONTROLLER_H_
 
 #include "base/macros.h"
+#include "third_party/blink/renderer/bindings/core/v8/classic_evaluation_result.h"
 #include "third_party/blink/renderer/bindings/core/v8/rejected_promises.h"
 #include "third_party/blink/renderer/bindings/core/v8/sanitize_script_errors.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
@@ -44,8 +45,6 @@
 
 namespace blink {
 
-class ErrorEvent;
-class ExceptionState;
 class ScriptSourceCode;
 class WorkerOrWorkletGlobalScope;
 
@@ -58,13 +57,50 @@
 
   bool IsExecutionForbidden() const;
 
-  // Returns a non-Empty value if the evaluation completed with no uncaught
-  // exception. Callers should enter ScriptState::Scope before calling this.
-  v8::Local<v8::Value> EvaluateAndReturnValue(
+  // Rethrow errors flag in
+  // https://html.spec.whatwg.org/C/#run-a-classic-script
+  class RethrowErrorsOption final {
+    STACK_ALLOCATED();
+
+   public:
+    RethrowErrorsOption(RethrowErrorsOption&&) = default;
+    RethrowErrorsOption& operator=(RethrowErrorsOption&&) = default;
+
+    RethrowErrorsOption(const RethrowErrorsOption&) = delete;
+    RethrowErrorsOption& operator=(const RethrowErrorsOption&) = delete;
+
+    // Rethrow errors flag is false.
+    static RethrowErrorsOption DoNotRethrow() {
+      return RethrowErrorsOption(base::nullopt);
+    }
+
+    // Rethrow errors flag is true. When rethrowing, a NetworkError with
+    // `message` is thrown. This is used only for importScripts(), and
+    // `message` is used to throw NetworkErrors with the same message text,
+    // no matter whether the NetworkError is thrown inside or outside
+    // EvaluateAndReturnValue().
+    static RethrowErrorsOption Rethrow(const String& message) {
+      return RethrowErrorsOption(message);
+    }
+
+    bool ShouldRethrow() const { return static_cast<bool>(message_); }
+    String Message() const { return *message_; }
+
+   private:
+    explicit RethrowErrorsOption(base::Optional<String> message)
+        : message_(std::move(message)) {}
+
+    // `nullopt` <=> rethrow errors is false.
+    base::Optional<String> message_;
+  };
+
+  // https://html.spec.whatwg.org/C/#run-a-classic-script
+  // Callers should enter ScriptState::Scope before calling this.
+  ClassicEvaluationResult EvaluateAndReturnValue(
       const ScriptSourceCode&,
       SanitizeScriptErrors sanitize_script_errors,
-      ErrorEvent** = nullptr,
-      V8CacheOptions = kV8CacheOptionsDefault);
+      V8CacheOptions = kV8CacheOptionsDefault,
+      RethrowErrorsOption = RethrowErrorsOption::DoNotRethrow());
 
   // Prevents future JavaScript execution.
   void ForbidExecution();
@@ -81,8 +117,6 @@
   // before Evaluate().
   void PrepareForEvaluation();
 
-  // Used by WorkerGlobalScope:
-  void RethrowExceptionFromImportedScript(ErrorEvent*, ExceptionState&);
   // Disables `eval()` on JavaScript. This must be called before Evaluate().
   void DisableEval(const String&);
 
@@ -106,14 +140,8 @@
   }
 
  private:
-  class ExecutionState;
-
   void DisableEvalInternal(const String& error_message);
 
-  // Evaluate a script file in the current execution environment.
-  v8::Local<v8::Value> EvaluateInternal(const ScriptSourceCode&,
-                                        SanitizeScriptErrors,
-                                        V8CacheOptions);
   void DisposeContextIfNeeded();
 
   Member<WorkerOrWorkletGlobalScope> global_scope_;
@@ -134,14 +162,6 @@
 
   scoped_refptr<RejectedPromises> rejected_promises_;
 
-  // |execution_state_| refers to a stack object that evaluate() allocates;
-  // evaluate() ensuring that the pointer reference to it is removed upon
-  // returning. Hence kept as a bare pointer here, and not a Persistent with
-  // Oilpan enabled; stack scanning will visit the object and
-  // trace its on-heap fields.
-  GC_PLUGIN_IGNORE("394615")
-  ExecutionState* execution_state_;
-
   DISALLOW_COPY_AND_ASSIGN(WorkerOrWorkletScriptController);
 };
 
diff --git a/third_party/blink/renderer/core/css/page_rule_collector.cc b/third_party/blink/renderer/core/css/page_rule_collector.cc
index f4818660c..db7bbd9 100644
--- a/third_party/blink/renderer/core/css/page_rule_collector.cc
+++ b/third_party/blink/renderer/core/css/page_rule_collector.cc
@@ -44,7 +44,7 @@
 }
 
 bool PageRuleCollector::IsLeftPage(const ComputedStyle* root_element_style,
-                                   int page_index) const {
+                                   uint32_t page_index) const {
   bool is_first_page_left = false;
   DCHECK(root_element_style);
   if (!root_element_style->IsLeftToRightDirection())
@@ -53,14 +53,14 @@
   return (page_index + (is_first_page_left ? 1 : 0)) % 2;
 }
 
-bool PageRuleCollector::IsFirstPage(int page_index) const {
+bool PageRuleCollector::IsFirstPage(uint32_t page_index) const {
   // FIXME: In case of forced left/right page, page at index 1 (not 0) can be
   // the first page.
   return (!page_index);
 }
 
 PageRuleCollector::PageRuleCollector(const ComputedStyle* root_element_style,
-                                     int page_index,
+                                     uint32_t page_index,
                                      const AtomicString& page_name,
                                      MatchResult& match_result)
     : is_left_page_(IsLeftPage(root_element_style, page_index)),
diff --git a/third_party/blink/renderer/core/css/page_rule_collector.h b/third_party/blink/renderer/core/css/page_rule_collector.h
index 57d8fbb..f6ef7c4 100644
--- a/third_party/blink/renderer/core/css/page_rule_collector.h
+++ b/third_party/blink/renderer/core/css/page_rule_collector.h
@@ -35,7 +35,7 @@
 
  public:
   PageRuleCollector(const ComputedStyle* root_element_style,
-                    int page_index,
+                    uint32_t page_index,
                     const AtomicString& page_name,
                     MatchResult&);
 
@@ -44,12 +44,12 @@
 
  private:
   bool IsLeftPage(const ComputedStyle* root_element_style,
-                  int page_index) const;
+                  uint32_t page_index) const;
   bool IsRightPage(const ComputedStyle* root_element_style,
-                   int page_index) const {
+                   uint32_t page_index) const {
     return !IsLeftPage(root_element_style, page_index);
   }
-  bool IsFirstPage(int page_index) const;
+  bool IsFirstPage(uint32_t page_index) const;
 
   void MatchPageRulesForList(HeapVector<Member<StyleRulePage>>& matched_rules,
                              const HeapVector<Member<StyleRulePage>>& rules);
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.cc b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
index 03cbf7a7..89ee70c 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
@@ -1172,7 +1172,7 @@
 }
 
 scoped_refptr<const ComputedStyle> StyleResolver::StyleForPage(
-    int page_index,
+    uint32_t page_index,
     const AtomicString& page_name) {
   scoped_refptr<const ComputedStyle> initial_style =
       InitialStyleForElement(GetDocument());
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.h b/third_party/blink/renderer/core/css/resolver/style_resolver.h
index 649908c..a956a53c 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver.h
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver.h
@@ -87,7 +87,7 @@
       const ComputedStyle* layout_parent_style);
 
   scoped_refptr<const ComputedStyle> StyleForPage(
-      int page_index,
+      uint32_t page_index,
       const AtomicString& page_name);
   scoped_refptr<const ComputedStyle> StyleForText(Text*);
   scoped_refptr<ComputedStyle> StyleForViewport();
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index 333ac6f3..612c5d17 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -2864,7 +2864,7 @@
     focused_element_->blur();
 }
 
-scoped_refptr<const ComputedStyle> Document::StyleForPage(int page_index) {
+scoped_refptr<const ComputedStyle> Document::StyleForPage(uint32_t page_index) {
   UpdateDistributionForUnknownReasons();
 
   AtomicString page_name;
@@ -2910,12 +2910,12 @@
   }
 }
 
-bool Document::IsPageBoxVisible(int page_index) {
+bool Document::IsPageBoxVisible(uint32_t page_index) {
   return StyleForPage(page_index)->Visibility() !=
          EVisibility::kHidden;  // display property doesn't apply to @page.
 }
 
-void Document::GetPageDescription(int page_index,
+void Document::GetPageDescription(uint32_t page_index,
                                   WebPrintPageDescription* description) {
   scoped_refptr<const ComputedStyle> style = StyleForPage(page_index);
 
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index 8d2e924..d36ae4c 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -597,7 +597,7 @@
   void IncLayoutBlockCounter() { ++layout_blocks_counter_; }
   void IncLayoutBlockCounterNG() { ++layout_blocks_counter_ng_; }
 
-  scoped_refptr<const ComputedStyle> StyleForPage(int page_index);
+  scoped_refptr<const ComputedStyle> StyleForPage(uint32_t page_index);
 
   // Ensures that location-based data will be valid for a given node.
   //
@@ -611,13 +611,13 @@
                                            DocumentUpdateReason reason);
 
   // Returns true if page box (margin boxes and page borders) is visible.
-  bool IsPageBoxVisible(int page_index);
+  bool IsPageBoxVisible(uint32_t page_index);
 
   // Gets the description for the specified page. This includes preferred page
   // size and margins in pixels, assuming 96 pixels per inch. The size and
   // margins must be initialized to the default values that are used if auto is
   // specified.
-  void GetPageDescription(int page_index, WebPrintPageDescription*);
+  void GetPageDescription(uint32_t page_index, WebPrintPageDescription*);
 
   ResourceFetcher* Fetcher() const { return fetcher_.Get(); }
 
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 04f84b3..16db88c 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -656,6 +656,13 @@
       // set copy’s shadow root’s "is declarative shadow root" property to true.
       cloned_shadow_root.SetIsDeclarativeShadowRoot(
           shadow_root->IsDeclarativeShadowRoot());
+
+      // 7.NEW If node’s shadow root’s "is available to element internals" is
+      // true, then set copy’s shadow root’s "is available to element internals"
+      // property to true.
+      cloned_shadow_root.SetAvailableToElementInternals(
+          shadow_root->IsAvailableToElementInternals());
+
       // 7.3 If the clone children flag is set, clone all the children of node’s
       // shadow root and append them to copy’s shadow root, with document as
       // specified, the clone children flag being set, and the clone shadows
@@ -3591,6 +3598,15 @@
                                 FocusDelegation::kDelegateFocus);
   // 8. Set shadow’s "is declarative shadow root" property to false.
   shadow_root.SetIsDeclarativeShadowRoot(false);
+
+  // NEW. If shadow host is a custom element, and if custom element state is
+  // not "precustomized" or "custom", set shadow root's
+  // IsAvailableToElementInternals flag to false. Otherwise, set it to true.
+  shadow_root.SetAvailableToElementInternals(
+      !(IsCustomElement() &&
+        GetCustomElementState() != CustomElementState::kCustom &&
+        GetCustomElementState() != CustomElementState::kPreCustomized));
+
   shadow_root.SetSlotAssignmentMode(slot_assignment_mode);
   return shadow_root;
 }
diff --git a/third_party/blink/renderer/core/dom/shadow_root.h b/third_party/blink/renderer/core/dom/shadow_root.h
index 909c1420..3392b4da 100644
--- a/third_party/blink/renderer/core/dom/shadow_root.h
+++ b/third_party/blink/renderer/core/dom/shadow_root.h
@@ -163,6 +163,15 @@
   }
   bool IsDeclarativeShadowRoot() const { return is_declarative_shadow_root_; }
 
+  void SetAvailableToElementInternals(bool flag) {
+    DCHECK(!flag || GetType() == ShadowRootType::kOpen ||
+           GetType() == ShadowRootType::kClosed);
+    available_to_element_internals_ = flag;
+  }
+  bool IsAvailableToElementInternals() const {
+    return available_to_element_internals_ || is_declarative_shadow_root_;
+  }
+
   bool ContainsShadowRoots() const { return child_shadow_root_count_; }
 
   StyleSheetList& StyleSheets();
@@ -195,8 +204,9 @@
   unsigned delegates_focus_ : 1;
   unsigned slot_assignment_mode_ : 1;
   unsigned is_declarative_shadow_root_ : 1;
+  unsigned available_to_element_internals_ : 1;
   unsigned needs_distribution_recalc_ : 1;
-  unsigned unused_ : 9;
+  unsigned unused_ : 8;
 };
 
 inline Element* ShadowRoot::ActiveElement() const {
diff --git a/third_party/blink/renderer/core/editing/editor.cc b/third_party/blink/renderer/core/editing/editor.cc
index 63e849d..92a0c547 100644
--- a/third_party/blink/renderer/core/editing/editor.cc
+++ b/third_party/blink/renderer/core/editing/editor.cc
@@ -851,10 +851,7 @@
   // the reference range, find again. Build a selection with the found range
   // to remove collapsed whitespace. Compare ranges instead of selection
   // objects to ignore the way that the current selection was made.
-  const bool find_next_if_selection_matches =
-      !(options & kDontFindNextIfSelectionMatches);
-  if (find_next_if_selection_matches && result_range &&
-      start_in_reference_range &&
+  if (result_range && start_in_reference_range &&
       NormalizeRange(EphemeralRangeInFlatTree(result_range)) ==
           reference_range) {
     if (forward)
diff --git a/third_party/blink/renderer/core/editing/finder/find_options.h b/third_party/blink/renderer/core/editing/finder/find_options.h
index 0d85e61..6058284 100644
--- a/third_party/blink/renderer/core/editing/finder/find_options.h
+++ b/third_party/blink/renderer/core/editing/finder/find_options.h
@@ -37,7 +37,6 @@
   // TODO(yosin) Once find UI works on flat tree and it doesn't use
   // |rangeOfString()|, we should get rid of |FindAPICall| enum member.
   kFindAPICall = 1 << 5,  // Used for Window.find or execCommand('find')
-  kDontFindNextIfSelectionMatches = 1 << 6,
 };
 
 typedef unsigned FindOptions;
diff --git a/third_party/blink/renderer/core/editing/finder/text_finder.cc b/third_party/blink/renderer/core/editing/finder/text_finder.cc
index 15afa35..3281a6439 100644
--- a/third_party/blink/renderer/core/editing/finder/text_finder.cc
+++ b/third_party/blink/renderer/core/editing/finder/text_finder.cc
@@ -171,9 +171,6 @@
       (options.forward ? 0 : kBackwards) |
       (options.match_case ? 0 : kCaseInsensitive) |
       (wrap_within_frame ? kWrapAround : 0) |
-      (options.find_next_if_selection_matches
-           ? 0
-           : kDontFindNextIfSelectionMatches) |
       (options.new_session ? kStartInSelection : 0);
   active_match_ = Editor::FindRangeOfString(
       *OwnerFrame().GetFrame()->GetDocument(), search_text,
diff --git a/third_party/blink/renderer/core/exported/DEPS b/third_party/blink/renderer/core/exported/DEPS
index 06d8f96..ef30f9c 100644
--- a/third_party/blink/renderer/core/exported/DEPS
+++ b/third_party/blink/renderer/core/exported/DEPS
@@ -6,3 +6,12 @@
   "+ui/base/mojom/ui_base_types.mojom-shared.h",
   "+ui/gfx/transform.h",
 ]
+
+specific_include_rules = {
+  "web_view_impl\.cc": [
+    "+base/command_line.h",
+    "+components/viz/common/features.h",
+    "+media/base/media_switches.h",
+    "+third_party/icu/source/common/unicode/uscript.h",
+  ],
+}
\ No newline at end of file
diff --git a/third_party/blink/renderer/core/exported/web_frame_test.cc b/third_party/blink/renderer/core/exported/web_frame_test.cc
index 84c7a6fa..5259dab 100644
--- a/third_party/blink/renderer/core/exported/web_frame_test.cc
+++ b/third_party/blink/renderer/core/exported/web_frame_test.cc
@@ -8743,8 +8743,8 @@
   print_params.print_content_area.width = 500;
   print_params.print_content_area.height = 500;
 
-  int page_count = frame->PrintBegin(print_params);
-  EXPECT_EQ(1, page_count);
+  uint32_t page_count = frame->PrintBegin(print_params);
+  EXPECT_EQ(1u, page_count);
   frame->PrintEnd();
 }
 
@@ -13038,7 +13038,7 @@
   WebSize page_size(500, 500);
   print_params.print_content_area.width = page_size.width;
   print_params.print_content_area.height = page_size.height;
-  EXPECT_EQ(1, frame->PrintBegin(print_params, WebNode()));
+  EXPECT_EQ(1u, frame->PrintBegin(print_params, WebNode()));
   PaintRecorder recorder;
   frame->PrintPagesForTesting(recorder.beginRecording(IntRect()), page_size,
                               page_size);
@@ -13117,7 +13117,7 @@
   print_params.print_content_area.width = page_size.width;
   print_params.print_content_area.height = page_size.height;
   WebLocalFrameImpl* frame = web_view_helper.LocalMainFrame();
-  EXPECT_EQ(1, frame->PrintBegin(print_params, WebNode()));
+  EXPECT_EQ(1u, frame->PrintBegin(print_params, WebNode()));
   PaintRecorder recorder;
   frame->PrintPagesForTesting(recorder.beginRecording(IntRect()), page_size,
                               page_size);
@@ -13365,7 +13365,7 @@
   WebPrintParams print_params;
   print_params.print_content_area.width = page_size.width;
   print_params.print_content_area.height = page_size.height;
-  EXPECT_EQ(4, frame->PrintBegin(print_params, WebNode()));
+  EXPECT_EQ(4u, frame->PrintBegin(print_params, WebNode()));
 
   WebPrintPageDescription description;
 
diff --git a/third_party/blink/renderer/core/exported/web_settings_impl.cc b/third_party/blink/renderer/core/exported/web_settings_impl.cc
index 8c3c00a3..eb5f606 100644
--- a/third_party/blink/renderer/core/exported/web_settings_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_settings_impl.cc
@@ -133,7 +133,7 @@
   settings_->SetMinimumLogicalFontSize(size);
 }
 
-void WebSettingsImpl::SetAutoplayPolicy(AutoplayPolicy policy) {
+void WebSettingsImpl::SetAutoplayPolicy(web_pref::AutoplayPolicy policy) {
   settings_->SetAutoplayPolicy(
       static_cast<blink::AutoplayPolicy::Type>(policy));
 }
diff --git a/third_party/blink/renderer/core/exported/web_settings_impl.h b/third_party/blink/renderer/core/exported/web_settings_impl.h
index e03f225..d796fea 100644
--- a/third_party/blink/renderer/core/exported/web_settings_impl.h
+++ b/third_party/blink/renderer/core/exported/web_settings_impl.h
@@ -50,7 +50,7 @@
   bool ShrinksViewportContentToFit() const override;
   bool ViewportEnabled() const override;
   void SetAccelerated2dCanvasMSAASampleCount(int) override;
-  void SetAutoplayPolicy(AutoplayPolicy) override;
+  void SetAutoplayPolicy(web_pref::AutoplayPolicy) override;
   void SetPreferCompositingToLCDTextEnabled(bool) override;
   void SetAccessibilityPasswordValuesEnabled(bool) override;
   void SetAllowFileAccessFromFileURLs(bool) override;
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index 4e5f756..4e29b67 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -34,19 +34,27 @@
 #include <utility>
 
 #include "base/auto_reset.h"
+#include "base/command_line.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "cc/layers/picture_layer.h"
+#include "media/base/media_switches.h"
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/common/input/web_input_event.h"
 #include "third_party/blink/public/common/input/web_menu_source_type.h"
 #include "third_party/blink/public/common/page/page_zoom.h"
+#include "third_party/blink/public/common/switches.h"
+#include "third_party/blink/public/common/web_preferences/web_preferences.h"
 #include "third_party/blink/public/mojom/input/focus_type.mojom-blink.h"
 #include "third_party/blink/public/platform/interface_registry.h"
+#include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
+#include "third_party/blink/public/platform/web_media_player.h"
+#include "third_party/blink/public/platform/web_network_state_notifier.h"
+#include "third_party/blink/public/platform/web_runtime_features.h"
 #include "third_party/blink/public/platform/web_text_input_info.h"
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/public/platform/web_vector.h"
@@ -161,9 +169,14 @@
 #include "third_party/blink/renderer/platform/scheduler/public/page_lifecycle_state.h"
 #include "third_party/blink/renderer/platform/scheduler/public/page_scheduler.h"
 #include "third_party/blink/renderer/platform/widget/widget_base.h"
+#include "third_party/icu/source/common/unicode/uscript.h"
 
 #include "ui/gfx/skia_util.h"
 
+#if defined(OS_ANDROID)
+#include "components/viz/common/features.h"
+#endif
+
 // Get rid of WTF's pow define so we can use std::pow.
 #undef pow
 #include <cmath>  // for std::pow
@@ -226,6 +239,147 @@
   void Invoke(ExecutionContext* execution_context, Event*) override {}
 };
 
+typedef void (*SetFontFamilyWrapper)(blink::WebSettings*,
+                                     const base::string16&,
+                                     UScriptCode);
+
+void SetStandardFontFamilyWrapper(WebSettings* settings,
+                                  const base::string16& font,
+                                  UScriptCode script) {
+  settings->SetStandardFontFamily(WebString::FromUTF16(font), script);
+}
+
+void SetFixedFontFamilyWrapper(WebSettings* settings,
+                               const base::string16& font,
+                               UScriptCode script) {
+  settings->SetFixedFontFamily(WebString::FromUTF16(font), script);
+}
+
+void SetSerifFontFamilyWrapper(WebSettings* settings,
+                               const base::string16& font,
+                               UScriptCode script) {
+  settings->SetSerifFontFamily(WebString::FromUTF16(font), script);
+}
+
+void SetSansSerifFontFamilyWrapper(WebSettings* settings,
+                                   const base::string16& font,
+                                   UScriptCode script) {
+  settings->SetSansSerifFontFamily(WebString::FromUTF16(font), script);
+}
+
+void SetCursiveFontFamilyWrapper(WebSettings* settings,
+                                 const base::string16& font,
+                                 UScriptCode script) {
+  settings->SetCursiveFontFamily(WebString::FromUTF16(font), script);
+}
+
+void SetFantasyFontFamilyWrapper(WebSettings* settings,
+                                 const base::string16& font,
+                                 UScriptCode script) {
+  settings->SetFantasyFontFamily(WebString::FromUTF16(font), script);
+}
+
+void SetPictographFontFamilyWrapper(WebSettings* settings,
+                                    const base::string16& font,
+                                    UScriptCode script) {
+  settings->SetPictographFontFamily(WebString::FromUTF16(font), script);
+}
+
+// If |scriptCode| is a member of a family of "similar" script codes, returns
+// the script code in that family that is used by WebKit for font selection
+// purposes.  For example, USCRIPT_KATAKANA_OR_HIRAGANA and USCRIPT_JAPANESE are
+// considered equivalent for the purposes of font selection.  WebKit uses the
+// script code USCRIPT_KATAKANA_OR_HIRAGANA.  So, if |scriptCode| is
+// USCRIPT_JAPANESE, the function returns USCRIPT_KATAKANA_OR_HIRAGANA.  WebKit
+// uses different scripts than the ones in Chrome pref names because the version
+// of ICU included on certain ports does not have some of the newer scripts.  If
+// |scriptCode| is not a member of such a family, returns |scriptCode|.
+UScriptCode GetScriptForWebSettings(UScriptCode scriptCode) {
+  switch (scriptCode) {
+    case USCRIPT_HIRAGANA:
+    case USCRIPT_KATAKANA:
+    case USCRIPT_JAPANESE:
+      return USCRIPT_KATAKANA_OR_HIRAGANA;
+    case USCRIPT_KOREAN:
+      return USCRIPT_HANGUL;
+    default:
+      return scriptCode;
+  }
+}
+
+void ApplyFontsFromMap(const web_pref::ScriptFontFamilyMap& map,
+                       SetFontFamilyWrapper setter,
+                       WebSettings* settings) {
+  for (auto& it : map) {
+    int32_t script = u_getPropertyValueEnum(UCHAR_SCRIPT, (it.first).c_str());
+    if (script >= 0 && script < USCRIPT_CODE_LIMIT) {
+      UScriptCode code = static_cast<UScriptCode>(script);
+      (*setter)(settings, it.second, GetScriptForWebSettings(code));
+    }
+  }
+}
+
+void ApplyCommandLineToSettings(WebSettings* settings) {
+  const base::CommandLine& command_line =
+      *base::CommandLine::ForCurrentProcess();
+
+  settings->SetThreadedScrollingEnabled(
+      !command_line.HasSwitch(switches::kDisableThreadedScrolling));
+
+  WebSettings::SelectionStrategyType selection_strategy;
+  if (command_line.GetSwitchValueASCII(switches::kTouchTextSelectionStrategy) ==
+      "direction")
+    selection_strategy = WebSettings::SelectionStrategyType::kDirection;
+  else
+    selection_strategy = WebSettings::SelectionStrategyType::kCharacter;
+  settings->SetSelectionStrategy(selection_strategy);
+
+  WebString passive_listeners_default = WebString::FromUTF8(
+      command_line.GetSwitchValueASCII(switches::kPassiveListenersDefault));
+  if (!passive_listeners_default.IsEmpty()) {
+    WebSettings::PassiveEventListenerDefault passive_default =
+        WebSettings::PassiveEventListenerDefault::kFalse;
+    if (passive_listeners_default == "true")
+      passive_default = WebSettings::PassiveEventListenerDefault::kTrue;
+    else if (passive_listeners_default == "forcealltrue")
+      passive_default = WebSettings::PassiveEventListenerDefault::kForceAllTrue;
+    settings->SetPassiveEventListenerDefault(passive_default);
+  }
+
+  WebString network_quiet_timeout = WebString::FromUTF8(
+      command_line.GetSwitchValueASCII(switches::kNetworkQuietTimeout));
+  if (!network_quiet_timeout.IsEmpty()) {
+    bool ok;
+    double network_quiet_timeout_seconds =
+        String(network_quiet_timeout).ToDouble(&ok);
+    if (ok)
+      settings->SetNetworkQuietTimeout(network_quiet_timeout_seconds);
+  }
+
+  if (command_line.HasSwitch(switches::kBlinkSettings)) {
+    Vector<String> blink_settings;
+    String command_line_settings =
+        command_line.GetSwitchValueASCII(switches::kBlinkSettings).c_str();
+    command_line_settings.Split(",", blink_settings);
+    for (const String& setting : blink_settings) {
+      wtf_size_t pos = setting.find('=');
+      settings->SetFromStrings(
+          WebString(setting.Substring(0, pos)),
+          WebString(pos == kNotFound ? "" : setting.Substring(pos + 1)));
+    }
+  }
+}
+
+WebMediaPlayer::SurfaceLayerMode GetVideoSurfaceLayerMode() {
+#if defined(OS_ANDROID)
+  if (base::FeatureList::IsEnabled(media::kDisableSurfaceLayerForVideo) &&
+      !::features::IsUsingVizForWebView())
+    return WebMediaPlayer::SurfaceLayerMode::kNever;
+#endif  // OS_ANDROID
+
+  return WebMediaPlayer::SurfaceLayerMode::kAlways;
+}
+
 }  // namespace
 
 // WebView ----------------------------------------------------------------
@@ -1705,6 +1859,399 @@
                                     .Unalias());
 }
 
+// static
+void WebView::ApplyWebPreferences(const web_pref::WebPreferences& prefs,
+                                  WebView* web_view) {
+  WebSettings* settings = web_view->GetSettings();
+  ApplyFontsFromMap(prefs.standard_font_family_map,
+                    SetStandardFontFamilyWrapper, settings);
+  ApplyFontsFromMap(prefs.fixed_font_family_map, SetFixedFontFamilyWrapper,
+                    settings);
+  ApplyFontsFromMap(prefs.serif_font_family_map, SetSerifFontFamilyWrapper,
+                    settings);
+  ApplyFontsFromMap(prefs.sans_serif_font_family_map,
+                    SetSansSerifFontFamilyWrapper, settings);
+  ApplyFontsFromMap(prefs.cursive_font_family_map, SetCursiveFontFamilyWrapper,
+                    settings);
+  ApplyFontsFromMap(prefs.fantasy_font_family_map, SetFantasyFontFamilyWrapper,
+                    settings);
+  ApplyFontsFromMap(prefs.pictograph_font_family_map,
+                    SetPictographFontFamilyWrapper, settings);
+  settings->SetDefaultFontSize(prefs.default_font_size);
+  settings->SetDefaultFixedFontSize(prefs.default_fixed_font_size);
+  settings->SetMinimumFontSize(prefs.minimum_font_size);
+  settings->SetMinimumLogicalFontSize(prefs.minimum_logical_font_size);
+  settings->SetDefaultTextEncodingName(
+      WebString::FromASCII(prefs.default_encoding));
+  settings->SetJavaScriptEnabled(prefs.javascript_enabled);
+  settings->SetWebSecurityEnabled(prefs.web_security_enabled);
+  settings->SetLoadsImagesAutomatically(prefs.loads_images_automatically);
+  settings->SetImagesEnabled(prefs.images_enabled);
+  settings->SetPluginsEnabled(prefs.plugins_enabled);
+  settings->SetDOMPasteAllowed(prefs.dom_paste_enabled);
+  settings->SetTextAreasAreResizable(prefs.text_areas_are_resizable);
+  settings->SetAllowScriptsToCloseWindows(prefs.allow_scripts_to_close_windows);
+  settings->SetDownloadableBinaryFontsEnabled(prefs.remote_fonts_enabled);
+  settings->SetJavaScriptCanAccessClipboard(
+      prefs.javascript_can_access_clipboard);
+  WebRuntimeFeatures::EnableXSLT(prefs.xslt_enabled);
+  settings->SetDNSPrefetchingEnabled(prefs.dns_prefetching_enabled);
+  blink::WebNetworkStateNotifier::SetSaveDataEnabled(prefs.data_saver_enabled);
+  settings->SetLocalStorageEnabled(prefs.local_storage_enabled);
+  settings->SetSyncXHRInDocumentsEnabled(prefs.sync_xhr_in_documents_enabled);
+  WebRuntimeFeatures::EnableDatabase(prefs.databases_enabled);
+  settings->SetOfflineWebApplicationCacheEnabled(
+      prefs.application_cache_enabled);
+  settings->SetShouldProtectAgainstIpcFlooding(
+      !prefs.disable_ipc_flooding_protection);
+  settings->SetHyperlinkAuditingEnabled(prefs.hyperlink_auditing_enabled);
+  settings->SetCookieEnabled(prefs.cookie_enabled);
+  settings->SetNavigateOnDragDrop(prefs.navigate_on_drag_drop);
+
+  // By default, allow_universal_access_from_file_urls is set to false and thus
+  // we mitigate attacks from local HTML files by not granting file:// URLs
+  // universal access. Only test shell will enable this.
+  settings->SetAllowUniversalAccessFromFileURLs(
+      prefs.allow_universal_access_from_file_urls);
+  settings->SetAllowFileAccessFromFileURLs(
+      prefs.allow_file_access_from_file_urls);
+
+  settings->SetWebGL1Enabled(prefs.webgl1_enabled);
+  settings->SetWebGL2Enabled(prefs.webgl2_enabled);
+
+  // Enable WebGL errors to the JS console if requested.
+  settings->SetWebGLErrorsToConsoleEnabled(
+      prefs.webgl_errors_to_console_enabled);
+
+  settings->SetHideScrollbars(prefs.hide_scrollbars);
+
+  // Enable gpu-accelerated 2d canvas if requested on the command line.
+  WebRuntimeFeatures::EnableAccelerated2dCanvas(
+      prefs.accelerated_2d_canvas_enabled);
+
+  // Enable new canvas 2d api features
+  WebRuntimeFeatures::EnableNewCanvas2DAPI(prefs.new_canvas_2d_api_enabled);
+
+  // Disable antialiasing for 2d canvas if requested on the command line.
+  settings->SetAntialiased2dCanvasEnabled(
+      !prefs.antialiased_2d_canvas_disabled);
+
+  // Disable antialiasing of clips for 2d canvas if requested on the command
+  // line.
+  settings->SetAntialiasedClips2dCanvasEnabled(
+      prefs.antialiased_clips_2d_canvas_enabled);
+
+  // Tabs to link is not part of the settings. WebCore calls
+  // ChromeClient::tabsToLinks which is part of the glue code.
+  web_view->SetTabsToLinks(prefs.tabs_to_links);
+
+  settings->SetAllowRunningOfInsecureContent(
+      prefs.allow_running_insecure_content);
+  settings->SetDisableReadingFromCanvas(prefs.disable_reading_from_canvas);
+  settings->SetStrictMixedContentChecking(prefs.strict_mixed_content_checking);
+
+  settings->SetStrictlyBlockBlockableMixedContent(
+      prefs.strictly_block_blockable_mixed_content);
+
+  settings->SetStrictMixedContentCheckingForPlugin(
+      prefs.block_mixed_plugin_content);
+
+  settings->SetStrictPowerfulFeatureRestrictions(
+      prefs.strict_powerful_feature_restrictions);
+  settings->SetAllowGeolocationOnInsecureOrigins(
+      prefs.allow_geolocation_on_insecure_origins);
+  settings->SetPasswordEchoEnabled(prefs.password_echo_enabled);
+  settings->SetShouldPrintBackgrounds(prefs.should_print_backgrounds);
+  settings->SetShouldClearDocumentBackground(
+      prefs.should_clear_document_background);
+  settings->SetEnableScrollAnimator(prefs.enable_scroll_animator);
+  settings->SetPrefersReducedMotion(prefs.prefers_reduced_motion);
+
+  WebRuntimeFeatures::EnableTouchEventFeatureDetection(
+      prefs.touch_event_feature_detection_enabled);
+  settings->SetMaxTouchPoints(prefs.pointer_events_max_touch_points);
+  settings->SetAvailablePointerTypes(prefs.available_pointer_types);
+  settings->SetPrimaryPointerType(
+      static_cast<blink::PointerType>(prefs.primary_pointer_type));
+  settings->SetAvailableHoverTypes(prefs.available_hover_types);
+  settings->SetPrimaryHoverType(
+      static_cast<blink::HoverType>(prefs.primary_hover_type));
+  settings->SetBarrelButtonForDragEnabled(prefs.barrel_button_for_drag_enabled);
+
+  settings->SetEditingBehavior(
+      static_cast<WebSettings::EditingBehavior>(prefs.editing_behavior));
+
+  settings->SetSupportsMultipleWindows(prefs.supports_multiple_windows);
+
+  settings->SetMainFrameClipsContent(!prefs.record_whole_document);
+
+  settings->SetSmartInsertDeleteEnabled(prefs.smart_insert_delete_enabled);
+
+  settings->SetSpatialNavigationEnabled(prefs.spatial_navigation_enabled);
+  // Spatnav depends on KeyboardFocusableScrollers. The WebUI team has
+  // disabled KFS because they need more time to update their custom elements,
+  // crbug.com/907284. Meanwhile, we pre-ship KFS to spatnav users.
+  if (prefs.spatial_navigation_enabled)
+    WebRuntimeFeatures::EnableKeyboardFocusableScrollers(true);
+
+  settings->SetSelectionIncludesAltImageText(true);
+
+  settings->SetV8CacheOptions(
+      static_cast<WebSettings::V8CacheOptions>(prefs.v8_cache_options));
+
+  settings->SetImageAnimationPolicy(
+      static_cast<WebSettings::ImageAnimationPolicy>(prefs.animation_policy));
+
+  settings->SetPresentationRequiresUserGesture(
+      prefs.user_gesture_required_for_presentation);
+
+  if (prefs.text_tracks_enabled) {
+    settings->SetTextTrackKindUserPreference(
+        WebSettings::TextTrackKindUserPreference::kCaptions);
+  } else {
+    settings->SetTextTrackKindUserPreference(
+        WebSettings::TextTrackKindUserPreference::kDefault);
+  }
+  settings->SetTextTrackBackgroundColor(
+      WebString::FromASCII(prefs.text_track_background_color));
+  settings->SetTextTrackTextColor(
+      WebString::FromASCII(prefs.text_track_text_color));
+  settings->SetTextTrackTextSize(
+      WebString::FromASCII(prefs.text_track_text_size));
+  settings->SetTextTrackTextShadow(
+      WebString::FromASCII(prefs.text_track_text_shadow));
+  settings->SetTextTrackFontFamily(
+      WebString::FromASCII(prefs.text_track_font_family));
+  settings->SetTextTrackFontStyle(
+      WebString::FromASCII(prefs.text_track_font_style));
+  settings->SetTextTrackFontVariant(
+      WebString::FromASCII(prefs.text_track_font_variant));
+  settings->SetTextTrackMarginPercentage(prefs.text_track_margin_percentage);
+  settings->SetTextTrackWindowColor(
+      WebString::FromASCII(prefs.text_track_window_color));
+  settings->SetTextTrackWindowPadding(
+      WebString::FromASCII(prefs.text_track_window_padding));
+  settings->SetTextTrackWindowRadius(
+      WebString::FromASCII(prefs.text_track_window_radius));
+
+  // Needs to happen before SetDefaultPageScaleLimits below since that'll
+  // recalculate the final page scale limits and that depends on this setting.
+  settings->SetShrinksViewportContentToFit(
+      prefs.shrinks_viewport_contents_to_fit);
+
+  // Needs to happen before SetIgnoreViewportTagScaleLimits below.
+  web_view->SetDefaultPageScaleLimits(prefs.default_minimum_page_scale_factor,
+                                      prefs.default_maximum_page_scale_factor);
+
+  settings->SetFullscreenSupported(prefs.fullscreen_supported);
+  settings->SetTextAutosizingEnabled(prefs.text_autosizing_enabled);
+  settings->SetDoubleTapToZoomEnabled(prefs.double_tap_to_zoom_enabled);
+  blink::WebNetworkStateNotifier::SetNetworkQualityWebHoldback(
+      static_cast<blink::WebEffectiveConnectionType>(
+          prefs.network_quality_estimator_web_holdback));
+
+  settings->SetDontSendKeyEventsToJavascript(
+      prefs.dont_send_key_events_to_javascript);
+  settings->SetWebAppScope(WebString::FromASCII(prefs.web_app_scope.spec()));
+
+#if defined(OS_ANDROID)
+  settings->SetAllowCustomScrollbarInMainFrame(false);
+  settings->SetAccessibilityFontScaleFactor(prefs.font_scale_factor);
+  settings->SetDeviceScaleAdjustment(prefs.device_scale_adjustment);
+  web_view->SetIgnoreViewportTagScaleLimits(prefs.force_enable_zoom);
+  settings->SetAutoZoomFocusedNodeToLegibleScale(true);
+  settings->SetDefaultVideoPosterURL(
+      WebString::FromASCII(prefs.default_video_poster_url.spec()));
+  settings->SetSupportDeprecatedTargetDensityDPI(
+      prefs.support_deprecated_target_density_dpi);
+  settings->SetUseLegacyBackgroundSizeShorthandBehavior(
+      prefs.use_legacy_background_size_shorthand_behavior);
+  settings->SetWideViewportQuirkEnabled(prefs.wide_viewport_quirk);
+  settings->SetUseWideViewport(prefs.use_wide_viewport);
+  settings->SetForceZeroLayoutHeight(prefs.force_zero_layout_height);
+  settings->SetViewportMetaMergeContentQuirk(
+      prefs.viewport_meta_merge_content_quirk);
+  settings->SetViewportMetaNonUserScalableQuirk(
+      prefs.viewport_meta_non_user_scalable_quirk);
+  settings->SetViewportMetaZeroValuesQuirk(
+      prefs.viewport_meta_zero_values_quirk);
+  settings->SetClobberUserAgentInitialScaleQuirk(
+      prefs.clobber_user_agent_initial_scale_quirk);
+  settings->SetIgnoreMainFrameOverflowHiddenQuirk(
+      prefs.ignore_main_frame_overflow_hidden_quirk);
+  settings->SetReportScreenSizeInPhysicalPixelsQuirk(
+      prefs.report_screen_size_in_physical_pixels_quirk);
+  settings->SetShouldReuseGlobalForUnownedMainFrame(
+      prefs.reuse_global_for_unowned_main_frame);
+  settings->SetPreferHiddenVolumeControls(true);
+  settings->SetSpellCheckEnabledByDefault(prefs.spellcheck_enabled_by_default);
+
+  WebRuntimeFeatures::EnableVideoFullscreenOrientationLock(
+      prefs.video_fullscreen_orientation_lock_enabled);
+  WebRuntimeFeatures::EnableVideoRotateToFullscreen(
+      prefs.video_rotate_to_fullscreen_enabled);
+  settings->SetEmbeddedMediaExperienceEnabled(
+      prefs.embedded_media_experience_enabled);
+  settings->SetImmersiveModeEnabled(prefs.immersive_mode_enabled);
+  settings->SetDoNotUpdateSelectionOnMutatingSelectionRange(
+      prefs.do_not_update_selection_on_mutating_selection_range);
+  WebRuntimeFeatures::EnableCSSHexAlphaColor(prefs.css_hex_alpha_color_enabled);
+  WebRuntimeFeatures::EnableScrollTopLeftInterop(
+      prefs.scroll_top_left_interop_enabled);
+  WebRuntimeFeatures::EnableSurfaceEmbeddingFeatures(
+      !prefs.disable_features_depending_on_viz);
+  WebRuntimeFeatures::EnableAcceleratedSmallCanvases(
+      !prefs.disable_accelerated_small_canvases);
+  if (prefs.reenable_web_components_v0) {
+    WebRuntimeFeatures::EnableShadowDOMV0(true);
+    WebRuntimeFeatures::EnableCustomElementsV0(true);
+    WebRuntimeFeatures::EnableHTMLImports(true);
+  }
+#endif  // defined(OS_ANDROID)
+  settings->SetForceDarkModeEnabled(prefs.force_dark_mode_enabled);
+
+  settings->SetAccessibilityAlwaysShowFocus(prefs.always_show_focus);
+  settings->SetAutoplayPolicy(prefs.autoplay_policy);
+  settings->SetViewportEnabled(prefs.viewport_enabled);
+  settings->SetViewportMetaEnabled(prefs.viewport_meta_enabled);
+  settings->SetViewportStyle(
+      static_cast<blink::WebViewportStyle>(prefs.viewport_style));
+
+  settings->SetLoadWithOverviewMode(prefs.initialize_at_minimum_page_scale);
+  settings->SetMainFrameResizesAreOrientationChanges(
+      prefs.main_frame_resizes_are_orientation_changes);
+
+  settings->SetShowContextMenuOnMouseUp(prefs.context_menu_on_mouse_up);
+  settings->SetAlwaysShowContextMenuOnTouch(
+      prefs.always_show_context_menu_on_touch);
+  settings->SetSmoothScrollForFindEnabled(prefs.smooth_scroll_for_find_enabled);
+
+  settings->SetHideDownloadUI(prefs.hide_download_ui);
+
+  settings->SetPresentationReceiver(prefs.presentation_receiver);
+
+  settings->SetMediaControlsEnabled(prefs.media_controls_enabled);
+
+  settings->SetLowPriorityIframesThreshold(
+      static_cast<blink::WebEffectiveConnectionType>(
+          prefs.low_priority_iframes_threshold));
+
+  settings->SetPictureInPictureEnabled(
+      prefs.picture_in_picture_enabled &&
+      GetVideoSurfaceLayerMode() !=
+          blink::WebMediaPlayer::SurfaceLayerMode::kNever);
+
+  settings->SetDataSaverHoldbackWebApi(
+      prefs.data_saver_holdback_web_api_enabled);
+
+  settings->SetLazyLoadEnabled(prefs.lazy_load_enabled);
+  settings->SetPreferredColorScheme(prefs.preferred_color_scheme);
+
+  for (const auto& ect_distance_pair :
+       prefs.lazy_frame_loading_distance_thresholds_px) {
+    switch (ect_distance_pair.first) {
+      case net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN:
+        settings->SetLazyFrameLoadingDistanceThresholdPxUnknown(
+            ect_distance_pair.second);
+        continue;
+      case net::EFFECTIVE_CONNECTION_TYPE_OFFLINE:
+        settings->SetLazyFrameLoadingDistanceThresholdPxOffline(
+            ect_distance_pair.second);
+        continue;
+      case net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G:
+        settings->SetLazyFrameLoadingDistanceThresholdPxSlow2G(
+            ect_distance_pair.second);
+        continue;
+      case net::EFFECTIVE_CONNECTION_TYPE_2G:
+        settings->SetLazyFrameLoadingDistanceThresholdPx2G(
+            ect_distance_pair.second);
+        continue;
+      case net::EFFECTIVE_CONNECTION_TYPE_3G:
+        settings->SetLazyFrameLoadingDistanceThresholdPx3G(
+            ect_distance_pair.second);
+        continue;
+      case net::EFFECTIVE_CONNECTION_TYPE_4G:
+        settings->SetLazyFrameLoadingDistanceThresholdPx4G(
+            ect_distance_pair.second);
+        continue;
+      case net::EFFECTIVE_CONNECTION_TYPE_LAST:
+        continue;
+    }
+    NOTREACHED();
+  }
+
+  for (const auto& ect_distance_pair :
+       prefs.lazy_image_loading_distance_thresholds_px) {
+    switch (ect_distance_pair.first) {
+      case net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN:
+        settings->SetLazyImageLoadingDistanceThresholdPxUnknown(
+            ect_distance_pair.second);
+        continue;
+      case net::EFFECTIVE_CONNECTION_TYPE_OFFLINE:
+        settings->SetLazyImageLoadingDistanceThresholdPxOffline(
+            ect_distance_pair.second);
+        continue;
+      case net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G:
+        settings->SetLazyImageLoadingDistanceThresholdPxSlow2G(
+            ect_distance_pair.second);
+        continue;
+      case net::EFFECTIVE_CONNECTION_TYPE_2G:
+        settings->SetLazyImageLoadingDistanceThresholdPx2G(
+            ect_distance_pair.second);
+        continue;
+      case net::EFFECTIVE_CONNECTION_TYPE_3G:
+        settings->SetLazyImageLoadingDistanceThresholdPx3G(
+            ect_distance_pair.second);
+        continue;
+      case net::EFFECTIVE_CONNECTION_TYPE_4G:
+        settings->SetLazyImageLoadingDistanceThresholdPx4G(
+            ect_distance_pair.second);
+        continue;
+      case net::EFFECTIVE_CONNECTION_TYPE_LAST:
+        continue;
+    }
+    NOTREACHED();
+  }
+
+  for (const auto& fully_load_k_pair : prefs.lazy_image_first_k_fully_load) {
+    switch (fully_load_k_pair.first) {
+      case net::EFFECTIVE_CONNECTION_TYPE_OFFLINE:
+        continue;
+      case net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN:
+        settings->SetLazyImageFirstKFullyLoadUnknown(fully_load_k_pair.second);
+        continue;
+      case net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G:
+        settings->SetLazyImageFirstKFullyLoadSlow2G(fully_load_k_pair.second);
+        continue;
+      case net::EFFECTIVE_CONNECTION_TYPE_2G:
+        settings->SetLazyImageFirstKFullyLoad2G(fully_load_k_pair.second);
+        continue;
+      case net::EFFECTIVE_CONNECTION_TYPE_3G:
+        settings->SetLazyImageFirstKFullyLoad3G(fully_load_k_pair.second);
+        continue;
+      case net::EFFECTIVE_CONNECTION_TYPE_4G:
+        settings->SetLazyImageFirstKFullyLoad4G(fully_load_k_pair.second);
+        continue;
+      case net::EFFECTIVE_CONNECTION_TYPE_LAST:
+        continue;
+    }
+    NOTREACHED();
+  }
+
+  settings->SetTouchDragDropEnabled(prefs.touch_drag_drop_enabled);
+  settings->SetTouchDragEndContextMenu(prefs.touch_dragend_context_menu);
+
+#if defined(OS_MAC)
+  web_view->SetMaximumLegibleScale(prefs.default_maximum_page_scale_factor);
+#endif
+
+#if defined(OS_WIN)
+  WebRuntimeFeatures::EnableMiddleClickAutoscroll(true);
+#endif
+
+  WebRuntimeFeatures::EnableTranslateService(prefs.translate_service_available);
+}
+
 void WebViewImpl::ThemeChanged() {
   if (!GetPage())
     return;
@@ -3252,6 +3799,22 @@
     web_widget_->SetIsNestedMainFrameWidget(inside_portal);
 }
 
+void WebViewImpl::SetWebPreferences(
+    const web_pref::WebPreferences& preferences) {
+  UpdateWebPreferences(preferences);
+}
+
+const web_pref::WebPreferences& WebViewImpl::GetWebPreferences() {
+  return web_preferences_;
+}
+
+void WebViewImpl::UpdateWebPreferences(
+    const blink::web_pref::WebPreferences& preferences) {
+  web_preferences_ = preferences;
+  ApplyWebPreferences(preferences, this);
+  ApplyCommandLineToSettings(SettingsImpl());
+}
+
 void WebViewImpl::SetIsActive(bool active) {
   if (GetPage())
     GetPage()->GetFocusController().SetActive(active);
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.h b/third_party/blink/renderer/core/exported/web_view_impl.h
index 694a1483..f34f9631 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.h
+++ b/third_party/blink/renderer/core/exported/web_view_impl.h
@@ -215,6 +215,8 @@
   void SetDeviceColorSpaceForTesting(
       const gfx::ColorSpace& color_space) override;
   void PaintContent(cc::PaintCanvas*, const gfx::Rect&) override;
+  void SetWebPreferences(const web_pref::WebPreferences& preferences) override;
+  const web_pref::WebPreferences& GetWebPreferences() override;
 
   // Overrides the page's background and base background color. You
   // can use this to enforce a transparent background, which is useful if you
@@ -537,6 +539,9 @@
   // browser.
   void DoDeferredCloseWindowSoon();
 
+  // Applies blink related preferences to this view.
+  void UpdateWebPreferences(const blink::web_pref::WebPreferences& preferences);
+
   WebViewImpl(
       WebViewClient*,
       mojom::blink::PageVisibilityState visibility,
@@ -771,6 +776,8 @@
 
   Persistent<EventListener> popup_mouse_wheel_event_listener_;
 
+  web_pref::WebPreferences web_preferences_;
+
   // The local root whose document has |popup_mouse_wheel_event_listener_|
   // registered.
   WeakPersistent<WebLocalFrameImpl> local_root_with_empty_mouse_wheel_listener_;
diff --git a/third_party/blink/renderer/core/frame/BUILD.gn b/third_party/blink/renderer/core/frame/BUILD.gn
index 01b1e7c..b67b7f28 100644
--- a/third_party/blink/renderer/core/frame/BUILD.gn
+++ b/third_party/blink/renderer/core/frame/BUILD.gn
@@ -231,6 +231,7 @@
   }
 
   deps = [
+    "//printing/buildflags",
     "//skia",
     "//ui/accessibility:ax_base",
     "//ui/base/cursor:cursor_base",
diff --git a/third_party/blink/renderer/core/frame/find_in_page.cc b/third_party/blink/renderer/core/frame/find_in_page.cc
index e0f493d..d0b2265c 100644
--- a/third_party/blink/renderer/core/frame/find_in_page.cc
+++ b/third_party/blink/renderer/core/frame/find_in_page.cc
@@ -103,7 +103,8 @@
 
   // Search for an active match only if this frame is focused or if this is an
   // existing session.
-  if (frame_->IsFocused() || !options->new_session) {
+  if (options->find_match &&
+      (frame_->IsFocused() || !options->new_session)) {
     result = FindInternal(request_id, search_text, *options,
                           false /* wrap_within_frame */, &active_now);
   }
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
index aeeb276..9421eda 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -292,7 +292,7 @@
     PrintContext::BeginPrintMode(printed_page_width_, height);
   }
 
-  virtual float GetPageShrink(int page_number) const {
+  virtual float GetPageShrink(uint32_t page_number) const {
     IntRect page_rect = page_rects_[page_number];
     return printed_page_width_ / page_rect.Width();
   }
@@ -488,7 +488,7 @@
 
   void EndPrintMode() override { plugin_->PrintEnd(); }
 
-  float GetPageShrink(int page_number) const override {
+  float GetPageShrink(uint32_t page_number) const override {
     // We don't shrink the page (maybe we should ask the widget ??)
     return 1.0;
   }
@@ -1626,8 +1626,8 @@
   return plugin_container ? plugin_container->Plugin() : nullptr;
 }
 
-int WebLocalFrameImpl::PrintBegin(const WebPrintParams& print_params,
-                                  const WebNode& constrain_to_node) {
+uint32_t WebLocalFrameImpl::PrintBegin(const WebPrintParams& print_params,
+                                       const WebNode& constrain_to_node) {
   WebPluginContainerImpl* plugin_container =
       GetPluginToPrintHelper(constrain_to_node);
   if (plugin_container && plugin_container->SupportsPaginatedPrint()) {
@@ -1643,18 +1643,16 @@
   print_context_->BeginPrintMode(size.Width(), size.Height());
   print_context_->ComputePageRects(size);
 
-  return static_cast<int>(print_context_->PageCount());
+  return print_context_->PageCount();
 }
 
-float WebLocalFrameImpl::GetPrintPageShrink(int page) {
+float WebLocalFrameImpl::GetPrintPageShrink(uint32_t page) {
   DCHECK(print_context_);
-  DCHECK_GE(page, 0);
   return print_context_->GetPageShrink(page);
 }
 
-float WebLocalFrameImpl::PrintPage(int page, cc::PaintCanvas* canvas) {
+float WebLocalFrameImpl::PrintPage(uint32_t page, cc::PaintCanvas* canvas) {
   DCHECK(print_context_);
-  DCHECK_GE(page, 0);
   DCHECK(GetFrame());
   DCHECK(GetFrame()->GetDocument());
 
@@ -1697,22 +1695,22 @@
   return success;
 }
 
-PageSizeType WebLocalFrameImpl::GetPageSizeType(int page_index) {
+PageSizeType WebLocalFrameImpl::GetPageSizeType(uint32_t page_index) {
   return GetFrame()->GetDocument()->StyleForPage(page_index)->GetPageSizeType();
 }
 
 void WebLocalFrameImpl::GetPageDescription(
-    int page_index,
+    uint32_t page_index,
     WebPrintPageDescription* description) {
   GetFrame()->GetDocument()->GetPageDescription(page_index, description);
 }
 
 WebSize WebLocalFrameImpl::SpoolSizeInPixelsForTesting(
     const WebSize& page_size_in_pixels,
-    int page_count) {
+    uint32_t page_count) {
   int spool_width = page_size_in_pixels.width;
   int spool_height = 0;
-  for (int page_index = 0; page_index < page_count; page_index++) {
+  for (uint32_t page_index = 0; page_index < page_count; page_index++) {
     // Make room for the 1px tall page separator.
     if (page_index)
       spool_height++;
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.h b/third_party/blink/renderer/core/frame/web_local_frame_impl.h
index 34f3fa3..69f7deb 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.h
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.h
@@ -143,8 +143,9 @@
                          bool had_redirect,
                          const WebSourceLocation&) override;
   void SendOrientationChangeEvent() override;
-  PageSizeType GetPageSizeType(int page_index) override;
-  void GetPageDescription(int page_index, WebPrintPageDescription*) override;
+  PageSizeType GetPageSizeType(uint32_t page_index) override;
+  void GetPageDescription(uint32_t page_index,
+                          WebPrintPageDescription*) override;
   void ExecuteScript(const WebScriptSource&) override;
   void ExecuteScriptInIsolatedWorld(int32_t world_id,
                                     const WebScriptSource&) override;
@@ -279,10 +280,10 @@
   void DispatchBeforePrintEvent(
       base::WeakPtr<WebPrintClient> print_client) override;
   WebPlugin* GetPluginToPrint(const WebNode& constrain_to_node) override;
-  int PrintBegin(const WebPrintParams&,
-                 const WebNode& constrain_to_node) override;
-  float GetPrintPageShrink(int page) override;
-  float PrintPage(int page_to_print, cc::PaintCanvas*) override;
+  uint32_t PrintBegin(const WebPrintParams&,
+                      const WebNode& constrain_to_node) override;
+  float GetPrintPageShrink(uint32_t page) override;
+  float PrintPage(uint32_t page_to_print, cc::PaintCanvas*) override;
   void PrintEnd() override;
   void DispatchAfterPrintEvent() override;
   bool GetPrintPresetOptionsForPlugin(const WebNode&,
@@ -295,7 +296,7 @@
   bool IsAdSubframe() const override;
   void SetIsAdSubframe(blink::mojom::AdFrameType ad_frame_type) override;
   WebSize SpoolSizeInPixelsForTesting(const WebSize& page_size_in_pixels,
-                                      int page_count) override;
+                                      uint32_t page_count) override;
   void PrintPagesForTesting(cc::PaintCanvas*,
                             const WebSize& page_size_in_pixels,
                             const WebSize& spool_size_in_pixels) override;
diff --git a/third_party/blink/renderer/core/html/custom/element_internals.cc b/third_party/blink/renderer/core/html/custom/element_internals.cc
index 9f6f846d..f579182 100644
--- a/third_party/blink/renderer/core/html/custom/element_internals.cc
+++ b/third_party/blink/renderer/core/html/custom/element_internals.cc
@@ -239,7 +239,10 @@
 }
 
 ShadowRoot* ElementInternals::shadowRoot() const {
-  return Target().AuthorShadowRoot();
+  if (ShadowRoot* shadow_root = Target().AuthorShadowRoot()) {
+    return shadow_root->IsAvailableToElementInternals() ? shadow_root : nullptr;
+  }
+  return nullptr;
 }
 
 const AtomicString& ElementInternals::FastGetAttribute(
diff --git a/third_party/blink/renderer/core/html/media/autoplay_policy.cc b/third_party/blink/renderer/core/html/media/autoplay_policy.cc
index b7ec37b..8ae33d3 100644
--- a/third_party/blink/renderer/core/html/media/autoplay_policy.cc
+++ b/third_party/blink/renderer/core/html/media/autoplay_policy.cc
@@ -395,11 +395,11 @@
   visitor->Trace(autoplay_uma_helper_);
 }
 
-STATIC_ASSERT_ENUM(WebSettings::AutoplayPolicy::kNoUserGestureRequired,
+STATIC_ASSERT_ENUM(web_pref::AutoplayPolicy::kNoUserGestureRequired,
                    AutoplayPolicy::Type::kNoUserGestureRequired);
-STATIC_ASSERT_ENUM(WebSettings::AutoplayPolicy::kUserGestureRequired,
+STATIC_ASSERT_ENUM(web_pref::AutoplayPolicy::kUserGestureRequired,
                    AutoplayPolicy::Type::kUserGestureRequired);
-STATIC_ASSERT_ENUM(WebSettings::AutoplayPolicy::kDocumentUserActivationRequired,
+STATIC_ASSERT_ENUM(web_pref::AutoplayPolicy::kDocumentUserActivationRequired,
                    AutoplayPolicy::Type::kDocumentUserActivationRequired);
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.cc b/third_party/blink/renderer/core/html/media/html_media_element.cc
index 472617e..173b185a 100644
--- a/third_party/blink/renderer/core/html/media/html_media_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_media_element.cc
@@ -1219,9 +1219,11 @@
   media_source_attachment_ =
       MediaSourceAttachment::LookupMediaSource(url.GetString());
   if (media_source_attachment_) {
+    bool start_result = false;
     media_source_tracer_ =
-        media_source_attachment_->StartAttachingToMediaElement(this);
-    if (media_source_tracer_) {
+        media_source_attachment_->StartAttachingToMediaElement(this,
+                                                               &start_result);
+    if (start_result) {
       // If the associated feature is enabled, auto-revoke the MediaSource
       // object URL that was used for attachment on successful (start of)
       // attachment. This can help reduce memory bloat later if the app does not
@@ -1236,6 +1238,7 @@
       // Forget our reference to the MediaSourceAttachment, so we leave it alone
       // while processing remainder of load failure.
       media_source_attachment_.reset();
+      media_source_tracer_ = nullptr;
       attempt_load = false;
     }
   }
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.h b/third_party/blink/renderer/core/html/media/html_media_element.h
index a2987be..550e6d0 100644
--- a/third_party/blink/renderer/core/html/media/html_media_element.h
+++ b/third_party/blink/renderer/core/html/media/html_media_element.h
@@ -640,7 +640,8 @@
   // of the attachment (same-thread vs cross-thread, for instance) must be the
   // same semantic as the actual derived type of the tracer. Further, if there
   // is no attachment, then there must be no tracer that's tracking an active
-  // attachment.
+  // attachment. Note that some kinds of attachments do not require a tracer;
+  // see MediaSourceAttachment::StartAttachingToMediaElement() for details.
   scoped_refptr<MediaSourceAttachment> media_source_attachment_;
   Member<MediaSourceTracer> media_source_tracer_;
 
diff --git a/third_party/blink/renderer/core/html/media/media_source_attachment.h b/third_party/blink/renderer/core/html/media/media_source_attachment.h
index 2052e5b6..851c43a 100644
--- a/third_party/blink/renderer/core/html/media/media_source_attachment.h
+++ b/third_party/blink/renderer/core/html/media/media_source_attachment.h
@@ -19,7 +19,6 @@
 
 class HTMLMediaElement;
 class MediaSourceRegistry;
-class TimeRanges;
 class TrackBase;
 class WebMediaSource;
 
@@ -68,40 +67,46 @@
   // attempting to attach to the MediaSource object using this attachment
   // instance. The WebMediaSource is not available to the element initially, so
   // between the two calls, the attachment could be considered partially setup.
-  // If already attached, StartAttachingToMediaElement() returns nullptr.
+  // If attachment start fails (for example, if the underlying MediaSource is
+  // already attached, or if this attachment has already been unregistered from
+  // the MediaSourceRegistry), StartAttachingToMediaElement() sets |*success|
+  // false and returns nullptr. |success| must not be nullptr.
   // Otherwise, the underlying MediaSource must be in 'closed' state, and
-  // indicates success by returning a tracer object useful in at least
-  // same-thread attachments for enabling automatic idle unreferenced
-  // same-thread attachment object garbage collection.
+  // indicates success by setting |*success| true and optionally returning a
+  // tracer object useful in at least same-thread attachments for enabling
+  // automatic idle unreferenced same-thread attachment object garbage
+  // collection. Note that that tracer could be nullptr even if attachment start
+  // was successful, for instance in a cross-thread attachment where there is no
+  // tracer.
   // CompleteAttachingToMediaElement() provides the attached MediaSource with
   // the underlying WebMediaSource, enabling parsing of media provided by the
   // application for playback, for example.
   // Once attached, the MediaSource and the HTMLMediaElement use each other via
   // this attachment to accomplish the extended API.
-  // The MediaSourceTracer argument to calls in this interface enables the
-  // attachment to dynamically retrieve the Oilpan-managed objects without
-  // itself being managed by oilpan. Alternatives like requiring the (non-GC'ed)
-  // attachment to remember the tracer as a Persistent would break the ability
-  // for automatic collection of idle unreferenced same-thread HTMLME+MSE object
-  // collections. The tracer argument must be the same as that returned by the
-  // most recent call to the attachment's StartAttachingToMediaElement. We
-  // cannot have the tracer as a Member, and using Persistent to hold it instead
-  // would break the ability for automatic collection of idle unreferenced
-  // same-thread attached HTMLMediaElement + MediaSource object groups.
-  virtual MediaSourceTracer* StartAttachingToMediaElement(
-      HTMLMediaElement*) = 0;
+  // The MediaSourceTracer argument to calls in this interface enables at least
+  // the same-thread attachment to dynamically retrieve the Oilpan-managed
+  // objects without itself being managed by oilpan. Alternatives like requiring
+  // the (non-GC'ed) attachment to remember the tracer as a Persistent would
+  // break the ability for automatic collection of idle unreferenced same-thread
+  // HTMLME+MSE object collections. The tracer argument must be the same as that
+  // returned by the most recent call to the attachment's
+  // StartAttachingToMediaElement. We cannot have the tracer as a Member, and
+  // using Persistent to hold it instead would break the ability for automatic
+  // collection of idle unreferenced same-thread attached HTMLMediaElement +
+  // MediaSource object groups.
+  virtual MediaSourceTracer* StartAttachingToMediaElement(HTMLMediaElement*,
+                                                          bool* success) = 0;
   virtual void CompleteAttachingToMediaElement(
       MediaSourceTracer* tracer,
       std::unique_ptr<WebMediaSource>) = 0;
 
   virtual void Close(MediaSourceTracer* tracer) = 0;
-  virtual double duration(MediaSourceTracer* tracer) const = 0;
 
   // 'Internal' in these methods doesn't mean private, it means that they are
   // internal to chromium and are not exposed to JavaScript.
   virtual WebTimeRanges BufferedInternal(MediaSourceTracer* tracer) const = 0;
   virtual WebTimeRanges SeekableInternal(MediaSourceTracer* tracer) const = 0;
-  virtual TimeRanges* Buffered(MediaSourceTracer* tracer) const = 0;
+
   virtual void OnTrackChanged(MediaSourceTracer* tracer, TrackBase*) = 0;
 
   // Provide state updates to the MediaSource that are necessary for its
diff --git a/third_party/blink/renderer/core/html/media/video_auto_fullscreen_test.cc b/third_party/blink/renderer/core/html/media/video_auto_fullscreen_test.cc
index d6229f16..8232b5bf 100644
--- a/third_party/blink/renderer/core/html/media/video_auto_fullscreen_test.cc
+++ b/third_party/blink/renderer/core/html/media/video_auto_fullscreen_test.cc
@@ -71,7 +71,7 @@
     frame_host_.Init(
         web_frame_client_.GetRemoteNavigationAssociatedInterfaces());
     GetWebView()->GetSettings()->SetAutoplayPolicy(
-        WebSettings::AutoplayPolicy::kUserGestureRequired);
+        web_pref::AutoplayPolicy::kUserGestureRequired);
 
     frame_test_helpers::LoadFrame(
         web_view_helper_.GetWebView()->MainFrameImpl(), "about:blank");
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.cc b/third_party/blink/renderer/core/layout/layout_block_flow.cc
index bd1131b..9c95792 100644
--- a/third_party/blink/renderer/core/layout/layout_block_flow.cc
+++ b/third_party/blink/renderer/core/layout/layout_block_flow.cc
@@ -4407,6 +4407,10 @@
   if (IsLayoutNGCustom())
     return;
 
+  // MathML layout objects don't support multicol.
+  if (IsMathML())
+    return;
+
   auto* flow_thread = LayoutMultiColumnFlowThread::CreateAnonymous(
       GetDocument(), StyleRef(), !CanTraversePhysicalFragments());
   AddChild(flow_thread);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc
index e9c093a..91f2af90 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc
@@ -478,6 +478,11 @@
     NGMarginStrut* margin_strut) {
   LogicalSize column_size(column_inline_size_, column_block_size_);
 
+  // We're adding a row. Incorporate the trailing margin from any preceding
+  // column spanner into the layout position.
+  intrinsic_block_size_ += margin_strut->Sum();
+  *margin_strut = NGMarginStrut();
+
   // If block-size is non-auto, subtract the space for content we've consumed in
   // previous fragments. This is necessary when we're nested inside another
   // fragmentation context.
@@ -504,15 +509,11 @@
         CalculateBalancedColumnBlockSize(column_size, next_column_token);
   }
 
-  // Column rows have no representation in the DOM and have no margins, but
-  // there may be a trailing margin from a preceding spanner.
-  LayoutUnit column_block_offset = intrinsic_block_size_ + margin_strut->Sum();
-
   bool needs_more_fragments_in_outer = false;
   bool zero_outer_space_left = false;
   if (is_constrained_by_outer_fragmentation_context_) {
     LayoutUnit available_outer_space =
-        FragmentainerSpaceAtBfcStart(ConstraintSpace()) - column_block_offset;
+        FragmentainerSpaceAtBfcStart(ConstraintSpace()) - intrinsic_block_size_;
 
     if (available_outer_space <= LayoutUnit()) {
       if (available_outer_space < LayoutUnit()) {
@@ -584,7 +585,7 @@
     do {
       // Lay out one column. Each column will become a fragment.
       NGConstraintSpace child_space = CreateConstraintSpaceForColumns(
-          ConstraintSpace(), Style().GetWritingMode(), column_size,
+          ConstraintSpace(), column_size, ColumnPercentageResolutionSize(),
           is_first_fragmentainer, balance_columns);
 
       NGFragmentGeometry fragment_geometry =
@@ -598,7 +599,7 @@
 
       // Add the new column fragment to the list, but don't commit anything to
       // the fragment builder until we know whether these are the final columns.
-      LogicalOffset logical_offset(column_inline_offset, column_block_offset);
+      LogicalOffset logical_offset(column_inline_offset, intrinsic_block_size_);
       new_columns.emplace_back(result, logical_offset);
 
       LayoutUnit space_shortage = result->MinimalSpaceShortage();
@@ -706,7 +707,7 @@
     column_size.block_size = new_column_block_size;
   } while (true);
 
-  intrinsic_block_size_ = column_block_offset + column_size.block_size;
+  intrinsic_block_size_ += column_size.block_size;
 
   // If we just have one empty fragmentainer, we need to keep the trailing
   // margin from any previous column spanner, and also make sure that we don't
@@ -719,10 +720,6 @@
   if (!is_empty) {
     has_processed_first_child_ = true;
     container_builder_.SetPreviousBreakAfter(EBreakBetween::kAuto);
-
-    // We added a row. Reset the trailing margin from any previous column
-    // spanner.
-    *margin_strut = NGMarginStrut();
   }
 
   // Commit all column fragments to the fragment builder.
@@ -1014,7 +1011,7 @@
       ConstraintSpace(), Style().GetWritingMode(), /* is_new_fc */ true);
   space_builder.SetFragmentationType(kFragmentColumn);
   space_builder.SetAvailableSize({column_size.inline_size, kIndefiniteSize});
-  space_builder.SetPercentageResolutionSize(column_size);
+  space_builder.SetPercentageResolutionSize(ColumnPercentageResolutionSize());
   space_builder.SetIsAnonymous(true);
   space_builder.SetIsInColumnBfc();
   space_builder.SetIsInsideBalancedColumns();
diff --git a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h
index 096dd9c..ceea193b 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h
@@ -72,6 +72,15 @@
   // such as break-before:avoid or break-after:avoid.
   scoped_refptr<const NGLayoutResult> RelayoutAndBreakEarlier();
 
+  // Get the percentage resolution size to use for column content (i.e. not
+  // spanners).
+  LogicalSize ColumnPercentageResolutionSize() const {
+    // Percentage block-size on children is resolved against the content-box of
+    // the multicol container (just like in regular block layout), while
+    // percentage inline-size is restricted by the columns.
+    return LogicalSize(column_inline_size_, ChildAvailableSize().block_size);
+  }
+
   NGConstraintSpace CreateConstraintSpaceForBalancing(
       const LogicalSize& column_size) const;
   NGConstraintSpace CreateConstraintSpaceForSpanner(
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
index 8308424..e6dc24b 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
@@ -679,14 +679,14 @@
 
 NGConstraintSpace CreateConstraintSpaceForColumns(
     const NGConstraintSpace& parent_space,
-    WritingMode writing_mode,
-    const LogicalSize& column_size,
+    LogicalSize column_size,
+    LogicalSize percentage_resolution_size,
     bool is_first_fragmentainer,
     bool balance_columns) {
-  NGConstraintSpaceBuilder space_builder(parent_space, writing_mode,
-                                         /* is_new_fc */ true);
+  NGConstraintSpaceBuilder space_builder(
+      parent_space, parent_space.GetWritingMode(), /* is_new_fc */ true);
   space_builder.SetAvailableSize(column_size);
-  space_builder.SetPercentageResolutionSize(column_size);
+  space_builder.SetPercentageResolutionSize(percentage_resolution_size);
 
   // To ensure progression, we need something larger than 0 here. The spec
   // actually says that fragmentainers have to accept at least 1px of content.
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h
index cd57e2c..71030f8 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h
@@ -262,8 +262,8 @@
 // Calculate the constraint space for columns of a multi-column layout.
 NGConstraintSpace CreateConstraintSpaceForColumns(
     const NGConstraintSpace& parent_space,
-    WritingMode writing_mode,
-    const LogicalSize& column_size,
+    LogicalSize column_size,
+    LogicalSize percentage_resolution_size,
     bool is_first_fragmentainer,
     bool balance_columns);
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
index 37e49e0..17602e2 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -1159,12 +1159,16 @@
     column_size.block_size = column_size.block_size.ClampNegativeToZero();
   }
 
+  // TODO(layout-dev): Calculate correct percentage resolution size.
+  LogicalSize percentage_resolution_size = column_size;
+
   // TODO(bebeaudr): Need to handle different fragmentation types. It won't
   // always be multi-column.
   NGConstraintSpace fragmentainer_constraint_space =
-      CreateConstraintSpaceForColumns(
-          *container_builder_->ConstraintSpace(), container_writing_mode,
-          column_size, is_first_fragmentainer, /* balance_columns */ false);
+      CreateConstraintSpaceForColumns(*container_builder_->ConstraintSpace(),
+                                      column_size, percentage_resolution_size,
+                                      is_first_fragmentainer,
+                                      /* balance_columns */ false);
 
   return fragmentainer_constraint_space_map_
       .insert(stored_index, fragmentainer_constraint_space)
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
index 0edf09a..37ae37f 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
@@ -51,7 +51,7 @@
       builder->mathml_paint_info_ ||
       !builder->oof_positioned_fragmentainer_descendants_.IsEmpty() ||
       builder->table_grid_rect_ || builder->table_column_geometries_ ||
-      builder->table_collapsed_borders_.get() ||
+      builder->table_collapsed_borders_ ||
       builder->table_collapsed_borders_geometry_ ||
       builder->table_cell_column_index_;
   size_t byte_size = sizeof(NGPhysicalBoxFragment) +
@@ -64,8 +64,6 @@
     if (items_builder->Size())
       byte_size += NGFragmentItems::ByteSizeFor(items_builder->Size());
   }
-  if (builder->HasOutOfFlowFragmentainerDescendants())
-    byte_size += sizeof(NGPhysicalOutOfFlowPositionedNode);
 
   // We store the children list inline in the fragment as a flexible
   // array. Therefore, we need to make sure to allocate enough space for
@@ -179,17 +177,17 @@
         descendant.containing_block_fragment);
   }
   if (builder->table_grid_rect_)
-    table_grid_rect_ = *builder->table_grid_rect_;
+    table_grid_rect = *builder->table_grid_rect_;
   if (builder->table_column_geometries_)
-    table_column_geometries_ = *builder->table_column_geometries_;
-  if (builder->table_collapsed_borders_.get())
-    table_collapsed_borders_ = builder->table_collapsed_borders_.get();
+    table_column_geometries = *builder->table_column_geometries_;
+  if (builder->table_collapsed_borders_)
+    table_collapsed_borders = std::move(builder->table_collapsed_borders_);
   if (builder->table_collapsed_borders_geometry_) {
-    table_collapsed_borders_geometry_ =
+    table_collapsed_borders_geometry =
         std::move(builder->table_collapsed_borders_geometry_);
   }
   if (builder->table_cell_column_index_)
-    table_cell_column_index_ = *builder->table_cell_column_index_;
+    table_cell_column_index = *builder->table_cell_column_index_;
 }
 
 scoped_refptr<const NGLayoutResult>
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
index d1ad96b0..66da3dd 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
@@ -68,28 +68,28 @@
   }
 
   PhysicalRect TableGridRect() const {
-    return ComputeRareDataAddress()->table_grid_rect_;
+    return ComputeRareDataAddress()->table_grid_rect;
   }
 
   const NGTableFragmentData::ColumnGeometries* TableColumnGeometries() const {
-    return &ComputeRareDataAddress()->table_column_geometries_;
+    return &ComputeRareDataAddress()->table_column_geometries;
   }
 
   const NGTableBorders* TableCollapsedBorders() const {
-    return ComputeRareDataAddress()->table_collapsed_borders_.get();
+    return ComputeRareDataAddress()->table_collapsed_borders.get();
   }
 
   const NGTableFragmentData::CollapsedBordersGeometry*
   TableCollapsedBordersGeometry() const {
     auto& table_collapsed_borders_geometry =
-        ComputeRareDataAddress()->table_collapsed_borders_geometry_;
+        ComputeRareDataAddress()->table_collapsed_borders_geometry;
     if (!table_collapsed_borders_geometry)
       return nullptr;
     return table_collapsed_borders_geometry.get();
   }
 
   wtf_size_t TableCellColumnIndex() const {
-    return ComputeRareDataAddress()->table_cell_column_index_;
+    return ComputeRareDataAddress()->table_cell_column_index;
   }
 
   const NGPhysicalBoxStrut Borders() const {
@@ -232,12 +232,12 @@
     const std::unique_ptr<NGMathMLPaintInfo> mathml_paint_info;
 
     // TablesNG rare data.
-    PhysicalRect table_grid_rect_;
-    NGTableFragmentData::ColumnGeometries table_column_geometries_;
-    scoped_refptr<const NGTableBorders> table_collapsed_borders_;
+    PhysicalRect table_grid_rect;
+    NGTableFragmentData::ColumnGeometries table_column_geometries;
+    scoped_refptr<const NGTableBorders> table_collapsed_borders;
     std::unique_ptr<NGTableFragmentData::CollapsedBordersGeometry>
-        table_collapsed_borders_geometry_;
-    wtf_size_t table_cell_column_index_;
+        table_collapsed_borders_geometry;
+    wtf_size_t table_cell_column_index;
   };
 
   const NGFragmentItems* ComputeItemsAddress() const {
@@ -277,8 +277,8 @@
   LayoutUnit baseline_;
   LayoutUnit last_baseline_;
   NGLink children_[];
-  // borders, padding, and oof_positioned_fragmentainer_descendants come after
-  // |children_| if they are not zero.
+  // fragment_items, borders, padding, and rare_data are after |children_| if
+  // they are not empty/initial.
 };
 
 template <>
diff --git a/third_party/blink/renderer/core/page/print_context.cc b/third_party/blink/renderer/core/page/print_context.cc
index 7df0317..fa2aa23 100644
--- a/third_party/blink/renderer/core/page/print_context.cc
+++ b/third_party/blink/renderer/core/page/print_context.cc
@@ -245,7 +245,7 @@
 // static
 String PrintContext::PageProperty(LocalFrame* frame,
                                   const char* property_name,
-                                  int page_number) {
+                                  uint32_t page_number) {
   Document* document = frame->GetDocument();
   ScopedPrintContext print_context(frame);
   // Any non-zero size is OK here. We don't care about actual layout. We just
@@ -274,12 +274,12 @@
   return String("pageProperty() unimplemented for: ") + property_name;
 }
 
-bool PrintContext::IsPageBoxVisible(LocalFrame* frame, int page_number) {
+bool PrintContext::IsPageBoxVisible(LocalFrame* frame, uint32_t page_number) {
   return frame->GetDocument()->IsPageBoxVisible(page_number);
 }
 
 String PrintContext::PageSizeAndMarginsInPixels(LocalFrame* frame,
-                                                int page_number,
+                                                uint32_t page_number,
                                                 int width,
                                                 int height,
                                                 int margin_top,
diff --git a/third_party/blink/renderer/core/page/print_context.h b/third_party/blink/renderer/core/page/print_context.h
index e63d9c2b..bf491305 100644
--- a/third_party/blink/renderer/core/page/print_context.h
+++ b/third_party/blink/renderer/core/page/print_context.h
@@ -91,10 +91,10 @@
                                   const FloatSize& page_size_in_pixels);
   static String PageProperty(LocalFrame*,
                              const char* property_name,
-                             int page_number);
-  static bool IsPageBoxVisible(LocalFrame*, int page_number);
+                             uint32_t page_number);
+  static bool IsPageBoxVisible(LocalFrame*, uint32_t page_number);
   static String PageSizeAndMarginsInPixels(LocalFrame*,
-                                           int page_number,
+                                           uint32_t page_number,
                                            int width,
                                            int height,
                                            int margin_top,
diff --git a/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.cc b/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.cc
index 2063ffeb..5d90f35 100644
--- a/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.cc
+++ b/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.cc
@@ -90,8 +90,10 @@
     return frame_view->LayoutViewport();
   }
 
-  DCHECK(element.GetLayoutObject()->IsBox());
-  return ToLayoutBox(element.GetLayoutObject())->GetScrollableArea();
+  if (!element.GetLayoutBoxForScrolling())
+    return nullptr;
+
+  return element.GetLayoutBoxForScrolling()->GetScrollableArea();
 }
 
 }  // namespace
diff --git a/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc b/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc
index efc3851d..8864fd4 100644
--- a/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc
@@ -2749,6 +2749,54 @@
       << "<iframe> should remain promoted when URL bar is hidden";
 }
 
+// Ensure that a scrollable fieldset doesn't get promoted to root scroller.
+// With FieldsetNG, a scrollable fieldset creates an anonymous LayoutBox that
+// doesn't have an associated Node. RootScroller is premised on the fact that a
+// scroller is associated with a Node. It'd be non-trivial work to make this
+// work without a clear benefit so for now ensure it doesn't get promoted and
+// doesn't cause any crashes. https://crbug.com/1125621.
+TEST_F(ImplicitRootScrollerSimTest, FieldsetNGCantBeRootScroller) {
+  // This test is specifically ensuring we avoid crashing with the LayoutNG
+  // version of fieldset since it uses an anonymous LayoutBox for scrolling.
+  if (!RuntimeEnabledFeatures::LayoutNGEnabled())
+    return;
+
+  WebView().MainFrameWidget()->Resize(WebSize(800, 600));
+  SimRequest request("https://example.com/test.html", "text/html");
+  LoadURL("https://example.com/test.html");
+  request.Complete(R"HTML(
+          <!DOCTYPE html>
+          <style>
+            ::-webkit-scrollbar {
+              width: 0px;
+              height: 0px;
+            }
+            body, html {
+              width: 100%;
+              height: 100%;
+              margin: 0px;
+            }
+            fieldset {
+              width: 100%;
+              height: 100%;
+              overflow: scroll;
+              border: 0;
+              margin: 0;
+              padding: 0;
+            }
+            div {
+              height: 200%;
+            }
+          </style>
+          <fieldset>
+            <div></div>
+          </fieldset>
+      )HTML");
+  Compositor().BeginFrame();
+
+  EXPECT_TRUE(GetDocument().GetLayoutView()->IsEffectiveRootScroller());
+}
+
 class RootScrollerHitTest : public ImplicitRootScrollerSimTest {
  public:
   void CheckHitTestAtBottomOfScreen(Element* target) {
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
index 9d46b93..d7c61cf 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -2372,10 +2372,16 @@
             *owner);
       }
     } else {
-      GetLayoutBox()
-          ->GetDocument()
-          .GetRootScrollerController()
-          .ConsiderForImplicit(*GetLayoutBox()->GetNode());
+      // In some cases, the LayoutBox may not be associated with a Node (e.g.
+      // <input> and <fieldset> can generate anonymous LayoutBoxes for their
+      // scrollers). We don't care about those cases for root scroller so
+      // simply avoid these. https://crbug.com/1125621.
+      if (GetLayoutBox()->GetNode()) {
+        GetLayoutBox()
+            ->GetDocument()
+            .GetRootScrollerController()
+            .ConsiderForImplicit(*GetLayoutBox()->GetNode());
+      }
     }
   }
 
diff --git a/third_party/blink/renderer/core/script/classic_script.cc b/third_party/blink/renderer/core/script/classic_script.cc
index 4141aad..17493fd1 100644
--- a/third_party/blink/renderer/core/script/classic_script.cc
+++ b/third_party/blink/renderer/core/script/classic_script.cc
@@ -57,10 +57,10 @@
   DCHECK(global_scope.IsContextThread());
 
   ScriptState::Scope scope(global_scope.ScriptController()->GetScriptState());
-  v8::Local<v8::Value> result =
+  ClassicEvaluationResult result =
       global_scope.ScriptController()->EvaluateAndReturnValue(
           GetScriptSourceCode(), sanitize_script_errors_,
-          nullptr /* error_event */, global_scope.GetV8CacheOptions());
+          global_scope.GetV8CacheOptions());
   return !result.IsEmpty();
 }
 
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc
index 3fdb30f0..08990242 100644
--- a/third_party/blink/renderer/core/testing/internals.cc
+++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -2320,7 +2320,7 @@
 }
 
 String Internals::pageProperty(String property_name,
-                               int page_number,
+                               unsigned page_number,
                                ExceptionState& exception_state) const {
   if (!GetFrame()) {
     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidAccessError,
@@ -2333,7 +2333,7 @@
 }
 
 String Internals::pageSizeAndMarginsInPixels(
-    int page_number,
+    unsigned page_number,
     int width,
     int height,
     int margin_top,
diff --git a/third_party/blink/renderer/core/testing/internals.h b/third_party/blink/renderer/core/testing/internals.h
index c0dcdd3..8c78d63 100644
--- a/third_party/blink/renderer/core/testing/internals.h
+++ b/third_party/blink/renderer/core/testing/internals.h
@@ -380,9 +380,11 @@
   int numberOfPages(float page_width_in_pixels,
                     float page_height_in_pixels,
                     ExceptionState&);
-  String pageProperty(String, int, ExceptionState& = ASSERT_NO_EXCEPTION) const;
+  String pageProperty(String,
+                      unsigned,
+                      ExceptionState& = ASSERT_NO_EXCEPTION) const;
   String pageSizeAndMarginsInPixels(
-      int,
+      unsigned,
       int,
       int,
       int,
diff --git a/third_party/blink/renderer/core/testing/internals.idl b/third_party/blink/renderer/core/testing/internals.idl
index 87e5ae0..4ee77c0 100644
--- a/third_party/blink/renderer/core/testing/internals.idl
+++ b/third_party/blink/renderer/core/testing/internals.idl
@@ -218,8 +218,8 @@
     sequence<DOMString> shortcutIconURLs(Document document);
     sequence<DOMString> allIconURLs(Document document);
     [RaisesException] long numberOfPages(optional double pageWidthInPixels = 800, optional double pageHeightInPixels = 600);
-    [RaisesException] DOMString pageProperty(DOMString propertyName, long pageNumber);
-    [RaisesException] DOMString pageSizeAndMarginsInPixels(long pageIndex, long width, long height, long marginTop, long marginRight, long marginBottom, long marginLeft);
+    [RaisesException] DOMString pageProperty(DOMString propertyName, unsigned long pageNumber);
+    [RaisesException] DOMString pageSizeAndMarginsInPixels(unsigned long pageIndex, long width, long height, long marginTop, long marginRight, long marginBottom, long marginLeft);
 
     [RaisesException] float pageScaleFactor();
     [RaisesException] void setPageScaleFactor(float scaleFactor);
diff --git a/third_party/blink/renderer/core/workers/worker_global_scope.cc b/third_party/blink/renderer/core/workers/worker_global_scope.cc
index 53a81c0..d369189 100644
--- a/third_party/blink/renderer/core/workers/worker_global_scope.cc
+++ b/third_party/blink/renderer/core/workers/worker_global_scope.cc
@@ -35,6 +35,7 @@
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_source_code.h"
 #include "third_party/blink/renderer/bindings/core/v8/source_location.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_void_function.h"
 #include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h"
 #include "third_party/blink/renderer/core/css/font_face_set_worker.h"
@@ -216,23 +217,42 @@
   return GetSecurityOrigin()->ToString();
 }
 
-void WorkerGlobalScope::importScripts(const Vector<String>& urls,
-                                      ExceptionState& exception_state) {
-  ImportScriptsInternal(urls, exception_state);
+void WorkerGlobalScope::importScripts(const Vector<String>& urls) {
+  ImportScriptsInternal(urls);
 }
 
+namespace {
+
+String NetworkErrorMessageAtImportScript(const char* const property_name,
+                                         const char* const interface_name,
+                                         const KURL& url) {
+  return ExceptionMessages::FailedToExecute(
+      property_name, interface_name,
+      "The script at '" + url.ElidedString() + "' failed to load.");
+}
+
+}  // namespace
+
 // Implementation of the "import scripts into worker global scope" algorithm:
 // https://html.spec.whatwg.org/C/#import-scripts-into-worker-global-scope
-void WorkerGlobalScope::ImportScriptsInternal(const Vector<String>& urls,
-                                              ExceptionState& exception_state) {
+void WorkerGlobalScope::ImportScriptsInternal(const Vector<String>& urls) {
   DCHECK(GetContentSecurityPolicy());
   DCHECK(GetExecutionContext());
+  v8::Isolate* isolate = GetThread()->GetIsolate();
+
+  // Previously, exceptions here were thrown via ExceptionState but now are
+  // thrown via V8ThrowException. To keep the existing error messages,
+  // ExceptionMessages::FailedToExecute() is called directly (crbug/1114610).
+  const char* const property_name = "importScripts";
+  const char* const interface_name = "WorkerGlobalScope";
 
   // Step 1: "If worker global scope's type is "module", throw a TypeError
   // exception."
   if (script_type_ == mojom::ScriptType::kModule) {
-    exception_state.ThrowTypeError(
-        "Module scripts don't support importScripts().");
+    V8ThrowException::ThrowTypeError(
+        isolate, ExceptionMessages::FailedToExecute(
+                     property_name, interface_name,
+                     "Module scripts don't support importScripts()."));
     return;
   }
 
@@ -249,17 +269,22 @@
   for (const String& url_string : urls) {
     const KURL& url = CompleteURL(url_string);
     if (!url.IsValid()) {
-      exception_state.ThrowDOMException(
-          DOMExceptionCode::kSyntaxError,
-          "The URL '" + url_string + "' is invalid.");
+      V8ThrowException::ThrowException(
+          isolate, V8ThrowDOMException::CreateOrEmpty(
+                       isolate, DOMExceptionCode::kSyntaxError,
+                       ExceptionMessages::FailedToExecute(
+                           property_name, interface_name,
+                           "The URL '" + url_string + "' is invalid.")));
       return;
     }
     if (!GetContentSecurityPolicy()->AllowScriptFromSource(
             url, AtomicString(), IntegrityMetadataSet(), kNotParserInserted,
             url, RedirectStatus::kNoRedirect)) {
-      exception_state.ThrowDOMException(
-          DOMExceptionCode::kNetworkError,
-          "The script at '" + url.ElidedString() + "' failed to load.");
+      V8ThrowException::ThrowException(
+          isolate, V8ThrowDOMException::CreateOrEmpty(
+                       isolate, DOMExceptionCode::kNetworkError,
+                       NetworkErrorMessageAtImportScript(property_name,
+                                                         interface_name, url)));
       return;
     }
     completed_urls.push_back(url);
@@ -270,6 +295,8 @@
     KURL response_url;
     String source_code;
     std::unique_ptr<Vector<uint8_t>> cached_meta_data;
+    const String error_message = NetworkErrorMessageAtImportScript(
+        property_name, interface_name, complete_url);
 
     // Step 5.1: "Fetch a classic worker-imported script given url and settings
     // object, passing along any custom perform the fetch steps provided. If
@@ -280,10 +307,10 @@
       // TODO(vogelheim): In case of certain types of failure - e.g. 'nosniff'
       // block - this ought to be a DOMExceptionCode::kSecurityError, but that
       // information presently gets lost on the way.
-      exception_state.ThrowDOMException(DOMExceptionCode::kNetworkError,
-                                        "The script at '" +
-                                            complete_url.ElidedString() +
-                                            "' failed to load.");
+      V8ThrowException::ThrowException(
+          isolate,
+          V8ThrowDOMException::CreateOrEmpty(
+              isolate, DOMExceptionCode::kNetworkError, error_message));
       return;
     }
 
@@ -297,24 +324,26 @@
 
     // Step 5.2: "Run the classic script script, with the rethrow errors
     // argument set to true."
-    ErrorEvent* error_event = nullptr;
     SingleCachedMetadataHandler* handler(
         CreateWorkerScriptCachedMetadataHandler(complete_url,
                                                 std::move(cached_meta_data)));
     ReportingProxy().WillEvaluateImportedClassicScript(
         source_code.length(), handler ? handler->GetCodeCacheSize() : 0);
     ScriptState::Scope scope(ScriptController()->GetScriptState());
-    ScriptController()->EvaluateAndReturnValue(
+    ClassicEvaluationResult result = ScriptController()->EvaluateAndReturnValue(
         ScriptSourceCode(source_code, ScriptSourceLocationType::kUnknown,
                          handler,
                          ScriptSourceCode::UsePostRedirectURL() ? response_url
                                                                 : complete_url),
-        sanitize_script_errors, &error_event, GetV8CacheOptions());
-    if (error_event) {
-      ScriptController()->RethrowExceptionFromImportedScript(error_event,
-                                                             exception_state);
+        sanitize_script_errors, GetV8CacheOptions(),
+        WorkerOrWorkletScriptController::RethrowErrorsOption::Rethrow(
+            error_message));
+
+    // Step 5.2: "If an exception was thrown or if the script was prematurely
+    // aborted, then abort all these steps, letting the exception or aborting
+    // continue to be processed by the calling script."
+    if (result.IsEmpty())
       return;
-    }
   }
 }
 
diff --git a/third_party/blink/renderer/core/workers/worker_global_scope.h b/third_party/blink/renderer/core/workers/worker_global_scope.h
index e2f52c2..d4b5f097 100644
--- a/third_party/blink/renderer/core/workers/worker_global_scope.h
+++ b/third_party/blink/renderer/core/workers/worker_global_scope.h
@@ -52,7 +52,6 @@
 
 struct BlinkTransferableMessage;
 class ConsoleMessage;
-class ExceptionState;
 class FetchClientSettingsObjectSnapshot;
 class FontFaceSet;
 class InstalledScriptsManager;
@@ -105,8 +104,9 @@
   DEFINE_ATTRIBUTE_EVENT_LISTENER(timezonechange, kTimezonechange)
   DEFINE_ATTRIBUTE_EVENT_LISTENER(unhandledrejection, kUnhandledrejection)
 
-  // WorkerUtils
-  virtual void importScripts(const Vector<String>& urls, ExceptionState&);
+  // This doesn't take an ExceptionState argument, but actually can throw
+  // exceptions directly to V8 (crbug/1114610).
+  virtual void importScripts(const Vector<String>& urls);
 
   // ExecutionContext
   const KURL& Url() const final;
@@ -255,7 +255,7 @@
   void RunWorkerScript();
 
   // Used for importScripts().
-  void ImportScriptsInternal(const Vector<String>& urls, ExceptionState&);
+  void ImportScriptsInternal(const Vector<String>& urls);
   // ExecutionContext
   void AddInspectorIssue(mojom::blink::InspectorIssueInfoPtr) final;
   EventTarget* ErrorEventTarget() final { return this; }
diff --git a/third_party/blink/renderer/core/workers/worker_global_scope.idl b/third_party/blink/renderer/core/workers/worker_global_scope.idl
index a84f6fd8..94fb4077 100644
--- a/third_party/blink/renderer/core/workers/worker_global_scope.idl
+++ b/third_party/blink/renderer/core/workers/worker_global_scope.idl
@@ -41,7 +41,9 @@
     // attribute EventHandler ononline;
 
     // https://html.spec.whatwg.org/C/#apis-available-to-workers
-    [RaisesException] void importScripts(ScriptURLString... urls);
+    // Although RaisesException is not specified, importScripts() can actually
+    // throw exceptions directly to V8.
+    void importScripts(ScriptURLString... urls);
     readonly attribute WorkerNavigator navigator;
 
 
diff --git a/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc b/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc
index 8c34474..6c5c19a 100644
--- a/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc
+++ b/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc
@@ -148,18 +148,27 @@
     waitable_event->Signal();
   }
 
+  static bool RunScriptAndGetBoolean(AnimationWorkletGlobalScope* global_scope,
+                                     const String& script) {
+    ScriptState* script_state =
+        global_scope->ScriptController()->GetScriptState();
+    DCHECK(script_state);
+    v8::Isolate* isolate = script_state->GetIsolate();
+    DCHECK(isolate);
+    ScriptState::Scope scope(script_state);
+
+    ClassicEvaluationResult result =
+        global_scope->ScriptController()->EvaluateAndReturnValue(
+            ScriptSourceCode(script), SanitizeScriptErrors::kSanitize);
+    DCHECK(!result.IsEmpty());
+    return ToBoolean(isolate, result.GetValue(), ASSERT_NO_EXCEPTION);
+  }
+
   void RunConstructAndAnimateTestOnWorklet(
       WorkerThread* thread,
       base::WaitableEvent* waitable_event) {
     ASSERT_TRUE(thread->IsCurrentThread());
     auto* global_scope = To<AnimationWorkletGlobalScope>(thread->GlobalScope());
-    ScriptState* script_state =
-        global_scope->ScriptController()->GetScriptState();
-    ASSERT_TRUE(script_state);
-    v8::Isolate* isolate = script_state->GetIsolate();
-    ASSERT_TRUE(isolate);
-
-    ScriptState::Scope scope(script_state);
 
     String source_code =
         R"JS(
@@ -182,18 +191,12 @@
         ClassicScript::CreateUnspecifiedScript(ScriptSourceCode(source_code))
             ->RunScriptOnWorkerOrWorklet(*global_scope));
 
-    v8::Local<v8::Value> constructed_before =
-        global_scope->ScriptController()->EvaluateAndReturnValue(
-            ScriptSourceCode("Function('return this')().constructed"),
-            SanitizeScriptErrors::kSanitize);
-    EXPECT_FALSE(ToBoolean(isolate, constructed_before, ASSERT_NO_EXCEPTION))
+    EXPECT_FALSE(RunScriptAndGetBoolean(
+        global_scope, "Function('return this')().constructed"))
         << "constructor is not invoked";
 
-    v8::Local<v8::Value> animated_before =
-        global_scope->ScriptController()->EvaluateAndReturnValue(
-            ScriptSourceCode("Function('return this')().animated"),
-            SanitizeScriptErrors::kSanitize);
-    EXPECT_FALSE(ToBoolean(isolate, animated_before, ASSERT_NO_EXCEPTION))
+    EXPECT_FALSE(RunScriptAndGetBoolean(global_scope,
+                                        "Function('return this')().animated"))
         << "animate function is invoked early";
 
     // Passing a new input state with a new animation id should cause the
@@ -209,18 +212,12 @@
         ProxyClientMutate(state, global_scope);
     EXPECT_EQ(output->animations.size(), 1ul);
 
-    v8::Local<v8::Value> constructed_after =
-        global_scope->ScriptController()->EvaluateAndReturnValue(
-            ScriptSourceCode("Function('return this')().constructed"),
-            SanitizeScriptErrors::kSanitize);
-    EXPECT_TRUE(ToBoolean(isolate, constructed_after, ASSERT_NO_EXCEPTION))
+    EXPECT_TRUE(RunScriptAndGetBoolean(global_scope,
+                                       "Function('return this')().constructed"))
         << "constructor is not invoked";
 
-    v8::Local<v8::Value> animated_after =
-        global_scope->ScriptController()->EvaluateAndReturnValue(
-            ScriptSourceCode("Function('return this')().animated"),
-            SanitizeScriptErrors::kSanitize);
-    EXPECT_TRUE(ToBoolean(isolate, animated_after, ASSERT_NO_EXCEPTION))
+    EXPECT_TRUE(RunScriptAndGetBoolean(global_scope,
+                                       "Function('return this')().animated"))
         << "animate function is not invoked";
 
     waitable_event->Signal();
diff --git a/third_party/blink/renderer/modules/background_sync/periodic_sync_manager.cc b/third_party/blink/renderer/modules/background_sync/periodic_sync_manager.cc
index 72e05f1c..6be9541b 100644
--- a/third_party/blink/renderer/modules/background_sync/periodic_sync_manager.cc
+++ b/third_party/blink/renderer/modules/background_sync/periodic_sync_manager.cc
@@ -4,7 +4,7 @@
 
 #include "third_party/blink/renderer/modules/background_sync/periodic_sync_manager.h"
 
-#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
@@ -94,8 +94,10 @@
 mojom::blink::PeriodicBackgroundSyncService*
 PeriodicSyncManager::GetBackgroundSyncServiceRemote() {
   if (!background_sync_service_.is_bound()) {
-    Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
-        background_sync_service_.BindNewPipeAndPassReceiver(task_runner_));
+    registration_->GetExecutionContext()
+        ->GetBrowserInterfaceBroker()
+        .GetInterface(
+            background_sync_service_.BindNewPipeAndPassReceiver(task_runner_));
   }
   return background_sync_service_.get();
 }
diff --git a/third_party/blink/renderer/modules/background_sync/sync_manager.cc b/third_party/blink/renderer/modules/background_sync/sync_manager.cc
index 9011c23..42cb8d3 100644
--- a/third_party/blink/renderer/modules/background_sync/sync_manager.cc
+++ b/third_party/blink/renderer/modules/background_sync/sync_manager.cc
@@ -4,7 +4,7 @@
 
 #include "third_party/blink/renderer/modules/background_sync/sync_manager.h"
 
-#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/bindings/core/v8/callback_promise_adapter.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
@@ -25,7 +25,7 @@
     : registration_(registration),
       background_sync_service_(registration->GetExecutionContext()) {
   DCHECK(registration);
-  Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
+  registration->GetExecutionContext()->GetBrowserInterfaceBroker().GetInterface(
       background_sync_service_.BindNewPipeAndPassReceiver(task_runner));
 }
 
diff --git a/third_party/blink/renderer/modules/canvas/BUILD.gn b/third_party/blink/renderer/modules/canvas/BUILD.gn
index 098a4e35..3dee279 100644
--- a/third_party/blink/renderer/modules/canvas/BUILD.gn
+++ b/third_party/blink/renderer/modules/canvas/BUILD.gn
@@ -53,4 +53,7 @@
     "//third_party/blink/renderer/core:testing",
     "//third_party/blink/renderer/platform:test_support",
   ]
+
+  # Disabled due to many false positives (crbug.com/1124824).
+  additional_configs = [ "//testing/libfuzzer:no_clusterfuzz" ]
 }
diff --git a/third_party/blink/renderer/modules/canvas/canvas_fuzzer.cc b/third_party/blink/renderer/modules/canvas/canvas_fuzzer.cc
index cd74623..c828a022 100644
--- a/third_party/blink/renderer/modules/canvas/canvas_fuzzer.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas_fuzzer.cc
@@ -81,10 +81,6 @@
 
 // Fuzzer for blink::ManifestParser
 int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  // TODO(bug/1124824) Disabling CanvasFuzzer as it seems to be producing lots
-  // of false positives.
-  return 0;
-
   // We are ignoring small tests
   constexpr int minSizeHtml = 20;
   if (size < minSizeHtml)
diff --git a/third_party/blink/renderer/modules/mediasource/media_source.cc b/third_party/blink/renderer/modules/mediasource/media_source.cc
index eeb9d9da..15ce7b31 100644
--- a/third_party/blink/renderer/modules/mediasource/media_source.cc
+++ b/third_party/blink/renderer/modules/mediasource/media_source.cc
@@ -787,12 +787,16 @@
 }
 
 // TODO(https://crbug.com/878133): Remove this getter and instead rely on
-// |media_source_attachment_| and |attachment_tracer_| to communicate about
-// the media element.
+// Attachment() to communicate about the media element.
 HTMLMediaElement* MediaSource::MediaElement() const {
   return attached_element_.Get();
 }
 
+std::pair<scoped_refptr<MediaSourceAttachmentSupplement>, MediaSourceTracer*>
+MediaSource::AttachmentAndTracer() const {
+  return std::make_pair(media_source_attachment_, attachment_tracer_);
+}
+
 void MediaSource::EndOfStreamAlgorithm(
     const WebMediaSource::EndOfStreamStatus eos_status) {
   // https://www.w3.org/TR/media-source/#end-of-stream-algorithm
@@ -880,6 +884,8 @@
 }
 
 void MediaSource::ContextDestroyed() {
+  if (media_source_attachment_)
+    media_source_attachment_->OnMediaSourceContextDestroyed();
   if (!IsClosed())
     SetReadyState(ClosedKeyword());
   web_media_source_.reset();
diff --git a/third_party/blink/renderer/modules/mediasource/media_source.h b/third_party/blink/renderer/modules/mediasource/media_source.h
index 2f45e6a..e2ee5452 100644
--- a/third_party/blink/renderer/modules/mediasource/media_source.h
+++ b/third_party/blink/renderer/modules/mediasource/media_source.h
@@ -6,6 +6,8 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_MEDIA_SOURCE_H_
 
 #include <memory>
+#include <tuple>
+#include <utility>
 
 #include "base/memory/scoped_refptr.h"
 #include "third_party/blink/public/platform/web_media_source.h"
@@ -108,6 +110,8 @@
   bool IsOpen() const;
   void SetSourceBufferActive(SourceBuffer*, bool);
   HTMLMediaElement* MediaElement() const;
+  std::pair<scoped_refptr<MediaSourceAttachmentSupplement>, MediaSourceTracer*>
+  AttachmentAndTracer() const;
   void EndOfStreamAlgorithm(const WebMediaSource::EndOfStreamStatus);
 
   void Trace(Visitor*) const override;
diff --git a/third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.cc b/third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.cc
index 5b9752cd..fcc3e13 100644
--- a/third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.cc
+++ b/third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.cc
@@ -11,10 +11,7 @@
 
 MediaSourceAttachmentSupplement::MediaSourceAttachmentSupplement(
     MediaSource* media_source)
-    : registered_media_source_(media_source),
-      recent_element_time_(0.0),
-      element_has_error_(false),
-      element_context_destroyed_(false) {}
+    : registered_media_source_(media_source) {}
 
 MediaSourceAttachmentSupplement::~MediaSourceAttachmentSupplement() = default;
 
@@ -32,25 +29,4 @@
   registered_media_source_ = nullptr;
 }
 
-void MediaSourceAttachmentSupplement::OnElementTimeUpdate(double time) {
-  DVLOG(3) << __func__ << " this=" << this << ", time=" << time;
-
-  recent_element_time_ = time;
-}
-
-void MediaSourceAttachmentSupplement::OnElementError() {
-  DVLOG(3) << __func__ << " this=" << this;
-
-  DCHECK(!element_has_error_)
-      << "At most one transition to element error per attachment is expected";
-
-  element_has_error_ = true;
-}
-
-void MediaSourceAttachmentSupplement::OnElementContextDestroyed() {
-  DVLOG(3) << __func__ << " this=" << this;
-
-  element_context_destroyed_ = true;
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.h b/third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.h
index d64c924..484f2df 100644
--- a/third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.h
+++ b/third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.h
@@ -5,8 +5,6 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_MEDIA_SOURCE_ATTACHMENT_SUPPLEMENT_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_MEDIA_SOURCE_ATTACHMENT_SUPPLEMENT_H_
 
-#include <memory>
-#include "third_party/blink/public/platform/web_time_range.h"
 #include "third_party/blink/renderer/core/html/media/media_source_attachment.h"
 #include "third_party/blink/renderer/core/html/media/media_source_tracer.h"
 #include "third_party/blink/renderer/modules/mediasource/media_source.h"
@@ -33,16 +31,26 @@
   // subsequent retrieval of MediaElement.duration, all on the main thread).
   virtual void NotifyDurationChanged(MediaSourceTracer* tracer,
                                      double duration) = 0;
+
+  // Retrieves the current (or a recent) media element time. Implementations may
+  // choose to either directly, synchronously consult the attached media element
+  // (via |tracer| in a same thread implementation) or rely on a "recent"
+  // currentTime pumped by the attached element via the MediaSourceAttachment
+  // interface (in a cross-thread implementation).
+  virtual double GetRecentMediaTime(MediaSourceTracer* tracer) = 0;
+
+  // Retrieves whether or not the media element currently has an error.
+  // Implementations may choose to either directly, synchronously consult the
+  // attached media element (via |tracer| in a same thread implementation) or
+  // rely on the element to correctly pump when it has an error to this
+  // attachment (in a cross-thread implementation).
+  virtual bool GetElementError(MediaSourceTracer* tracer) = 0;
+
+  virtual void OnMediaSourceContextDestroyed() = 0;
+
   // MediaSourceAttachment
   void Unregister() final;
 
-  // TODO(https://crbug.com/878133): Make MediaSource consult us for this
-  // information. In same-thread version, we may still directly consult the
-  // element, but cross-thread version will need this info.
-  void OnElementTimeUpdate(double time) final;
-  void OnElementError() final;
-  void OnElementContextDestroyed() final;
-
  protected:
   explicit MediaSourceAttachmentSupplement(MediaSource* media_source);
   ~MediaSourceAttachmentSupplement() override;
@@ -51,11 +59,6 @@
   // construction of this object until Unregister() is called.
   Persistent<MediaSource> registered_media_source_;
 
- private:
-  double recent_element_time_;
-  bool element_has_error_;
-  bool element_context_destroyed_;
-
   DISALLOW_COPY_AND_ASSIGN(MediaSourceAttachmentSupplement);
 };
 
diff --git a/third_party/blink/renderer/modules/mediasource/same_thread_media_source_attachment.cc b/third_party/blink/renderer/modules/mediasource/same_thread_media_source_attachment.cc
index d478dde..d8741a20 100644
--- a/third_party/blink/renderer/modules/mediasource/same_thread_media_source_attachment.cc
+++ b/third_party/blink/renderer/modules/mediasource/same_thread_media_source_attachment.cc
@@ -33,7 +33,11 @@
 
 SameThreadMediaSourceAttachment::SameThreadMediaSourceAttachment(
     MediaSource* media_source)
-    : MediaSourceAttachmentSupplement(media_source) {
+    : MediaSourceAttachmentSupplement(media_source),
+      recent_element_time_(0.0),
+      element_has_error_(false),
+      element_context_destroyed_(false),
+      media_source_context_destroyed_(false) {
   // This kind of attachment only operates on the main thread.
   DCHECK(IsMainThread());
 
@@ -51,56 +55,151 @@
 void SameThreadMediaSourceAttachment::NotifyDurationChanged(
     MediaSourceTracer* tracer,
     double duration) {
+  DVLOG(1) << __func__ << " this=" << this;
+
+  VerifyCalledWhileContextsAliveForDebugging();
+
   HTMLMediaElement* element = GetMediaElement(tracer);
 
   bool request_seek = element->currentTime() > duration;
   element->DurationChanged(duration, request_seek);
 }
 
+double SameThreadMediaSourceAttachment::GetRecentMediaTime(
+    MediaSourceTracer* tracer) {
+  DVLOG(1) << __func__ << " this=" << this;
+
+  VerifyCalledWhileContextsAliveForDebugging();
+
+  HTMLMediaElement* element = GetMediaElement(tracer);
+  double result = element->currentTime();
+
+  DVLOG(2) << __func__ << " this=" << this
+           << " -> recent time=" << recent_element_time_
+           << ", actual currentTime=" << result;
+  return result;
+}
+
+bool SameThreadMediaSourceAttachment::GetElementError(
+    MediaSourceTracer* tracer) {
+  DVLOG(1) << __func__ << " this=" << this;
+
+  VerifyCalledWhileContextsAliveForDebugging();
+
+  HTMLMediaElement* element = GetMediaElement(tracer);
+  bool current_element_error_state = !!element->error();
+
+  DCHECK_EQ(current_element_error_state, element_has_error_);
+
+  return current_element_error_state;
+}
+
 MediaSourceTracer*
 SameThreadMediaSourceAttachment::StartAttachingToMediaElement(
-    HTMLMediaElement* element) {
-  if (!registered_media_source_)
-    return nullptr;
+    HTMLMediaElement* element,
+    bool* success) {
+  VerifyCalledWhileContextsAliveForDebugging();
+  DCHECK(success);
 
-  return registered_media_source_->StartAttachingToMediaElement(
-      WrapRefCounted(this), element);
+  if (!registered_media_source_) {
+    *success = false;
+    return nullptr;
+  }
+
+  MediaSourceTracer* tracer =
+      registered_media_source_->StartAttachingToMediaElement(
+          WrapRefCounted(this), element);
+
+  // For this same-thread attachment start, a non-nullptr tracer indicates
+  // success here.
+  *success = !!tracer;
+  return tracer;
 }
 
 void SameThreadMediaSourceAttachment::CompleteAttachingToMediaElement(
     MediaSourceTracer* tracer,
     std::unique_ptr<WebMediaSource> web_media_source) {
+  VerifyCalledWhileContextsAliveForDebugging();
+
   GetMediaSource(tracer)->CompleteAttachingToMediaElement(
       std::move(web_media_source));
 }
 
 void SameThreadMediaSourceAttachment::Close(MediaSourceTracer* tracer) {
-  GetMediaSource(tracer)->Close();
-}
+  // The media element may have already notified us that its context is
+  // destroyed, so VerifyCalledWhileContextIsAliveForDebugging() is unusable in
+  // this scope.
 
-double SameThreadMediaSourceAttachment::duration(
-    MediaSourceTracer* tracer) const {
-  return GetMediaSource(tracer)->duration();
+  GetMediaSource(tracer)->Close();
 }
 
 WebTimeRanges SameThreadMediaSourceAttachment::BufferedInternal(
     MediaSourceTracer* tracer) const {
+  VerifyCalledWhileContextsAliveForDebugging();
+
   return GetMediaSource(tracer)->BufferedInternal();
 }
 
 WebTimeRanges SameThreadMediaSourceAttachment::SeekableInternal(
     MediaSourceTracer* tracer) const {
-  return GetMediaSource(tracer)->SeekableInternal();
-}
+  VerifyCalledWhileContextsAliveForDebugging();
 
-TimeRanges* SameThreadMediaSourceAttachment::Buffered(
-    MediaSourceTracer* tracer) const {
-  return GetMediaSource(tracer)->Buffered();
+  return GetMediaSource(tracer)->SeekableInternal();
 }
 
 void SameThreadMediaSourceAttachment::OnTrackChanged(MediaSourceTracer* tracer,
                                                      TrackBase* track) {
+  // In this same thread implementation, the MSE side of the attachment can loop
+  // back into this from SourceBuffer's initialization segment received
+  // algorithm notifying the element, which then calls this. Regardless, we are
+  // not called as part of execution context teardown, so verification should be
+  // stable here.
+  VerifyCalledWhileContextsAliveForDebugging();
+
   GetMediaSource(tracer)->OnTrackChanged(track);
 }
 
+void SameThreadMediaSourceAttachment::OnElementTimeUpdate(double time) {
+  DVLOG(3) << __func__ << " this=" << this << ", time=" << time;
+
+  VerifyCalledWhileContextsAliveForDebugging();
+
+  recent_element_time_ = time;
+}
+
+void SameThreadMediaSourceAttachment::OnElementError() {
+  DVLOG(3) << __func__ << " this=" << this;
+
+  VerifyCalledWhileContextsAliveForDebugging();
+
+  DCHECK(!element_has_error_)
+      << "At most one transition to element error per attachment is expected";
+
+  element_has_error_ = true;
+}
+
+void SameThreadMediaSourceAttachment::OnElementContextDestroyed() {
+  DVLOG(3) << __func__ << " this=" << this;
+
+  // We should only be notified once.
+  DCHECK(!element_context_destroyed_);
+
+  element_context_destroyed_ = true;
+}
+
+void SameThreadMediaSourceAttachment::OnMediaSourceContextDestroyed() {
+  DVLOG(3) << __func__ << " this=" << this;
+
+  // We should only be notified once.
+  DCHECK(!element_context_destroyed_);
+
+  media_source_context_destroyed_ = true;
+}
+
+void SameThreadMediaSourceAttachment::
+    VerifyCalledWhileContextsAliveForDebugging() const {
+  DCHECK(!element_context_destroyed_);
+  DCHECK(!media_source_context_destroyed_);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/mediasource/same_thread_media_source_attachment.h b/third_party/blink/renderer/modules/mediasource/same_thread_media_source_attachment.h
index c571554..832746d 100644
--- a/third_party/blink/renderer/modules/mediasource/same_thread_media_source_attachment.h
+++ b/third_party/blink/renderer/modules/mediasource/same_thread_media_source_attachment.h
@@ -5,6 +5,9 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_SAME_THREAD_MEDIA_SOURCE_ATTACHMENT_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASOURCE_SAME_THREAD_MEDIA_SOURCE_ATTACHMENT_H_
 
+#include <memory>
+
+#include "third_party/blink/public/platform/web_time_range.h"
 #include "third_party/blink/renderer/modules/mediasource/media_source.h"
 #include "third_party/blink/renderer/modules/mediasource/media_source_attachment_supplement.h"
 
@@ -20,25 +23,44 @@
   explicit SameThreadMediaSourceAttachment(MediaSource* media_source);
 
   // MediaSourceAttachmentSupplement
-  void NotifyDurationChanged(MediaSourceTracer* tracer,
-                             double duration) override;
+  void NotifyDurationChanged(MediaSourceTracer* tracer, double duration) final;
+  double GetRecentMediaTime(MediaSourceTracer* tracer) final;
+  bool GetElementError(MediaSourceTracer* tracer) final;
+  void OnMediaSourceContextDestroyed() final;
 
   // MediaSourceAttachment
-  MediaSourceTracer* StartAttachingToMediaElement(HTMLMediaElement*) override;
+  MediaSourceTracer* StartAttachingToMediaElement(HTMLMediaElement*,
+                                                  bool* success) override;
   void CompleteAttachingToMediaElement(
       MediaSourceTracer* tracer,
       std::unique_ptr<WebMediaSource>) override;
 
   void Close(MediaSourceTracer* tracer) override;
-  double duration(MediaSourceTracer* tracer) const override;
   WebTimeRanges BufferedInternal(MediaSourceTracer* tracer) const override;
   WebTimeRanges SeekableInternal(MediaSourceTracer* tracer) const override;
-  TimeRanges* Buffered(MediaSourceTracer* tracer) const override;
   void OnTrackChanged(MediaSourceTracer* tracer, TrackBase*) override;
 
+  void OnElementTimeUpdate(double time) final;
+  void OnElementError() final;
+  void OnElementContextDestroyed() final;
+
  private:
   ~SameThreadMediaSourceAttachment() override;
 
+  // In this same thread implementation, if the media element context is
+  // destroyed, then so should be the Media Source's context. This method
+  // this precondition in debug mode.
+  void VerifyCalledWhileContextsAliveForDebugging() const;
+
+  // These are mostly used to verify correct behavior of the media element and
+  // media source state pumping in debug builds. In a cross-thread attachment
+  // implementation, state like this will be relied upon for servicing the
+  // MediaSource API.
+  double recent_element_time_;           // See OnElementTimeUpdate().
+  bool element_has_error_;               // See OnElementError().
+  bool element_context_destroyed_;       // See OnElementContextDestroyed().
+  bool media_source_context_destroyed_;  // See OnMediaSourceContextDestroyed().
+
   DISALLOW_COPY_AND_ASSIGN(SameThreadMediaSourceAttachment);
 };
 
diff --git a/third_party/blink/renderer/modules/mediasource/source_buffer.cc b/third_party/blink/renderer/modules/mediasource/source_buffer.cc
index 5b4556655..1a6e4d34e 100644
--- a/third_party/blink/renderer/modules/mediasource/source_buffer.cc
+++ b/third_party/blink/renderer/modules/mediasource/source_buffer.cc
@@ -126,6 +126,9 @@
   DCHECK(web_source_buffer_);
   DCHECK(source_);
   DCHECK(source_->MediaElement());
+  // TODO(https://crbug.com/878133): Enable construction of media tracks that
+  // don't reference the media element if, for instance, they are owned by a
+  // different execution context.
   audio_tracks_ =
       MakeGarbageCollected<AudioTrackList>(*source_->MediaElement());
   video_tracks_ =
@@ -770,8 +773,13 @@
 
 double SourceBuffer::GetMediaTime() {
   double media_time = std::numeric_limits<float>::quiet_NaN();
-  if (source_ && source_->MediaElement())
-    media_time = source_->MediaElement()->currentTime();
+  if (source_) {
+    scoped_refptr<MediaSourceAttachmentSupplement> attachment;
+    MediaSourceTracer* tracer;
+    std::tie(attachment, tracer) = source_->AttachmentAndTracer();
+    if (attachment)
+      media_time = attachment->GetRecentMediaTime(tracer);
+  }
   return media_time;
 }
 
@@ -1210,8 +1218,12 @@
   // 3. If the HTMLMediaElement.error attribute is not null, then throw an
   //    InvalidStateError exception and abort these steps.
   DCHECK(source_);
-  DCHECK(source_->MediaElement());
-  if (source_->MediaElement()->error()) {
+  scoped_refptr<MediaSourceAttachmentSupplement> attachment;
+  MediaSourceTracer* tracer;
+  std::tie(attachment, tracer) = source_->AttachmentAndTracer();
+  DCHECK(attachment);
+  DCHECK(tracer);
+  if (attachment->GetElementError(tracer)) {
     MediaSource::LogAndThrowDOMException(
         exception_state, DOMExceptionCode::kInvalidStateError,
         "The HTMLMediaElement.error attribute is not null.");
diff --git a/third_party/blink/renderer/modules/payments/payment_request.cc b/third_party/blink/renderer/modules/payments/payment_request.cc
index 770903f0..aefe1245 100644
--- a/third_party/blink/renderer/modules/payments/payment_request.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request.cc
@@ -598,7 +598,8 @@
   if (exception_state.HadException())
     return;
   if (input->hasTotal()) {
-    DCHECK(!RuntimeEnabledFeatures::DigitalGoodsEnabled() || !ignore_total);
+    DCHECK(!RuntimeEnabledFeatures::DigitalGoodsEnabled(&execution_context) ||
+           !ignore_total);
     if (ignore_total) {
       output->total =
           CreateTotalPlaceHolderForAppStoreBilling(execution_context);
@@ -1196,7 +1197,11 @@
           this,
           &PaymentRequest::OnUpdatePaymentDetailsTimeout),
       is_waiting_for_show_promise_to_resolve_(false) {
+  // options_, details has default value, so could never be null, according to
+  // payment_request.idl.
+  DCHECK(options_);
   DCHECK(details);
+
   DCHECK(GetExecutionContext()->IsSecureContext());
   if (!AllowedToUsePaymentRequest(execution_context)) {
     exception_state.ThrowSecurityError(
@@ -1229,8 +1234,9 @@
   if (exception_state.HadException())
     return;
 
-  ignore_total_ = RuntimeEnabledFeatures::DigitalGoodsEnabled() &&
-                  RequestingOnlyAppStoreBillingMethods(validated_method_data);
+  ignore_total_ =
+      RuntimeEnabledFeatures::DigitalGoodsEnabled(GetExecutionContext()) &&
+      RequestingOnlyAppStoreBillingMethods(validated_method_data);
   ValidateAndConvertPaymentDetailsInit(details, options_, validated_details,
                                        shipping_option_, ignore_total_,
                                        *GetExecutionContext(), exception_state);
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
index ebfc413c..bd425f6f 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
@@ -55,6 +55,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/core/v8/source_location.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
 #include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_background_fetch_event_init.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_content_index_event_init.h"
@@ -825,22 +826,24 @@
   return features::kInstallingServiceWorkerOutstandingThrottledLimit.Get();
 }
 
-void ServiceWorkerGlobalScope::importScripts(const Vector<String>& urls,
-                                             ExceptionState& exception_state) {
+void ServiceWorkerGlobalScope::importScripts(const Vector<String>& urls) {
   for (const String& string_url : urls) {
     KURL completed_url = CompleteURL(string_url);
     if (installed_scripts_manager_ &&
         !installed_scripts_manager_->IsScriptInstalled(completed_url)) {
       DCHECK(installed_scripts_manager_->IsScriptInstalled(Url()));
-      exception_state.ThrowDOMException(
-          DOMExceptionCode::kNetworkError,
-          "Failed to import '" + completed_url.ElidedString() +
-              "'. importScripts() of new scripts after service worker "
-              "installation is not allowed.");
+      v8::Isolate* isolate = GetThread()->GetIsolate();
+      V8ThrowException::ThrowException(
+          isolate,
+          V8ThrowDOMException::CreateOrEmpty(
+              isolate, DOMExceptionCode::kNetworkError,
+              "Failed to import '" + completed_url.ElidedString() +
+                  "'. importScripts() of new scripts after service worker "
+                  "installation is not allowed."));
       return;
     }
   }
-  WorkerGlobalScope::importScripts(urls, exception_state);
+  WorkerGlobalScope::importScripts(urls);
 }
 
 SingleCachedMetadataHandler*
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
index da50e108..d5fd966 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
@@ -339,7 +339,7 @@
       const override;
 
  private:
-  void importScripts(const Vector<String>& urls, ExceptionState&) override;
+  void importScripts(const Vector<String>& urls) override;
   SingleCachedMetadataHandler* CreateWorkerScriptCachedMetadataHandler(
       const KURL& script_url,
       std::unique_ptr<Vector<uint8_t>> meta_data) override;
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc
index fa6a04d4..493004a99 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc
@@ -203,22 +203,6 @@
                          testing::Values(TextDirection::kLtr,
                                          TextDirection::kRtl));
 
-TEST_F(HarfBuzzShaperTest, MutableUnique) {
-  scoped_refptr<ShapeResult> result =
-      ShapeResult::Create(&font, 0, 0, TextDirection::kLtr);
-  EXPECT_TRUE(result->HasOneRef());
-
-  // At this point, |result| has only one ref count.
-  scoped_refptr<ShapeResult> result2 = result->MutableUnique();
-  EXPECT_EQ(result.get(), result2.get());
-  EXPECT_FALSE(result2->HasOneRef());
-
-  // Since |result| has 2 ref counts, it should return a clone.
-  scoped_refptr<ShapeResult> result3 = result->MutableUnique();
-  EXPECT_NE(result.get(), result3.get());
-  EXPECT_TRUE(result3->HasOneRef());
-}
-
 TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsLatin) {
   String latin_common = To16Bit("ABC DEF.", 8);
   HarfBuzzShaper shaper(latin_common);
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
index d4134bd..f70d3b38 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
@@ -414,12 +414,6 @@
   return self_byte_size;
 }
 
-scoped_refptr<ShapeResult> ShapeResult::MutableUnique() const {
-  if (HasOneRef())
-    return const_cast<ShapeResult*>(this);
-  return ShapeResult::Create(*this);
-}
-
 unsigned ShapeResult::NextSafeToBreakOffset(unsigned index) const {
   for (auto* it = runs_.begin(); it != runs_.end(); ++it) {
     const auto& run = *it;
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
index 74eb4ea..327fff59e3 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
@@ -155,10 +155,6 @@
       const OpenTypeMathStretchData::AssemblyParameters&);
   ~ShapeResult();
 
-  // Returns a mutable unique instance. If |this| has more than 1 ref count,
-  // a clone is created.
-  scoped_refptr<ShapeResult> MutableUnique() const;
-
   // The logical width of this result.
   float Width() const { return width_; }
   LayoutUnit SnappedWidth() const { return LayoutUnit::FromFloatCeil(width_); }
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index c42873d..f64798f 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -662,6 +662,8 @@
     },
     {
       name: "DigitalGoods",
+      origin_trial_feature_name: "DigitalGoods",
+      origin_trial_os: ["android"],
       status: "experimental",
     },
     {
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/base.py b/third_party/blink/tools/blinkpy/web_tests/port/base.py
index c1411025..bb65e8aa 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/base.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/base.py
@@ -135,6 +135,7 @@
         ('mac10.13', 'x86'),
         ('mac10.14', 'x86'),
         ('mac10.15', 'x86'),
+        ('mac11.0', 'x86'),
         ('win7', 'x86'),
         ('win10', 'x86'),
         ('trusty', 'x86_64'),
@@ -142,10 +143,10 @@
     )
 
     CONFIGURATION_SPECIFIER_MACROS = {
-        'mac': ['mac10.12', 'mac10.13', 'mac10.14', 'mac10.15'],
+        'mac': ['mac10.12', 'mac10.13', 'mac10.14', 'mac10.15', 'mac11.0'],
         'win': ['win7', 'win10'],
         'linux': ['trusty'],
-        'fuschia': ['fuchsia'],
+        'fuchsia': ['fuchsia'],
     }
 
     # List of ports open on the host that the tests will connect to. When tests
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/base_unittest.py b/third_party/blink/tools/blinkpy/web_tests/port/base_unittest.py
index c78d6f2..908bdab 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/base_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/base_unittest.py
@@ -39,6 +39,7 @@
 from blinkpy.common.system.system_host import SystemHost
 from blinkpy.common.system.system_host_mock import MockSystemHost
 from blinkpy.web_tests.port.base import Port, VirtualTestSuite
+from blinkpy.web_tests.port.factory import PortFactory
 from blinkpy.web_tests.port.test import add_unit_tests_to_mock_filesystem, WEB_TEST_DIR, TestPort
 
 MOCK_WEB_TESTS = '/mock-checkout/' + RELATIVE_WEB_TESTS
@@ -1712,7 +1713,6 @@
         self.assertIn('--disable-system-font-check',
                       port.additional_driver_flags())
 
-
     def test_enable_tracing(self):
         options, _ = optparse.OptionParser().parse_args([])
         options.enable_tracing = '*,-blink'
@@ -1724,6 +1724,27 @@
                 '--trace-startup-file=trace_layout_test_non_virtual_TIME.json',
             ], port.args_for_test('non/virtual'))
 
+    def test_all_systems(self):
+        # Port.ALL_SYSTEMS should match CONFIGURATION_SPECIFIER_MACROS.
+        all_systems = []
+        for system in Port.ALL_SYSTEMS:
+            self.assertEqual(len(system), 2)
+            all_systems.append(system[0])
+        all_systems.sort()
+        configuration_specifier_macros = []
+        for macros in Port.CONFIGURATION_SPECIFIER_MACROS.values():
+            configuration_specifier_macros += macros
+        configuration_specifier_macros.sort()
+        self.assertListEqual(all_systems, configuration_specifier_macros)
+
+    def test_configuration_specifier_macros(self):
+        # CONFIGURATION_SPECIFIER_MACROS should contain all SUPPORTED_VERSIONS
+        # of each port. Must use real Port classes in this test.
+        for port_name, versions in Port.CONFIGURATION_SPECIFIER_MACROS.items():
+            port_class, _ = PortFactory.get_port_class(port_name)
+            self.assertIsNotNone(port_class, port_name)
+            self.assertListEqual(versions, list(port_class.SUPPORTED_VERSIONS))
+
 
 class NaturalCompareTest(unittest.TestCase):
     def setUp(self):
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/factory.py b/third_party/blink/tools/blinkpy/web_tests/port/factory.py
index 2345de24..40159d4 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/factory.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/factory.py
@@ -69,26 +69,35 @@
 
         _check_configuration_and_target(self._host.filesystem, options)
 
+        port_class, class_name = self.get_port_class(port_name)
+        if port_class is None:
+            raise NotImplementedError('unsupported platform: "%s"' % port_name)
+
+        full_port_name = port_class.determine_full_port_name(
+            self._host, options,
+            class_name if 'browser_test' in port_name else port_name)
+        return port_class(self._host,
+                          full_port_name,
+                          options=options,
+                          **kwargs)
+
+    @classmethod
+    def get_port_class(cls, port_name):
+        """Returns a Port subclass and its name for the given port_name."""
         if 'browser_test' in port_name:
             module_name, class_name = port_name.rsplit('.', 1)
             module = __import__(module_name, globals(), locals(), [], -1)
             port_class_name = module.get_port_class_name(class_name)
             if port_class_name is not None:
-                cls = module.__dict__[port_class_name]
-                port_name = cls.determine_full_port_name(
-                    self._host, options, class_name)
-                return cls(self._host, port_name, options=options, **kwargs)
+                return module.__dict__[port_class_name], class_name
         else:
-            for port_class in self.PORT_CLASSES:
+            for port_class in cls.PORT_CLASSES:
                 module_name, class_name = port_class.rsplit('.', 1)
                 module = __import__(module_name, globals(), locals(), [], -1)
-                cls = module.__dict__[class_name]
-                if port_name.startswith(cls.port_name):
-                    port_name = cls.determine_full_port_name(
-                        self._host, options, port_name)
-                    return cls(
-                        self._host, port_name, options=options, **kwargs)
-        raise NotImplementedError('unsupported platform: "%s"' % port_name)
+                port_class = module.__dict__[class_name]
+                if port_name.startswith(port_class.port_name):
+                    return port_class, class_name
+        return None, None
 
     def all_port_names(self, platform=None):
         """Returns a list of all valid, fully-specified, "real" port names.
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 0ba6520..982b65d 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -75,6 +75,9 @@
 # Tested by paint/background/root-element-background-transparency.html for now.
 external/wpt/css/compositing/root-element-background-transparency.html [ Failure ]
 
+# PaintPropertyTreeBuilder bug.
+crbug.com/1116358 external/wpt/css/css-transforms/scrolalble-scroll-3d-transform-z.html [ Failure ]
+
 # ====== Synchronous, budgeted HTML parser tests from here ======
 
 ### virtual/synchronous_html_parser/http/tests/preload/
@@ -1022,7 +1025,6 @@
 crbug.com/1079031 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-contained-absolute.html [ Failure ]
 crbug.com/1079031 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-containing-002.xht [ Crash Failure ]
 crbug.com/1079031 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-fill-auto-002.xht [ Crash Failure ]
-crbug.com/829028 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-fill-auto-block-children-001.xht [ Failure ]
 crbug.com/1079031 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-fill-balance-001.xht [ Crash Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-gap-large-001.xht [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-inherit-001.xht [ Failure ]
@@ -1040,8 +1042,6 @@
 crbug.com/1079031 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-rule-fraction-003.xht [ Crash Failure ]
 crbug.com/1079031 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-009.html [ Crash Failure ]
 crbug.com/1079031 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-010.html [ Failure ]
-crbug.com/829028 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-children-height-002.html [ Failure ]
-crbug.com/829028 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-children-height-003.html [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-children-height-006.html [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-children-height-008.html [ Failure ]
 crbug.com/874051 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-fieldset-002.html [ Failure Crash ]
@@ -1795,7 +1795,6 @@
 crbug.com/1075869 http/tests/devtools/elements/styles-3/spectrum.js [ Pass Failure ]
 crbug.com/1075869 http/tests/devtools/elements/styles-4/styles-invalid-color-values.js [ Pass Failure ]
 crbug.com/1075869 http/tests/devtools/extensions/extensions-timeline-api.js [ Pass Failure Timeout ]
-crbug.com/1125357 http/tests/devtools/elements/styles-3/styles-cssom-important-property.js [ Pass Failure ]
 
 # On these platforms (all but Android) media tests don't currently use gpu-accelerated (proprietary) codecs, so no
 # benefit to running them again with gpu acceleration enabled.
@@ -2531,10 +2530,7 @@
 crbug.com/1105958 external/wpt/payment-request/payment-is-showing.https.html [ Timeout ]
 
 # ====== New tests from wpt-importer added here ======
-crbug.com/626703 [ Linux ] external/wpt/fetch/connection-pool/network-partition-key.html [ Timeout ]
-crbug.com/626703 [ Mac ] external/wpt/fetch/connection-pool/network-partition-key.html [ Timeout ]
-crbug.com/626703 [ Mac11.0 ] external/wpt/fetch/connection-pool/network-partition-key.html [ Timeout ]
-crbug.com/626703 [ Win ] external/wpt/fetch/connection-pool/network-partition-key.html [ Timeout ]
+crbug.com/626703 external/wpt/fetch/connection-pool/network-partition-key.html [ Timeout ]
 crbug.com/626703 [ Mac10.15 ] external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-top-left.html [ Timeout ]
 crbug.com/626703 external/wpt/css/css-shapes/shape-outside/supported-shapes/circle/shape-outside-circle-043.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-048.html [ Failure ]
@@ -2570,11 +2566,7 @@
 crbug.com/626703 [ Win7 ] external/wpt/html/cross-origin-embedder-policy/reporting-subresource-corp.https.html [ Failure Timeout ]
 crbug.com/626703 external/wpt/css/css-sizing/aspect-ratio/replaced-element-016.tentative.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-sizing/aspect-ratio/replaced-element-021.tentative.html [ Failure ]
-crbug.com/626703 [ Mac10.12 ] external/wpt/webrtc-insertable-streams/RTCPeerConnection-insertable-streams.https.html [ Timeout ]
-crbug.com/626703 [ Mac10.13 ] external/wpt/webrtc-insertable-streams/RTCPeerConnection-insertable-streams.https.html [ Timeout ]
-crbug.com/626703 [ Mac10.14 ] external/wpt/webrtc-insertable-streams/RTCPeerConnection-insertable-streams.https.html [ Timeout ]
-crbug.com/626703 [ Mac10.15 ] external/wpt/webrtc-insertable-streams/RTCPeerConnection-insertable-streams.https.html [ Timeout ]
-crbug.com/626703 [ Mac11.0 ] external/wpt/webrtc-insertable-streams/RTCPeerConnection-insertable-streams.https.html [ Timeout ]
+crbug.com/626703 [ Mac ] external/wpt/webrtc-insertable-streams/RTCPeerConnection-insertable-streams.https.html [ Timeout ]
 crbug.com/626703 external/wpt/content-security-policy/frame-src/frame-src-same-document.sub.html [ Timeout ]
 crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-backspace.tentative.html [ Timeout ]
 crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-forwarddelete.tentative.html [ Timeout ]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/scrolalble-hidden-3d-transform-z-ref.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/scrolalble-hidden-3d-transform-z-ref.html
new file mode 100644
index 0000000..b2399db
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/scrolalble-hidden-3d-transform-z-ref.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<div style="width: 100px; height: 100px; background: green"></div>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/scrolalble-hidden-3d-transform-z.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/scrolalble-hidden-3d-transform-z.html
new file mode 100644
index 0000000..5d539f6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/scrolalble-hidden-3d-transform-z.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<link rel="author" title="Seokho Song"  href="mailto:0xdevssh@gmail.com">
+<link rel="help" href="https://www.w3.org/TR/css-transforms-2/#3d-transform-rendering/">
+<link rel="match" href="scrolalble-hidden-3d-transform-z-ref.html">
+<style>
+#container {
+  width: 100px;
+  height: 100px;
+  background: green;
+  position: relative;
+  transform-style: preserve-3d;
+}
+#scroller {
+  width: 100px;
+  height: 100px;
+  background: red;
+  position: absolute;
+  transform: translateZ(-1px);
+  overflow-y: hidden;
+}
+</style>
+<div id="container">
+  <div id="scroller">
+    <div style="height: 300px"></div>
+  </div>
+</div>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/scrolalble-scroll-3d-transform-z-ref.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/scrolalble-scroll-3d-transform-z-ref.html
new file mode 100644
index 0000000..b2399db
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/scrolalble-scroll-3d-transform-z-ref.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<div style="width: 100px; height: 100px; background: green"></div>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/scrolalble-scroll-3d-transform-z.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/scrolalble-scroll-3d-transform-z.html
new file mode 100644
index 0000000..fd273fd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/scrolalble-scroll-3d-transform-z.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<link rel="author" title="Seokho Song"  href="mailto:0xdevssh@gmail.com">
+<link rel="help" href="https://www.w3.org/TR/css-transforms-2/#3d-transform-rendering/">
+<link rel="match" href="scrolalble-scroll-3d-transform-z-ref.html">
+<style>
+#container {
+  width: 100px;
+  height: 100px;
+  background: green;
+  position: relative;
+  transform-style: preserve-3d;
+}
+#scroller {
+  width: 100px;
+  height: 100px;
+  background: red;
+  position: absolute;
+  transform: translateZ(-1px);
+  overflow-y: scroll;
+}
+</style>
+<div id="container">
+  <div id="scroller">
+    <div style="height: 300px"></div>
+  </div>
+</div>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/evaluation-order-1-sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/evaluation-order-1-sharedworker-expected.txt
deleted file mode 100644
index 7ce88a5..0000000
--- a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/evaluation-order-1-sharedworker-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Test evaluation order of modules assert_array_equals: expected property 2 to be "global-error" but got "microtask" (expected array ["step-1-1", "step-1-2", "global-error", "error", "microtask"] got ["step-1-1", "step-1-2", "microtask", "global-error", "error"])
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/evaluation-order-1-worker-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/evaluation-order-1-worker-expected.txt
deleted file mode 100644
index 7ce88a5..0000000
--- a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/evaluation-order-1-worker-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Test evaluation order of modules assert_array_equals: expected property 2 to be "global-error" but got "microtask" (expected array ["step-1-1", "step-1-2", "global-error", "error", "microtask"] got ["step-1-1", "step-1-2", "microtask", "global-error", "error"])
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/microtasks/checkpoint-after-workerglobalscope-onerror-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/microtasks/checkpoint-after-workerglobalscope-onerror-expected.txt
deleted file mode 100644
index 40f3999..0000000
--- a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/microtasks/checkpoint-after-workerglobalscope-onerror-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-FAIL Promise resolved during #report-the-error assert_array_equals: expected property 1 to be "handler 2" but got "handler 1 promise" (expected array ["handler 1", "handler 2", "handler 1 promise", "handler 2 promise"] got ["handler 1", "handler 1 promise", "handler 2", "handler 2 promise"])
-PASS Promise resolved during event handlers other than error
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/mathml/crashtests/multicol-on-token-elements.html b/third_party/blink/web_tests/external/wpt/mathml/crashtests/multicol-on-token-elements.html
new file mode 100644
index 0000000..9fc00eb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/crashtests/multicol-on-token-elements.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<math><mi style="column-count: 10">mi</mi></math>
+<math><mi style="column-width: 10px">mi</mi></math>
+<math><mn style="column-count: 10">mn</mn></math>
+<math><mn style="column-width: 10px">mn</mn></math>
+<math><mo style="column-count: 10">mo</mo></math>
+<math><mo style="column-width: 10px">mo</mo></math>
+<math><ms style="column-count: 10">ms</ms></math>
+<math><ms style="column-width: 10px">ms</ms></math>
+<math><mtext style="column-count: 10">mtext</mtext></math>
+<math><mtext style="column-width: 10px">mtext</mtext></math>
diff --git a/third_party/blink/web_tests/external/wpt/picture-in-picture/OWNERS b/third_party/blink/web_tests/external/wpt/picture-in-picture/OWNERS
new file mode 100644
index 0000000..f7dde29
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/picture-in-picture/OWNERS
@@ -0,0 +1 @@
+# COMPONENT: Blink>Media>PictureInPicture
diff --git a/third_party/blink/web_tests/external/wpt/shadow-dom/declarative/element-internals-shadowroot.tentative.html b/third_party/blink/web_tests/external/wpt/shadow-dom/declarative/element-internals-shadowroot.tentative.html
index 8469a6c..aeaa322a 100644
--- a/third_party/blink/web_tests/external/wpt/shadow-dom/declarative/element-internals-shadowroot.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/shadow-dom/declarative/element-internals-shadowroot.tentative.html
@@ -108,6 +108,23 @@
   assert_throws_dom('NotSupportedError', () => element.attachInternals(), 'attachInternals forbidden by disabledFeatures, post-upgrade');
 }, 'ElementInternals disabled by disabledFeatures');
 
-
-
+test(() => {
+  let constructed = false;
+  const element = document.createElement('x-6');
+  const sr = element.attachShadow({mode: 'closed'});
+  assert_true(sr instanceof ShadowRoot);
+  customElements.define('x-6', class extends HTMLElement {
+    constructor() {
+      super();
+      assert_throws_dom('NotSupportedError', () => this.attachShadow({mode:'open'}), 'attachShadow already called');
+      const elementInternals = this.attachInternals();
+      assert_equals(elementInternals.shadowRoot, null, 'ElementInternals.shadowRoot should not be available for pre-attached shadow');
+      constructed = true;
+    }
+  });
+  assert_false(constructed);
+  customElements.upgrade(element);
+  assert_true(constructed,'Failed to construct - test failed');
+  assert_equals(element.shadowRoot, null, 'shadow root is closed');
+}, 'ElementInternals.shadowRoot doesn\'t reveal pre-attached closed shadowRoot');
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/wasm/jsapi/table/grow-reftypes.tentative.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/wasm/jsapi/table/grow-reftypes.tentative.any.worker-expected.txt
index 4354c6fb..7d6bf80 100644
--- a/third_party/blink/web_tests/external/wpt/wasm/jsapi/table/grow-reftypes.tentative.any.worker-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/wasm/jsapi/table/grow-reftypes.tentative.any.worker-expected.txt
@@ -1,4 +1,4 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Uncaught 
+Harness Error. harness_status.status = 1 , harness_status.message = Uncaught NetworkError: Failed to execute 'importScripts' on 'WorkerGlobalScope': The script at 'http://web-platform.test:8001/wasm/jsapi/wasm-constants.js' failed to load.
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webtransport/quic/client-indication.sub.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/webtransport/quic/client-indication.sub.any.worker-expected.txt
index 4354c6fb..ef7377a 100644
--- a/third_party/blink/web_tests/external/wpt/webtransport/quic/client-indication.sub.any.worker-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webtransport/quic/client-indication.sub.any.worker-expected.txt
@@ -1,4 +1,4 @@
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Uncaught 
+Harness Error. harness_status.status = 1 , harness_status.message = Uncaught NetworkError: Failed to execute 'importScripts' on 'WorkerGlobalScope': The script at 'http://web-platform.test:8001/webtransport/quic/client-indication.sub.any.js' failed to load.
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerGlobalScope/onerror/message-classic-DOMException-expected.txt b/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerGlobalScope/onerror/message-classic-DOMException-expected.txt
deleted file mode 100644
index 0743ef6..0000000
--- a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerGlobalScope/onerror/message-classic-DOMException-expected.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-This is a testharness.js-based test.
-FAIL Throw DOMException-TypeError in toplevel: classic: listener assert_regexp_match: e.message should contain the message of the thrown error expected object "/Throw in/" but got "Uncaught "
-FAIL Throw DOMException-TypeError in toplevel: classic: handler assert_regexp_match: e.message should contain the message of the thrown error expected object "/Throw in/" but got "Uncaught "
-PASS Throw DOMException-TypeError in setTimeout-function: classic: listener
-PASS Throw DOMException-TypeError in setTimeout-function: classic: handler
-FAIL Throw DOMException-TypeError in setTimeout-string: classic: listener assert_regexp_match: e.message should contain the message of the thrown error expected object "/Throw in/" but got "Uncaught "
-FAIL Throw DOMException-TypeError in setTimeout-string: classic: handler assert_regexp_match: e.message should contain the message of the thrown error expected object "/Throw in/" but got "Uncaught "
-PASS Throw DOMException-TypeError in onmessage: classic: listener
-PASS Throw DOMException-TypeError in onmessage: classic: handler
-PASS Throw DOMException-TypeError in onerror: classic: listener
-PASS Throw DOMException-TypeError in onerror: classic: handler
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerGlobalScope/onerror/message-module-DOMException-expected.txt b/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerGlobalScope/onerror/message-module-DOMException-expected.txt
index d1238f95..00118cc 100644
--- a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerGlobalScope/onerror/message-module-DOMException-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerGlobalScope/onerror/message-module-DOMException-expected.txt
@@ -3,8 +3,8 @@
 FAIL Throw DOMException-TypeError in toplevel: module: handler assert_regexp_match: e.message should contain the message of the thrown error expected object "/Throw in/" but got "Uncaught "
 PASS Throw DOMException-TypeError in setTimeout-function: module: listener
 PASS Throw DOMException-TypeError in setTimeout-function: module: handler
-FAIL Throw DOMException-TypeError in setTimeout-string: module: listener assert_regexp_match: e.message should contain the message of the thrown error expected object "/Throw in/" but got "Uncaught "
-FAIL Throw DOMException-TypeError in setTimeout-string: module: handler assert_regexp_match: e.message should contain the message of the thrown error expected object "/Throw in/" but got "Uncaught "
+PASS Throw DOMException-TypeError in setTimeout-string: module: listener
+PASS Throw DOMException-TypeError in setTimeout-string: module: handler
 PASS Throw DOMException-TypeError in onmessage: module: listener
 PASS Throw DOMException-TypeError in onmessage: module: handler
 PASS Throw DOMException-TypeError in onerror: module: listener
diff --git a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/catch.sub.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/catch.sub.any.serviceworker-expected.txt
deleted file mode 100644
index 32ebda0..0000000
--- a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/catch.sub.any.serviceworker-expected.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-This is a testharness.js-based test.
-PASS Same-origin syntax error
-PASS Same-origin throw
-FAIL Cross-origin syntax error assert_throws_dom: function "function() {
-    importScripts(crossOrigin +
-                  "/workers/modules/resources/syntax-error.js");
-  }" threw null, not an object
-FAIL Cross-origin throw assert_throws_dom: function "function() {
-    importScripts(crossOrigin +
-                  "/workers/modules/resources/throw.js");
-  }" threw null, not an object
-PASS Redirect-to-cross-origin syntax error
-PASS Redirect-to-Cross-origin throw
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/catch.sub.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/catch.sub.any.sharedworker-expected.txt
deleted file mode 100644
index 1942e64d..0000000
--- a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/catch.sub.any.sharedworker-expected.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-This is a testharness.js-based test.
-PASS Same-origin syntax error
-PASS Same-origin throw
-FAIL Cross-origin syntax error assert_throws_dom: function "function() {
-    importScripts(crossOrigin +
-                  "/workers/modules/resources/syntax-error.js");
-  }" threw null, not an object
-FAIL Cross-origin throw assert_throws_dom: function "function() {
-    importScripts(crossOrigin +
-                  "/workers/modules/resources/throw.js");
-  }" threw null, not an object
-FAIL Redirect-to-cross-origin syntax error assert_throws_dom: function "function() {
-    importScripts(redirectToCrossOrigin +
-                  "/workers/modules/resources/syntax-error.js");
-  }" threw null, not an object
-FAIL Redirect-to-Cross-origin throw assert_throws_dom: function "function() {
-    importScripts(redirectToCrossOrigin +
-                  "/workers/modules/resources/throw.js");
-  }" threw null, not an object
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/catch.sub.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/catch.sub.any.worker-expected.txt
deleted file mode 100644
index 1942e64d..0000000
--- a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/catch.sub.any.worker-expected.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-This is a testharness.js-based test.
-PASS Same-origin syntax error
-PASS Same-origin throw
-FAIL Cross-origin syntax error assert_throws_dom: function "function() {
-    importScripts(crossOrigin +
-                  "/workers/modules/resources/syntax-error.js");
-  }" threw null, not an object
-FAIL Cross-origin throw assert_throws_dom: function "function() {
-    importScripts(crossOrigin +
-                  "/workers/modules/resources/throw.js");
-  }" threw null, not an object
-FAIL Redirect-to-cross-origin syntax error assert_throws_dom: function "function() {
-    importScripts(redirectToCrossOrigin +
-                  "/workers/modules/resources/syntax-error.js");
-  }" threw null, not an object
-FAIL Redirect-to-Cross-origin throw assert_throws_dom: function "function() {
-    importScripts(redirectToCrossOrigin +
-                  "/workers/modules/resources/throw.js");
-  }" threw null, not an object
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-cross-origin.sub.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-cross-origin.sub.any.sharedworker-expected.txt
deleted file mode 100644
index db410757..0000000
--- a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-cross-origin.sub.any.sharedworker-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-FAIL WorkerGlobalScope error event: error Cannot read property 'constructor' of null
-FAIL WorkerGlobalScope error event: message assert_not_equals: e.message should not be muted to 'Script error.' got disallowed value "Script error."
-FAIL WorkerGlobalScope error event: filename assert_equals: expected "http://web-platform.test:8001/workers/interfaces/WorkerUtils/importScripts/report-error-helper.js" but got ""
-FAIL WorkerGlobalScope error event: lineno assert_equals: expected 8 but got 0
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-cross-origin.sub.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-cross-origin.sub.any.worker-expected.txt
deleted file mode 100644
index db410757..0000000
--- a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-cross-origin.sub.any.worker-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-FAIL WorkerGlobalScope error event: error Cannot read property 'constructor' of null
-FAIL WorkerGlobalScope error event: message assert_not_equals: e.message should not be muted to 'Script error.' got disallowed value "Script error."
-FAIL WorkerGlobalScope error event: filename assert_equals: expected "http://web-platform.test:8001/workers/interfaces/WorkerUtils/importScripts/report-error-helper.js" but got ""
-FAIL WorkerGlobalScope error event: lineno assert_equals: expected 8 but got 0
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-redirect-to-cross-origin.sub.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-redirect-to-cross-origin.sub.any.sharedworker-expected.txt
deleted file mode 100644
index db410757..0000000
--- a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-redirect-to-cross-origin.sub.any.sharedworker-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-FAIL WorkerGlobalScope error event: error Cannot read property 'constructor' of null
-FAIL WorkerGlobalScope error event: message assert_not_equals: e.message should not be muted to 'Script error.' got disallowed value "Script error."
-FAIL WorkerGlobalScope error event: filename assert_equals: expected "http://web-platform.test:8001/workers/interfaces/WorkerUtils/importScripts/report-error-helper.js" but got ""
-FAIL WorkerGlobalScope error event: lineno assert_equals: expected 8 but got 0
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-redirect-to-cross-origin.sub.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-redirect-to-cross-origin.sub.any.worker-expected.txt
deleted file mode 100644
index db410757..0000000
--- a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-redirect-to-cross-origin.sub.any.worker-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-FAIL WorkerGlobalScope error event: error Cannot read property 'constructor' of null
-FAIL WorkerGlobalScope error event: message assert_not_equals: e.message should not be muted to 'Script error.' got disallowed value "Script error."
-FAIL WorkerGlobalScope error event: filename assert_equals: expected "http://web-platform.test:8001/workers/interfaces/WorkerUtils/importScripts/report-error-helper.js" but got ""
-FAIL WorkerGlobalScope error event: lineno assert_equals: expected 8 but got 0
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-cross-origin.sub.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-cross-origin.sub.any.sharedworker-expected.txt
deleted file mode 100644
index 81bc6ac..0000000
--- a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-cross-origin.sub.any.sharedworker-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-FAIL WorkerGlobalScope error event: error Cannot read property 'constructor' of null
-PASS WorkerGlobalScope error event: message
-PASS WorkerGlobalScope error event: filename
-PASS WorkerGlobalScope error event: lineno
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-cross-origin.sub.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-cross-origin.sub.any.worker-expected.txt
deleted file mode 100644
index 81bc6ac..0000000
--- a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-cross-origin.sub.any.worker-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-FAIL WorkerGlobalScope error event: error Cannot read property 'constructor' of null
-PASS WorkerGlobalScope error event: message
-PASS WorkerGlobalScope error event: filename
-PASS WorkerGlobalScope error event: lineno
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-redirect-to-cross-origin.sub.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-redirect-to-cross-origin.sub.any.sharedworker-expected.txt
deleted file mode 100644
index 81bc6ac..0000000
--- a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-redirect-to-cross-origin.sub.any.sharedworker-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-FAIL WorkerGlobalScope error event: error Cannot read property 'constructor' of null
-PASS WorkerGlobalScope error event: message
-PASS WorkerGlobalScope error event: filename
-PASS WorkerGlobalScope error event: lineno
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-redirect-to-cross-origin.sub.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-redirect-to-cross-origin.sub.any.worker-expected.txt
deleted file mode 100644
index 81bc6ac..0000000
--- a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-redirect-to-cross-origin.sub.any.worker-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-FAIL WorkerGlobalScope error event: error Cannot read property 'constructor' of null
-PASS WorkerGlobalScope error event: message
-PASS WorkerGlobalScope error event: filename
-PASS WorkerGlobalScope error event: lineno
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-same-origin.sub.any.sharedworker-expected.txt b/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-same-origin.sub.any.sharedworker-expected.txt
deleted file mode 100644
index 736c8c6..0000000
--- a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-same-origin.sub.any.sharedworker-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-PASS WorkerGlobalScope error event: error
-PASS WorkerGlobalScope error event: message
-FAIL WorkerGlobalScope error event: filename assert_equals: expected "http://web-platform.test:8001/workers/modules/resources/syntax-error.js" but got "http://web-platform.test:8001/workers/interfaces/WorkerUtils/importScripts/report-error-helper.js"
-FAIL WorkerGlobalScope error event: lineno assert_equals: expected 1 but got 8
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-same-origin.sub.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-same-origin.sub.any.worker-expected.txt
deleted file mode 100644
index 736c8c6..0000000
--- a/third_party/blink/web_tests/external/wpt/workers/interfaces/WorkerUtils/importScripts/report-error-setTimeout-same-origin.sub.any.worker-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-PASS WorkerGlobalScope error event: error
-PASS WorkerGlobalScope error event: message
-FAIL WorkerGlobalScope error event: filename assert_equals: expected "http://web-platform.test:8001/workers/modules/resources/syntax-error.js" but got "http://web-platform.test:8001/workers/interfaces/WorkerUtils/importScripts/report-error-helper.js"
-FAIL WorkerGlobalScope error event: lineno assert_equals: expected 1 but got 8
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/http/tests/background_sync/oneshot.html b/third_party/blink/web_tests/http/tests/background_sync/oneshot.html
index 35ac7db3..82502eb 100644
--- a/third_party/blink/web_tests/http/tests/background_sync/oneshot.html
+++ b/third_party/blink/web_tests/http/tests/background_sync/oneshot.html
@@ -14,7 +14,7 @@
   const scope = '/resources/scope/background_sync/' + iframe_scope;
   var sync_manager;
 
-  // This test verifies that registration of one-shots fails from an iframe.
+  // This test verifies that one-shot syncs can be registered from an iframe.
   return PermissionsHelper.setPermission('background-sync', 'granted')
     .then(function() {
         return service_worker_unregister_and_register(t, url, scope);
diff --git a/third_party/libvpx/README.chromium b/third_party/libvpx/README.chromium
index aa5e747..ebe65ae4c 100644
--- a/third_party/libvpx/README.chromium
+++ b/third_party/libvpx/README.chromium
@@ -6,9 +6,9 @@
 License File: source/libvpx/LICENSE
 Security Critical: yes
 
-Date: Tuesday August 18 2020
+Date: Monday September 14 2020
 Branch: master
-Commit: 53747dfe65eaf670a7192f55117f3bf1e0280743
+Commit: 97356acb50e212fcfb7c91715718ec70953f780c
 
 Description:
 Contains the sources used to compile libvpx binaries used by Google Chrome and
diff --git a/third_party/libvpx/libvpx_srcs.gni b/third_party/libvpx/libvpx_srcs.gni
index be796cb6..24450c41 100644
--- a/third_party/libvpx/libvpx_srcs.gni
+++ b/third_party/libvpx/libvpx_srcs.gni
@@ -3714,6 +3714,8 @@
   "//third_party/libvpx/source/libvpx/vpx_ports/mem.h",
   "//third_party/libvpx/source/libvpx/vpx_ports/mem_ops.h",
   "//third_party/libvpx/source/libvpx/vpx_ports/mem_ops_aligned.h",
+  "//third_party/libvpx/source/libvpx/vpx_ports/mips.h",
+  "//third_party/libvpx/source/libvpx/vpx_ports/mips_cpudetect.c",
   "//third_party/libvpx/source/libvpx/vpx_ports/msvc.h",
   "//third_party/libvpx/source/libvpx/vpx_ports/static_assert.h",
   "//third_party/libvpx/source/libvpx/vpx_ports/system_state.h",
diff --git a/third_party/libvpx/source/config/vpx_version.h b/third_party/libvpx/source/config/vpx_version.h
index 366fae0..c9472c2 100644
--- a/third_party/libvpx/source/config/vpx_version.h
+++ b/third_party/libvpx/source/config/vpx_version.h
@@ -2,8 +2,8 @@
 #define VERSION_MAJOR 1
 #define VERSION_MINOR 9
 #define VERSION_PATCH 0
-#define VERSION_EXTRA "58-g53747dfe6"
+#define VERSION_EXTRA "65-g97356acb5"
 #define VERSION_PACKED \
   ((VERSION_MAJOR << 16) | (VERSION_MINOR << 8) | (VERSION_PATCH))
-#define VERSION_STRING_NOSP "v1.9.0-58-g53747dfe6"
-#define VERSION_STRING " v1.9.0-58-g53747dfe6"
+#define VERSION_STRING_NOSP "v1.9.0-65-g97356acb5"
+#define VERSION_STRING " v1.9.0-65-g97356acb5"
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 4ae02e7..412582b 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -2162,7 +2162,7 @@
     ],
 
     'official_goma_mac_perf': [
-      'official', 'goma', 'no_keystone_registration_framework', 'full_symbols',
+      'official', 'goma', 'no_keystone_registration_framework', 'no_widevine_cdm_host_verification', 'full_symbols',
     ],
 
     'official_goma_mac_pgo': [
@@ -2897,6 +2897,10 @@
       'gn_args': 'symbol_level=0',
     },
 
+    'no_widevine_cdm_host_verification': {
+      'gn_args': 'enable_widevine_cdm_host_verification=false',
+    },
+
     'official': {
       'mixins': ['official_optimize'],
       'gn_args': 'is_chrome_branded=true',
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 36f08be..1301b23 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -29452,6 +29452,16 @@
   <int value="2" label="CONTENT_DISMISSED"/>
 </enum>
 
+<enum name="FetchFontResult">
+  <int value="0" label="Success"/>
+  <int value="1" label="Failed due to unexpected font name"/>
+  <int value="2" label="Failed with non-OK status code on result"/>
+  <int value="3" label="Failed with non-unique number of font results"/>
+  <int value="4" label="Failed with non-OK result code on font info"/>
+  <int value="5" label="Failed to open font file"/>
+  <int value="6" label="Failed with an exception"/>
+</enum>
+
 <enum name="FetchRequestMode">
   <int value="0" label="SameOrigin"/>
   <int value="1" label="NoCORS"/>
@@ -40589,6 +40599,7 @@
   <int value="-2017953534" label="enable-hosted-app-shim-creation"/>
   <int value="-2017778637" label="PrintSaveToDrive:disabled"/>
   <int value="-2015293660" label="AccessibilityExposeDisplayNone:disabled"/>
+  <int value="-2014948560" label="TabGroupsAutoCreate:enabled"/>
   <int value="-2013551096" label="ViewsSimplifiedFullscreenUI:disabled"/>
   <int value="-2013124655" label="EnableEphemeralFlashPermission:disabled"/>
   <int value="-2012990889" label="SpannableInlineAutocomplete:enabled"/>
@@ -40694,6 +40705,7 @@
   <int value="-1925106340" label="CameraSystemWebApp:disabled"/>
   <int value="-1921593903" label="ImeInputLogicHmm:disabled"/>
   <int value="-1920912991" label="PermissionChip:disabled"/>
+  <int value="-1919683750" label="EnableOopPrintDrivers:disabled"/>
   <int value="-1919199528"
       label="AlwaysShowServerCardsInSyncTransport:disabled"/>
   <int value="-1916060206" label="enable-display-zoom-setting"/>
@@ -41701,6 +41713,7 @@
   <int value="-950793721" label="TranslateUI2016Q2:disabled"/>
   <int value="-950384924" label="OmniboxDisableInstantExtendedLimit:enabled"/>
   <int value="-949178861" label="enable-new-avatar-menu"/>
+  <int value="-948930847" label="EnableOopPrintDrivers:enabled"/>
   <int value="-945806012" label="DownloadsUi:enabled"/>
   <int value="-943304570" label="PaintHolding:enabled"/>
   <int value="-938178614" label="enable-suggestions-with-substring-match"/>
@@ -41818,6 +41831,7 @@
   <int value="-820041355" label="enable-transition-compositing"/>
   <int value="-816984237" label="OfflinePagesAsyncDownload:enabled"/>
   <int value="-816895294" label="DiscoverApp:disabled"/>
+  <int value="-816404462" label="TabGroupsAutoCreate:disabled"/>
   <int value="-815213125" label="SplitSettings:enabled"/>
   <int value="-814097014" label="disable-session-crashed-bubble"/>
   <int value="-813753274" label="VrBrowsing:disabled"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 29e4aa1..7393c39 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -3664,6 +3664,28 @@
   </summary>
 </histogram>
 
+<histogram name="Android.FontLookup.FetchFontResult" enum="FetchFontResult"
+    expires_after="M89">
+  <owner>chouinard@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <summary>
+    Records the result of font fetch requests made to the GMS Core Android
+    downloadable font provider. The result may be success, or failure with a
+    reason. In the case of multiple failures, only the first one encountered is
+    reported. See implementation at AndroidFontLookupImpl.
+  </summary>
+</histogram>
+
+<histogram name="Android.FontLookup.MatchLocalFontByUniqueName.Time" units="ms"
+    expires_after="M89">
+  <owner>chouinard@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <summary>
+    Records the time taken to respond to a request from the renderer to fetch a
+    specific font file from the GMS Core Android downloadable font provider.
+  </summary>
+</histogram>
+
 <histogram name="Android.HistoryPage.OpenSelected" units="units"
     expires_after="M80">
   <obsolete>
@@ -183256,12 +183278,40 @@
 
 <histogram name="Tabs.TabSearch.WindowDisplayedDuration" units="ms"
     expires_after="M90">
+  <obsolete>
+    Removed as of 09/2020 as the way the metric is emitted has changed. Replaced
+    with Tabs.TabSearch.WindowDisplayedDuration2.
+  </obsolete>
   <owner>tluk@chromium.org</owner>
   <owner>robliao@chromium.org</owner>
   <summary>
     Tab Search is a feature that allows users to better search their browsers
     for their desired tabs. It can be opened and closed. This records the amount
-    of time between when a Tab Search bubble is opened and when it is closed.
+    of time between when a Tab Search bubble is opened and when it is closed. It
+    does so by recording the difference in time between when the Tab Search's
+    WebView is first set visible and when the WebView's destructor is called.
+
+    The Tab Search UI is a bubble anchored to an element within a browser window
+    and is closed if the user switches to a tab, presses the escape key or
+    performs an action to return focus to the hosting window. The Tab Search UI
+    bubble will also close if the hosting browser window is closed or crashes.
+
+    Users may leave the bubble open for long periods of time without directly
+    interacting with the UI which could result in a long tail of displayed
+    durations.
+  </summary>
+</histogram>
+
+<histogram name="Tabs.TabSearch.WindowDisplayedDuration2" units="ms"
+    expires_after="M90">
+  <owner>tluk@chromium.org</owner>
+  <owner>robliao@chromium.org</owner>
+  <summary>
+    Tab Search is a feature that allows users to better search their browsers
+    for their desired tabs. It can be opened and closed. This records the amount
+    of time between when a Tab Search bubble is opened and when it is closed. It
+    does so by recording the difference in time between when the Tab Search's
+    bubble is first shown and when the bubble's destructor is called.
 
     The Tab Search UI is a bubble anchored to an element within a browser window
     and is closed if the user switches to a tab, presses the escape key or
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index df52d62..c125f42 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -379,6 +379,7 @@
 crbug.com/1112337 [ android ] system_health.memory_mobile/browse:news:cricbuzz:2019 [ Skip ]
 crbug.com/1113921 [ android-go ] system_health.memory_mobile/load:tools:dropbox:2019 [ Skip ]
 crbug.com/1128019 [ android-pixel-2 ] system_health.memory_mobile/load:tools:dropbox:2019 [ Skip ]
+crbug.com/1128019 [ android-nexus-5x ] system_health.memory_mobile/load:tools:dropbox:2019 [ Skip ]
 
 # Benchmark: tab_switching.typical_25
 crbug.com/747026 [ mac ] tab_switching.typical_25/multitab:misc:typical24 [ Skip ]
diff --git a/tools/polymer/polymer.gni b/tools/polymer/polymer.gni
index ca64f28..61c7cdb 100644
--- a/tools/polymer/polymer.gni
+++ b/tools/polymer/polymer.gni
@@ -71,5 +71,9 @@
     if (defined(invoker.migrated_imports)) {
       args += [ "--migrated_imports" ] + invoker.migrated_imports
     }
+
+    if (defined(invoker.preserve_url_scheme) && invoker.preserve_url_scheme) {
+      args += [ "--preserve_url_scheme" ]
+    }
   }
 }
diff --git a/tools/polymer/polymer.py b/tools/polymer/polymer.py
index 75d78fd..2bc049f0 100644
--- a/tools/polymer/polymer.py
+++ b/tools/polymer/polymer.py
@@ -79,6 +79,11 @@
 
 _migrated_imports = []
 
+# Populated from command line arguments. Specifies whether "chrome://" URLs
+# should be preserved, or whether they should be converted to scheme-relative
+# URLs "//" (default behavior).
+_preserve_url_scheme = False
+
 # Use an OrderedDict, since the order these redirects are applied matters.
 _chrome_redirects = OrderedDict([
     ('chrome://resources/polymer/v1_0/', POLYMER_V1_DIR),
@@ -97,18 +102,23 @@
 # imports. |to_js_import()| is the only public method exposed by this class.
 # Internally an HTML import path is
 #
-# 1) normalized, meaning converted from a chrome or relative URL to to an
-#    absolute path starting at the repo's root
+# 1) normalized, meaning converted from a chrome or scheme-relative or relative
+#    URL to to an absolute path starting at the repo's root
 # 2) converted to an equivalent JS normalized path
-# 3) de-normalized, meaning converted back to a relative or chrome URL
+# 3) de-normalized, meaning converted back to a chrome or scheme-relative or
+#    relative URL
 # 4) converted to a JS import statement
 class Dependency:
   def __init__(self, src, dst):
     self.html_file = src
     self.html_path = dst
 
-    self.input_format = ('chrome' if self.html_path.startswith('chrome://')
-                         or self.html_path.startswith('//') else 'relative')
+    if self.html_path.startswith('chrome://'):
+      self.input_format = 'chrome'
+    elif self.html_path.startswith('//'):
+      self.input_format = 'scheme-relative'
+    else:
+      self.input_format = 'relative'
     self.output_format = self.input_format
 
     self.html_path_normalized = self._to_html_normalized()
@@ -116,7 +126,7 @@
     self.js_path = self._to_js()
 
   def _to_html_normalized(self):
-    if self.input_format == 'chrome':
+    if self.input_format == 'chrome' or self.input_format == 'scheme-relative':
       self.html_path_normalized = self.html_path
       for r in _chrome_redirects:
         if self.html_path.startswith(r):
@@ -136,7 +146,8 @@
           .replace(r'.html', '.js'))
 
     if self.html_path_normalized == 'ui/webui/resources/html/polymer.html':
-      self.output_format = 'chrome'
+      if self.output_format == 'relative':
+        self.output_format = 'chrome'
       return POLYMER_V3_DIR + 'polymer/polymer_bundled.min.js'
 
     if re.match(r'ui/webui/resources/html/', self.html_path_normalized):
@@ -151,14 +162,19 @@
   def _to_js(self):
     js_path = self.js_path_normalized
 
-    if self.output_format == 'chrome':
+    if self.output_format == 'chrome' or self.output_format == 'scheme-relative':
       for r in _chrome_reverse_redirects:
         if self.js_path_normalized.startswith(r):
           js_path = self.js_path_normalized.replace(
               r, _chrome_reverse_redirects[r])
           break
+
+      # Restore the chrome:// scheme if |preserve_url_scheme| is enabled.
+      if _preserve_url_scheme and self.output_format == 'chrome':
+        js_path = "chrome:" + js_path
       return js_path
 
+    assert self.output_format == 'relative'
     input_dir = os.path.relpath(os.path.dirname(self.html_file), _ROOT)
     relpath = os.path.relpath(
         self.js_path_normalized, input_dir).replace("\\", "/")
@@ -512,6 +528,7 @@
   parser.add_argument('--ignore_imports', required=False, nargs="*")
   parser.add_argument('--auto_imports', required=False, nargs="*")
   parser.add_argument('--migrated_imports', required=False, nargs="*")
+  parser.add_argument('--preserve_url_scheme', action="store_true")
   parser.add_argument(
       '--html_type', choices=['dom-module', 'style-module', 'custom-style',
       'iron-iconset', 'v3-ready'],
@@ -543,6 +560,10 @@
     global _migrated_imports
     _migrated_imports = args.migrated_imports
 
+  # Extract |preserve_url_scheme| from arguments.
+  global _preserve_url_scheme
+  _preserve_url_scheme = args.preserve_url_scheme
+
   in_folder = os.path.normpath(os.path.join(_CWD, args.in_folder))
   out_folder = os.path.normpath(os.path.join(_CWD, args.out_folder))
 
diff --git a/tools/polymer/polymer_test.py b/tools/polymer/polymer_test.py
index b5d96a5..33b1c64 100755
--- a/tools/polymer/polymer_test.py
+++ b/tools/polymer/polymer_test.py
@@ -165,54 +165,79 @@
         # Case where relative path to polymer.html is used.
         [
             '../../html/polymer.html',
-            'import {Polymer, html} from \'//resources/polymer/v3_0/polymer/polymer_bundled.min.js\';'
+            'import {Polymer, html} from \'//resources/polymer/v3_0/polymer/polymer_bundled.min.js\';',
+            'import {Polymer, html} from \'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js\';',
         ],
         # Case where relative path to file in the same folder is used.
-        ['foo.html', 'import \'./foo.m.js\';'],
+        [
+            'foo.html',
+            'import \'./foo.m.js\';',
+            'import \'./foo.m.js\';',
+        ],
         # Case where relative path to file in the same subtree is used.
         [
             'path/to/subfolder/foo.html',
-            'import \'./path/to/subfolder/foo.m.js\';'
+            'import \'./path/to/subfolder/foo.m.js\';',
+            'import \'./path/to/subfolder/foo.m.js\';',
         ],
         # Case where relative path to file in ui/webui/resources/html/ is used.
-        ['../../html/foo.html', 'import {Foo} from \'../../js/foo.m.js\';'],
+        [
+            '../../html/foo.html',
+            'import {Foo} from \'../../js/foo.m.js\';',
+            'import {Foo} from \'../../js/foo.m.js\';',
+        ],
 
         # chrome:// paths cases.
         # Case where absolute path to a Polymer UI element is used.
         [
             'chrome://resources/polymer/v1_0/path/to/folder/foo.html',
-            'import \'//resources/polymer/v3_0/path/to/folder/foo.js\';'
+            'import \'//resources/polymer/v3_0/path/to/folder/foo.js\';',
+            'import \'chrome://resources/polymer/v3_0/path/to/folder/foo.js\';',
         ],
         # Case where chrome:// path to polymer.html is used.
         [
             'chrome://resources/html/polymer.html',
-            'import {Polymer, html} from \'//resources/polymer/v3_0/polymer/polymer_bundled.min.js\';'
+            'import {Polymer, html} from \'//resources/polymer/v3_0/polymer/polymer_bundled.min.js\';',
+            'import {Polymer, html} from \'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js\';',
         ],
         # Case where chrome://resources/html/ path to something other than
         # polymer.html is used.
         [
             'chrome://resources/html/bar.html',
-            'import \'//resources/js/bar.m.js\';'
+            'import \'//resources/js/bar.m.js\';',
+            'import \'chrome://resources/js/bar.m.js\';',
         ],
 
         # Scheme-relative paths cases.
         # Case where absolute path to a Polymer UI element is used.
         [
             '//resources/polymer/v1_0/path/to/folder/foo.html',
-            'import \'//resources/polymer/v3_0/path/to/folder/foo.js\';'
+            'import \'//resources/polymer/v3_0/path/to/folder/foo.js\';',
+            'import \'//resources/polymer/v3_0/path/to/folder/foo.js\';',
         ],
         # Case where path to polymer.html is used.
         [
             '//resources/html/polymer.html',
-            'import {Polymer, html} from \'//resources/polymer/v3_0/polymer/polymer_bundled.min.js\';'
+            'import {Polymer, html} from \'//resources/polymer/v3_0/polymer/polymer_bundled.min.js\';',
+            'import {Polymer, html} from \'//resources/polymer/v3_0/polymer/polymer_bundled.min.js\';',
         ],
         # Case where //resources/html/ path to something other than
         # polymer.html is used.
-        ['//resources/html/bar.html', 'import \'//resources/js/bar.m.js\';'],
+        [
+            '//resources/html/bar.html',
+            'import \'//resources/js/bar.m.js\';',
+            'import \'//resources/js/bar.m.js\';',
+        ],
     ]
 
-    for [html, js_expected] in cases:
-      assert_html_to_js(html, js_expected)
+    for [html, js_expected1, js_expected2] in cases:
+      # Test case where |preserve_url_scheme| is False
+      polymer._preserve_url_scheme = False
+      assert_html_to_js(html, js_expected1)
+
+      # Test case where |preserve_url_scheme| is True
+      polymer._preserve_url_scheme = True
+      assert_html_to_js(html, js_expected2)
 
 
 if __name__ == '__main__':
diff --git a/ui/base/clipboard/clipboard_android.cc b/ui/base/clipboard/clipboard_android.cc
index dfc27ac..aea13c4 100644
--- a/ui/base/clipboard/clipboard_android.cc
+++ b/ui/base/clipboard/clipboard_android.cc
@@ -27,6 +27,7 @@
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/clipboard/clipboard_constants.h"
 #include "ui/base/clipboard/clipboard_data_endpoint.h"
+#include "ui/base/clipboard/clipboard_format_type.h"
 #include "ui/base/clipboard/clipboard_metrics.h"
 #include "ui/base/ui_base_jni_headers/Clipboard_jni.h"
 #include "ui/gfx/android/java_bitmap.h"
@@ -88,16 +89,16 @@
   ClipboardMap();
   void SetModifiedCallback(ClipboardAndroid::ModifiedCallback cb);
   void SetJavaSideNativePtr(Clipboard* clipboard);
-  std::string Get(const std::string& format);
+  std::string Get(const ClipboardFormatType& format);
   void GetImage(ReadImageCallback callback);
   uint64_t GetSequenceNumber() const;
   base::Time GetLastModifiedTime() const;
   void ClearLastModifiedTime();
-  bool HasFormat(const std::string& format);
-  std::vector<std::string> GetFormats();
+  bool HasFormat(const ClipboardFormatType& format);
+  std::vector<ClipboardFormatType> GetFormats();
   void OnPrimaryClipboardChanged();
   void OnPrimaryClipTimestampInvalidated(int64_t timestamp_ms);
-  void Set(const std::string& format, const std::string& data);
+  void Set(const ClipboardFormatType& format, const std::string& data);
   void CommitToAndroidClipboard();
   void Clear();
 
@@ -117,8 +118,7 @@
   // Updates |map_| and |map_state_| if necessary by fetching data from Java.
   void UpdateFromAndroidClipboard();
 
-  // TODO(huangdarwin): Refactor this to hold base::string16.
-  std::map<std::string, std::string> map_ GUARDED_BY(lock_);
+  std::map<ClipboardFormatType, std::string> map_ GUARDED_BY(lock_);
   MapState map_state_;
 
   // This lock is for read/write |map_|.
@@ -149,10 +149,10 @@
                               reinterpret_cast<intptr_t>(clipboard));
 }
 
-std::string ClipboardMap::Get(const std::string& format) {
+std::string ClipboardMap::Get(const ClipboardFormatType& format) {
   base::AutoLock lock(lock_);
   UpdateFromAndroidClipboard();
-  std::map<std::string, std::string>::const_iterator it = map_.find(format);
+  auto it = map_.find(format);
   return it == map_.end() ? std::string() : it->second;
 }
 
@@ -174,16 +174,16 @@
   UpdateLastModifiedTime(base::Time());
 }
 
-bool ClipboardMap::HasFormat(const std::string& format) {
+bool ClipboardMap::HasFormat(const ClipboardFormatType& format) {
   base::AutoLock lock(lock_);
   UpdateFromAndroidClipboard();
   return base::Contains(map_, format);
 }
 
-std::vector<std::string> ClipboardMap::GetFormats() {
+std::vector<ClipboardFormatType> ClipboardMap::GetFormats() {
   base::AutoLock lock(lock_);
   UpdateFromAndroidClipboard();
-  std::vector<std::string> formats;
+  std::vector<ClipboardFormatType> formats;
   formats.reserve(map_.size());
   for (const auto& it : map_)
     formats.push_back(it.first);
@@ -205,7 +205,8 @@
   }
 }
 
-void ClipboardMap::Set(const std::string& format, const std::string& data) {
+void ClipboardMap::Set(const ClipboardFormatType& format,
+                       const std::string& data) {
   base::AutoLock lock(lock_);
   map_[format] = data;
   map_state_ = MapState::kPreparingCommit;
@@ -214,30 +215,27 @@
 void ClipboardMap::CommitToAndroidClipboard() {
   JNIEnv* env = AttachCurrentThread();
   base::AutoLock lock(lock_);
-  if (base::Contains(map_, ClipboardFormatType::GetHtmlType().GetName())) {
+  if (base::Contains(map_, ClipboardFormatType::GetHtmlType())) {
     // Android's API for storing HTML content on the clipboard requires a plain-
     // text representation to be available as well.
-    if (!base::Contains(map_,
-                        ClipboardFormatType::GetPlainTextType().GetName()))
+    if (!base::Contains(map_, ClipboardFormatType::GetPlainTextType()))
       return;
 
-    ScopedJavaLocalRef<jstring> html = ConvertUTF8ToJavaString(
-        env, map_[ClipboardFormatType::GetHtmlType().GetName()]);
+    ScopedJavaLocalRef<jstring> html =
+        ConvertUTF8ToJavaString(env, map_[ClipboardFormatType::GetHtmlType()]);
     ScopedJavaLocalRef<jstring> text = ConvertUTF8ToJavaString(
-        env, map_[ClipboardFormatType::GetPlainTextType().GetName()]);
+        env, map_[ClipboardFormatType::GetPlainTextType()]);
 
     DCHECK(html.obj() && text.obj());
     Java_Clipboard_setHTMLText(env, clipboard_manager_, html, text);
-  } else if (base::Contains(
-                 map_, ClipboardFormatType::GetPlainTextType().GetName())) {
+  } else if (base::Contains(map_, ClipboardFormatType::GetPlainTextType())) {
     ScopedJavaLocalRef<jstring> str = ConvertUTF8ToJavaString(
-        env, map_[ClipboardFormatType::GetPlainTextType().GetName()]);
+        env, map_[ClipboardFormatType::GetPlainTextType()]);
     DCHECK(str.obj());
     Java_Clipboard_setText(env, clipboard_manager_, str);
-  } else if (base::Contains(map_,
-                            ClipboardFormatType::GetBitmapType().GetName())) {
-    ScopedJavaLocalRef<jbyteArray> image_data = ToJavaByteArray(
-        env, map_[ClipboardFormatType::GetBitmapType().GetName()]);
+  } else if (base::Contains(map_, ClipboardFormatType::GetBitmapType())) {
+    ScopedJavaLocalRef<jbyteArray> image_data =
+        ToJavaByteArray(env, map_[ClipboardFormatType::GetBitmapType()]);
     ScopedJavaLocalRef<jstring> image_extension =
         ConvertUTF8ToJavaString(env, kPngExtension);
     DCHECK(image_data.obj());
@@ -267,21 +265,22 @@
   last_modified_time_ = time;
 }
 
-// Add a key:jstr pair to map, if jstr is null or is empty, then remove that
+// Add a format:jstr pair to map, if jstr is null or is empty, then remove that
 // entry.
 void JNI_Clipboard_AddMapEntry(JNIEnv* env,
-                               std::map<std::string, std::string>* map,
-                               const char* key,
+                               std::map<ClipboardFormatType, std::string>* map,
+                               const ClipboardFormatType& format,
                                const ScopedJavaLocalRef<jstring>& jstr) {
   if (jstr.is_null()) {
-    map->erase(key);
+    map->erase(format);
     return;
   }
+
   std::string str = ConvertJavaStringToUTF8(env, jstr.obj());
   if (!str.empty()) {
-    (*map)[key] = str;
+    (*map)[format] = str;
   } else {
-    map->erase(key);
+    map->erase(format);
   }
 }
 
@@ -308,12 +307,12 @@
   ScopedJavaLocalRef<jstring> jimageuri =
       Java_Clipboard_getImageUriString(env, clipboard_manager_);
 
+  JNI_Clipboard_AddMapEntry(env, &map_, ClipboardFormatType::GetPlainTextType(),
+                            jtext);
+  JNI_Clipboard_AddMapEntry(env, &map_, ClipboardFormatType::GetHtmlType(),
+                            jhtml);
   JNI_Clipboard_AddMapEntry(
-      env, &map_, ClipboardFormatType::GetPlainTextType().GetName().c_str(),
-      jtext);
-  JNI_Clipboard_AddMapEntry(
-      env, &map_, ClipboardFormatType::GetHtmlType().GetName().c_str(), jhtml);
-  JNI_Clipboard_AddMapEntry(env, &map_, kMimeTypeImageURI, jimageuri);
+      env, &map_, ClipboardFormatType::GetType(kMimeTypeImageURI), jimageuri);
 
   map_state_ = MapState::kUpToDate;
 }
@@ -386,9 +385,10 @@
   DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste);
 
   if (format == ClipboardFormatType::GetBitmapType()) {
-    return g_map.Get().HasFormat(kMimeTypeImageURI);
+    return g_map.Get().HasFormat(
+        ClipboardFormatType::GetType(kMimeTypeImageURI));
   }
-  return g_map.Get().HasFormat(format.GetName());
+  return g_map.Get().HasFormat(format);
 }
 
 void ClipboardAndroid::Clear(ClipboardBuffer buffer) {
@@ -432,12 +432,12 @@
     ClipboardBuffer buffer,
     const ClipboardDataEndpoint* data_dst) const {
   DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste);
-  std::vector<std::string> formats = g_map.Get().GetFormats();
+  std::vector<ClipboardFormatType> formats = g_map.Get().GetFormats();
 
   std::vector<base::string16> types;
   types.reserve(formats.size());
-  for (const std::string& format : formats)
-    types.push_back(base::UTF8ToUTF16(format));
+  for (const ClipboardFormatType& format : formats)
+    types.push_back(base::UTF8ToUTF16(format.GetName()));
 
   return types;
 }
@@ -462,7 +462,7 @@
   DCHECK(CalledOnValidThread());
   DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste);
   RecordRead(ClipboardFormatMetric::kText);
-  *result = g_map.Get().Get(ClipboardFormatType::GetPlainTextType().GetName());
+  *result = g_map.Get().Get(ClipboardFormatType::GetPlainTextType());
 }
 
 // Note: |src_url| isn't really used. It is only implemented in Windows.
@@ -480,8 +480,7 @@
   if (src_url)
     src_url->clear();
 
-  std::string input =
-      g_map.Get().Get(ClipboardFormatType::GetHtmlType().GetName());
+  std::string input = g_map.Get().Get(ClipboardFormatType::GetHtmlType());
   *markup = base::UTF8ToUTF16(input);
 
   *fragment_start = 0;
@@ -495,8 +494,7 @@
                                base::string16* result) const {
   DCHECK(CalledOnValidThread());
   DCHECK_EQ(buffer, ClipboardBuffer::kCopyPaste);
-  std::string utf8 =
-      g_map.Get().Get(ClipboardFormatType::GetSvgType().GetName());
+  std::string utf8 = g_map.Get().Get(ClipboardFormatType::GetSvgType());
   *result = base::UTF8ToUTF16(utf8);
 }
 
@@ -546,7 +544,7 @@
                                 std::string* result) const {
   DCHECK(CalledOnValidThread());
   RecordRead(ClipboardFormatMetric::kData);
-  *result = g_map.Get().Get(format.GetName());
+  *result = g_map.Get().Get(format);
 }
 
 base::Time ClipboardAndroid::GetLastModifiedTime() const {
@@ -592,7 +590,7 @@
 }
 
 void ClipboardAndroid::WriteText(const char* text_data, size_t text_len) {
-  g_map.Get().Set(ClipboardFormatType::GetPlainTextType().GetName(),
+  g_map.Get().Set(ClipboardFormatType::GetPlainTextType(),
                   std::string(text_data, text_len));
 }
 
@@ -600,12 +598,12 @@
                                  size_t markup_len,
                                  const char* url_data,
                                  size_t url_len) {
-  g_map.Get().Set(ClipboardFormatType::GetHtmlType().GetName(),
+  g_map.Get().Set(ClipboardFormatType::GetHtmlType(),
                   std::string(markup_data, markup_len));
 }
 
 void ClipboardAndroid::WriteSvg(const char* markup_data, size_t markup_len) {
-  g_map.Get().Set(ClipboardFormatType::GetSvgType().GetName(),
+  g_map.Get().Set(ClipboardFormatType::GetSvgType(),
                   std::string(markup_data, markup_len));
 }
 
@@ -619,14 +617,14 @@
                                      size_t title_len,
                                      const char* url_data,
                                      size_t url_len) {
-  g_map.Get().Set(ClipboardFormatType::GetUrlType().GetName(),
+  g_map.Get().Set(ClipboardFormatType::GetUrlType(),
                   std::string(url_data, url_len));
 }
 
 // Write an extra flavor that signifies WebKit was the last to modify the
 // pasteboard. This flavor has no data.
 void ClipboardAndroid::WriteWebSmartPaste() {
-  g_map.Get().Set(ClipboardFormatType::GetWebKitSmartPasteType().GetName(),
+  g_map.Get().Set(ClipboardFormatType::GetWebKitSmartPasteType(),
                   std::string());
 }
 
@@ -637,13 +635,13 @@
       gfx::Image::CreateFrom1xBitmap(sk_bitmap).As1xPNGBytes();
   std::string packed(image_memory->front_as<char>(), image_memory->size());
 
-  g_map.Get().Set(ClipboardFormatType::GetBitmapType().GetName(), packed);
+  g_map.Get().Set(ClipboardFormatType::GetBitmapType(), packed);
 }
 
 void ClipboardAndroid::WriteData(const ClipboardFormatType& format,
                                  const char* data_data,
                                  size_t data_len) {
-  g_map.Get().Set(format.GetName(), std::string(data_data, data_len));
+  g_map.Get().Set(format, std::string(data_data, data_len));
 }
 
 }  // namespace ui
diff --git a/ui/base/ime/chromeos/component_extension_ime_manager.cc b/ui/base/ime/chromeos/component_extension_ime_manager.cc
index 9c5c367..796d713 100644
--- a/ui/base/ime/chromeos/component_extension_ime_manager.cc
+++ b/ui/base/ime/chromeos/component_extension_ime_manager.cc
@@ -75,13 +75,13 @@
   delegate_ = std::move(delegate);
   std::vector<ComponentExtensionIME> ext_list = delegate_->ListIME();
   for (const auto& ext : ext_list) {
-    bool extension_exists = IsWhitelistedExtension(ext.id);
+    bool extension_exists = IsAllowlistedExtension(ext.id);
     if (!extension_exists)
       component_extension_imes_[ext.id] = ext;
     for (const auto& ime : ext.engines) {
       const std::string input_method_id =
           extension_ime_util::GetComponentInputMethodID(ext.id, ime.engine_id);
-      if (extension_exists && !IsWhitelisted(input_method_id))
+      if (extension_exists && !IsAllowlisted(input_method_id))
         component_extension_imes_[ext.id].engines.push_back(ime);
       input_method_id_set_.insert(input_method_id);
     }
@@ -109,13 +109,13 @@
   return true;
 }
 
-bool ComponentExtensionIMEManager::IsWhitelisted(
+bool ComponentExtensionIMEManager::IsAllowlisted(
     const std::string& input_method_id) {
   return input_method_id_set_.find(input_method_id) !=
          input_method_id_set_.end();
 }
 
-bool ComponentExtensionIMEManager::IsWhitelistedExtension(
+bool ComponentExtensionIMEManager::IsAllowlistedExtension(
     const std::string& extension_id) {
   return component_extension_imes_.find(extension_id) !=
          component_extension_imes_.end();
@@ -134,18 +134,13 @@
           extension_ime_util::GetComponentInputMethodID(
               ext.id, ime.engine_id);
       const std::vector<std::string>& layouts = ime.layouts;
-      result.push_back(
-          input_method::InputMethodDescriptor(
-              input_method_id,
-              ime.display_name,
-              ime.indicator,
-              layouts,
-              ime.language_codes,
-              // Enables extension based xkb keyboards on login screen.
-              extension_ime_util::IsKeyboardLayoutExtension(
-                  input_method_id) && IsInLoginLayoutWhitelist(layouts),
-              ime.options_page_url,
-              ime.input_view_url));
+      result.push_back(input_method::InputMethodDescriptor(
+          input_method_id, ime.display_name, ime.indicator, layouts,
+          ime.language_codes,
+          // Enables extension based xkb keyboards on login screen.
+          extension_ime_util::IsKeyboardLayoutExtension(input_method_id) &&
+              IsInLoginLayoutAllowlist(layouts),
+          ime.options_page_url, ime.input_view_url));
     }
   }
   std::stable_sort(result.begin(), result.end(), InputMethodCompare);
@@ -167,7 +162,7 @@
 bool ComponentExtensionIMEManager::FindEngineEntry(
     const std::string& input_method_id,
     ComponentExtensionIME* out_extension) {
-  if (!IsWhitelisted(input_method_id))
+  if (!IsAllowlisted(input_method_id))
     return false;
 
   std::string extension_id =
@@ -181,7 +176,7 @@
   return true;
 }
 
-bool ComponentExtensionIMEManager::IsInLoginLayoutWhitelist(
+bool ComponentExtensionIMEManager::IsInLoginLayoutAllowlist(
     const std::vector<std::string>& layouts) {
   for (const auto& layout : layouts) {
     if (login_layout_set_.find(layout) != login_layout_set_.end())
diff --git a/ui/base/ime/chromeos/component_extension_ime_manager.h b/ui/base/ime/chromeos/component_extension_ime_manager.h
index b6bd2d4..6a50823 100644
--- a/ui/base/ime/chromeos/component_extension_ime_manager.h
+++ b/ui/base/ime/chromeos/component_extension_ime_manager.h
@@ -94,12 +94,12 @@
   bool UnloadComponentExtensionIME(Profile* profile,
                                    const std::string& input_method_id);
 
-  // Returns true if |input_method_id| is whitelisted component extension input
+  // Returns true if |input_method_id| is allowlisted component extension input
   // method.
-  bool IsWhitelisted(const std::string& input_method_id);
+  bool IsAllowlisted(const std::string& input_method_id);
 
-  // Returns true if |extension_id| is whitelisted component extension.
-  bool IsWhitelistedExtension(const std::string& extension_id);
+  // Returns true if |extension_id| is allowlisted component extension.
+  bool IsAllowlistedExtension(const std::string& extension_id);
 
   // Returns all IME as InputMethodDescriptors.
   input_method::InputMethodDescriptors GetAllIMEAsInputMethodDescriptor();
@@ -115,7 +115,7 @@
   bool FindEngineEntry(const std::string& input_method_id,
                        ComponentExtensionIME* out_extension);
 
-  bool IsInLoginLayoutWhitelist(const std::vector<std::string>& layouts);
+  bool IsInLoginLayoutAllowlist(const std::vector<std::string>& layouts);
 
   std::unique_ptr<ComponentExtensionIMEManagerDelegate> delegate_;
 
diff --git a/ui/base/ime/chromeos/component_extension_ime_manager_unittest.cc b/ui/base/ime/chromeos/component_extension_ime_manager_unittest.cc
index 0be95ca9..1f07cec 100644
--- a/ui/base/ime/chromeos/component_extension_ime_manager_unittest.cc
+++ b/ui/base/ime/chromeos/component_extension_ime_manager_unittest.cc
@@ -161,28 +161,25 @@
   EXPECT_EQ(9, mock_delegate_->unload_call_count());
 }
 
-TEST_F(ComponentExtensionIMEManagerTest, IsWhitelistedTest) {
-  EXPECT_TRUE(component_ext_mgr_->IsWhitelisted(
+TEST_F(ComponentExtensionIMEManagerTest, IsAllowlistedTest) {
+  EXPECT_TRUE(component_ext_mgr_->IsAllowlisted(
       extension_ime_util::GetComponentInputMethodID(
-          ime_list_[0].id,
-          ime_list_[0].engines[0].engine_id)));
-  EXPECT_FALSE(component_ext_mgr_->IsWhitelisted(
-      extension_ime_util::GetInputMethodID(
-          ime_list_[0].id,
-          ime_list_[0].engines[0].engine_id)));
-  EXPECT_FALSE(component_ext_mgr_->IsWhitelisted("mozc"));
-  EXPECT_FALSE(component_ext_mgr_->IsWhitelisted(
+          ime_list_[0].id, ime_list_[0].engines[0].engine_id)));
+  EXPECT_FALSE(
+      component_ext_mgr_->IsAllowlisted(extension_ime_util::GetInputMethodID(
+          ime_list_[0].id, ime_list_[0].engines[0].engine_id)));
+  EXPECT_FALSE(component_ext_mgr_->IsAllowlisted("mozc"));
+  EXPECT_FALSE(component_ext_mgr_->IsAllowlisted(
       extension_ime_util::GetInputMethodID("AAAA", "012345")));
-  EXPECT_FALSE(component_ext_mgr_->IsWhitelisted(
-      extension_ime_util::GetComponentInputMethodID(
-          "AAAA", "012345")));
+  EXPECT_FALSE(component_ext_mgr_->IsAllowlisted(
+      extension_ime_util::GetComponentInputMethodID("AAAA", "012345")));
 }
 
-TEST_F(ComponentExtensionIMEManagerTest, IsWhitelistedExtensionTest) {
-  EXPECT_TRUE(component_ext_mgr_->IsWhitelistedExtension(ime_list_[0].id));
-  EXPECT_TRUE(component_ext_mgr_->IsWhitelistedExtension(ime_list_[1].id));
-  EXPECT_FALSE(component_ext_mgr_->IsWhitelistedExtension("dummy"));
-  EXPECT_FALSE(component_ext_mgr_->IsWhitelistedExtension(""));
+TEST_F(ComponentExtensionIMEManagerTest, IsAllowlistedExtensionTest) {
+  EXPECT_TRUE(component_ext_mgr_->IsAllowlistedExtension(ime_list_[0].id));
+  EXPECT_TRUE(component_ext_mgr_->IsAllowlistedExtension(ime_list_[1].id));
+  EXPECT_FALSE(component_ext_mgr_->IsAllowlistedExtension("dummy"));
+  EXPECT_FALSE(component_ext_mgr_->IsAllowlistedExtension(""));
 }
 
 TEST_F(ComponentExtensionIMEManagerTest, GetAllIMEAsInputMethodDescriptor) {
diff --git a/ui/base/x/x11_cursor_loader.cc b/ui/base/x/x11_cursor_loader.cc
index 8b35ae6..e0bdb89a 100644
--- a/ui/base/x/x11_cursor_loader.cc
+++ b/ui/base/x/x11_cursor_loader.cc
@@ -4,8 +4,6 @@
 
 #include "ui/base/x/x11_cursor_loader.h"
 
-#include <dlfcn.h>
-
 #include <limits>
 #include <string>
 
@@ -15,7 +13,6 @@
 #include "base/files/file_util.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/no_destructor.h"
 #include "base/sequence_checker.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
@@ -31,10 +28,6 @@
 #include "ui/gfx/x/connection.h"
 #include "ui/gfx/x/xproto.h"
 
-extern "C" {
-const char* XcursorLibraryPath(void);
-}
-
 namespace ui {
 
 namespace {
@@ -127,41 +120,14 @@
   return value;
 }
 
-std::string CursorPathFromLibXcursor() {
-  struct DlCloser {
-    void operator()(void* ptr) const { dlclose(ptr); }
-  };
-
-  std::unique_ptr<void, DlCloser> lib(dlopen("libXcursor.so.1", RTLD_LAZY));
-  if (!lib)
-    return "";
-
-  if (auto* sym = reinterpret_cast<decltype(&XcursorLibraryPath)>(
-          dlsym(lib.get(), "XcursorLibraryPath"))) {
-    if (const char* path = sym())
-      return path;
-  }
-  return "";
-}
-
-std::string CursorPathImpl() {
+std::string CursorPath() {
   constexpr const char kDefaultPath[] =
       "~/.local/share/icons:~/.icons:/usr/share/icons:/usr/share/pixmaps:"
       "/usr/X11R6/lib/X11/icons";
-
-  auto libxcursor_path = CursorPathFromLibXcursor();
-  if (!libxcursor_path.empty())
-    return libxcursor_path;
-
   std::string path = GetEnv("XCURSOR_PATH");
   return path.empty() ? kDefaultPath : path;
 }
 
-const std::string& CursorPath() {
-  static base::NoDestructor<std::string> path(CursorPathImpl());
-  return *path;
-}
-
 x11::Render::PictFormat GetRenderARGBFormat(
     const x11::Render::QueryPictFormatsReply& formats) {
   for (const auto& format : formats.formats) {
diff --git a/ui/gfx/linux/BUILD.gn b/ui/gfx/linux/BUILD.gn
index c54b85f..3574e02b 100644
--- a/ui/gfx/linux/BUILD.gn
+++ b/ui/gfx/linux/BUILD.gn
@@ -5,7 +5,7 @@
 import("//build/config/ui.gni")
 import("//ui/ozone/ozone.gni")
 
-assert(use_x11 || ozone_platform_gbm || ozone_platform_wayland)
+assert(use_x11 || ozone_platform_drm || ozone_platform_wayland)
 
 source_set("drm") {
   sources = [
diff --git a/ui/ozone/BUILD.gn b/ui/ozone/BUILD.gn
index 70959e8..be8545a 100644
--- a/ui/ozone/BUILD.gn
+++ b/ui/ozone/BUILD.gn
@@ -31,8 +31,8 @@
   ozone_platform_deps += [ "platform/headless" ]
 }
 
-if (ozone_platform_gbm) {
-  ozone_platforms += [ "gbm" ]
+if (ozone_platform_drm) {
+  ozone_platforms += [ "drm" ]
   ozone_platform_deps += [ "platform/drm:gbm" ]
   ozone_platform_test_deps += [ "platform/drm:gbm_unittests" ]
 }
diff --git a/ui/ozone/ozone.gni b/ui/ozone/ozone.gni
index 951a5b8..5943791 100644
--- a/ui/ozone/ozone.gni
+++ b/ui/ozone/ozone.gni
@@ -14,6 +14,10 @@
 
   # Select platforms automatically. Turn this off for manual control.
   ozone_auto_platforms = use_ozone
+
+  # TODO(petermcneeley): Backwards compatiblity support for VM images.
+  # Remove when deprecated. (https://crbug.com/1122009)
+  ozone_platform_gbm = -1
 }
 
 declare_args() {
@@ -24,8 +28,8 @@
   # Compile the 'cast' platform.
   ozone_platform_cast = false
 
-  # Compile the 'gbm' platform.
-  ozone_platform_gbm = false
+  # Compile the 'drm' platform.
+  ozone_platform_drm = false
 
   # Compile the 'headless' platform.
   ozone_platform_headless = false
@@ -64,7 +68,7 @@
       }
     } else if (is_chromeos) {
       ozone_platform = "x11"
-      ozone_platform_gbm = true
+      ozone_platform_drm = true
       ozone_platform_x11 = true
 
       # Enable the Ozone Wayland platform for ChromiumOS codesearch-gen bots
@@ -84,6 +88,12 @@
       ozone_platform_scenic = true
     }
   }
+
+  # TODO(petermcneeley): Backwards compatiblity support for VM images.
+  # Remove when deprecated. (https://crbug.com/1122009)
+  if (ozone_platform_gbm != -1) {
+    ozone_platform_drm = ozone_platform_gbm
+  }
 }
 
 import(ozone_extra_path)
@@ -94,9 +104,20 @@
 ozone_external_platform_visibility = [ "$_ozone_extra_directory/*" ]
 
 if (is_a_target_toolchain) {
-  assert(use_ozone || !(ozone_platform_cast || ozone_platform_gbm ||
+  assert(use_ozone || !(ozone_platform_cast || ozone_platform_drm ||
                             ozone_platform_headless || ozone_platform_x11 ||
                             ozone_platform_wayland || ozone_platform_windows ||
                             ozone_platform_scenic),
          "Must set use_ozone to select ozone platforms")
 }
+
+# TODO(petermcneeley): Backwards compatiblity support for VM images.
+# Remove when deprecated. (https://crbug.com/1122009)
+
+assert(ozone_platform_gbm == -1 || ozone_platform_drm == ozone_platform_gbm)
+
+ozone_platform_gbm = ozone_platform_drm
+
+if (ozone_platform == "gbm") {
+  ozone_platform = "drm"
+}
diff --git a/ui/ozone/platform/drm/BUILD.gn b/ui/ozone/platform/drm/BUILD.gn
index 01ed606..d69ec46 100644
--- a/ui/ozone/platform/drm/BUILD.gn
+++ b/ui/ozone/platform/drm/BUILD.gn
@@ -17,8 +17,8 @@
 
 source_set("gbm") {
   sources = [
-    "client_native_pixmap_factory_gbm.cc",
-    "client_native_pixmap_factory_gbm.h",
+    "client_native_pixmap_factory_drm.cc",
+    "client_native_pixmap_factory_drm.h",
     "common/display_types.h",
     "common/drm_util.cc",
     "common/drm_util.h",
@@ -112,8 +112,8 @@
     "host/host_cursor_proxy.h",
     "host/host_drm_device.cc",
     "host/host_drm_device.h",
-    "ozone_platform_gbm.cc",
-    "ozone_platform_gbm.h",
+    "ozone_platform_drm.cc",
+    "ozone_platform_drm.h",
   ]
 
   deps = [
diff --git a/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.cc b/ui/ozone/platform/drm/client_native_pixmap_factory_drm.cc
similarity index 75%
rename from ui/ozone/platform/drm/client_native_pixmap_factory_gbm.cc
rename to ui/ozone/platform/drm/client_native_pixmap_factory_drm.cc
index 8e363e6..67b821625 100644
--- a/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.cc
+++ b/ui/ozone/platform/drm/client_native_pixmap_factory_drm.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/drm/client_native_pixmap_factory_gbm.h"
+#include "ui/ozone/platform/drm/client_native_pixmap_factory_drm.h"
 
 #include <utility>
 
@@ -12,7 +12,7 @@
 
 namespace ui {
 
-gfx::ClientNativePixmapFactory* CreateClientNativePixmapFactoryGbm() {
+gfx::ClientNativePixmapFactory* CreateClientNativePixmapFactoryDrm() {
   return gfx::CreateClientNativePixmapFactoryDmabuf();
 }
 
diff --git a/ui/ozone/platform/drm/client_native_pixmap_factory_drm.h b/ui/ozone/platform/drm/client_native_pixmap_factory_drm.h
new file mode 100644
index 0000000..e0b4f9e
--- /dev/null
+++ b/ui/ozone/platform/drm/client_native_pixmap_factory_drm.h
@@ -0,0 +1,19 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_DRM_CLIENT_NATIVE_PIXMAP_FACTORY_DRM_H_
+#define UI_OZONE_PLATFORM_DRM_CLIENT_NATIVE_PIXMAP_FACTORY_DRM_H_
+
+namespace gfx {
+class ClientNativePixmapFactory;
+}
+
+namespace ui {
+
+// Constructor hook for use in constructor_list.cc
+gfx::ClientNativePixmapFactory* CreateClientNativePixmapFactoryDrm();
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_DRM_CLIENT_NATIVE_PIXMAP_FACTORY_DRM_H_
diff --git a/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.h b/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.h
deleted file mode 100644
index 05506d6..0000000
--- a/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_OZONE_PLATFORM_DRM_CLIENT_NATIVE_PIXMAP_FACTORY_GBM_H_
-#define UI_OZONE_PLATFORM_DRM_CLIENT_NATIVE_PIXMAP_FACTORY_GBM_H_
-
-namespace gfx {
-class ClientNativePixmapFactory;
-}
-
-namespace ui {
-
-// Constructor hook for use in constructor_list.cc
-gfx::ClientNativePixmapFactory* CreateClientNativePixmapFactoryGbm();
-
-}  // namespace ui
-
-#endif  // UI_OZONE_PLATFORM_DRM_CLIENT_NATIVE_PIXMAP_FACTORY_GBM_H_
diff --git a/ui/ozone/platform/drm/ozone_platform_gbm.cc b/ui/ozone/platform/drm/ozone_platform_drm.cc
similarity index 94%
rename from ui/ozone/platform/drm/ozone_platform_gbm.cc
rename to ui/ozone/platform/drm/ozone_platform_drm.cc
index 4e81e147..8a64422 100644
--- a/ui/ozone/platform/drm/ozone_platform_gbm.cc
+++ b/ui/ozone/platform/drm/ozone_platform_drm.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/drm/ozone_platform_gbm.h"
+#include "ui/ozone/platform/drm/ozone_platform_drm.h"
 
 #include <gbm.h>
 #include <stdlib.h>
@@ -68,10 +68,10 @@
 
 namespace {
 
-class OzonePlatformGbm : public OzonePlatform {
+class OzonePlatformDrm : public OzonePlatform {
  public:
-  OzonePlatformGbm() = default;
-  ~OzonePlatformGbm() override = default;
+  OzonePlatformDrm() = default;
+  ~OzonePlatformDrm() override = default;
 
   // OzonePlatform:
   ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() override {
@@ -91,7 +91,7 @@
   }
 
   GpuPlatformSupportHost* GetGpuPlatformSupportHost() override {
-      return drm_device_connector_.get();
+    return drm_device_connector_.get();
   }
 
   std::unique_ptr<SystemInputInjector> CreateSystemInputInjector() override {
@@ -110,7 +110,7 @@
       // method after drm_thread is started.
       binders->Add<ozone::mojom::DrmDevice>(
           base::BindRepeating(
-              &OzonePlatformGbm::CreateDrmDeviceReceiverOnGpuThread,
+              &OzonePlatformDrm::CreateDrmDeviceReceiverOnGpuThread,
               weak_factory_.GetWeakPtr()),
           gpu_task_runner_);
     } else {
@@ -123,7 +123,7 @@
       // Binder callbacks should directly run on DRM thread.
       binders->Add<ozone::mojom::DrmDevice>(
           base::BindRepeating(
-              &OzonePlatformGbm::CreateDrmDeviceReceiverOnDrmThread,
+              &OzonePlatformDrm::CreateDrmDeviceReceiverOnDrmThread,
               weak_factory_.GetWeakPtr()),
           drm_thread_proxy_->GetDrmThreadTaskRunner());
     }
@@ -295,7 +295,7 @@
       DrainReceiverRequests();
     } else {
       auto safe_receiver_request_drainer = CreateSafeOnceCallback(
-          base::BindOnce(&OzonePlatformGbm::DrainReceiverRequests,
+          base::BindOnce(&OzonePlatformDrm::DrainReceiverRequests,
                          weak_factory_.GetWeakPtr()));
       drm_thread_proxy_->StartDrmThread(
           std::move(safe_receiver_request_drainer));
@@ -336,15 +336,15 @@
   std::unique_ptr<DrmDisplayHostManager> display_manager_;
   InitializedHostProperties host_properties_;
 
-  base::WeakPtrFactory<OzonePlatformGbm> weak_factory_{this};
-
-  DISALLOW_COPY_AND_ASSIGN(OzonePlatformGbm);
+  base::WeakPtrFactory<OzonePlatformDrm> weak_factory_{this};
+  OzonePlatformDrm(const OzonePlatformDrm&) = delete;
+  OzonePlatformDrm& operator=(const OzonePlatformDrm&) = delete;
 };
 
 }  // namespace
 
-OzonePlatform* CreateOzonePlatformGbm() {
-  return new OzonePlatformGbm;
+OzonePlatform* CreateOzonePlatformDrm() {
+  return new OzonePlatformDrm;
 }
 
 }  // namespace ui
diff --git a/ui/ozone/platform/drm/ozone_platform_drm.h b/ui/ozone/platform/drm/ozone_platform_drm.h
new file mode 100644
index 0000000..39cfa0d
--- /dev/null
+++ b/ui/ozone/platform/drm/ozone_platform_drm.h
@@ -0,0 +1,17 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_DRM_OZONE_PLATFORM_DRM_H_
+#define UI_OZONE_PLATFORM_DRM_OZONE_PLATFORM_DRM_H_
+
+namespace ui {
+
+class OzonePlatform;
+
+// Constructor hook for use in ozone_platform_list.cc
+OzonePlatform* CreateOzonePlatformDrm();
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_DRM_OZONE_PLATFORM_DRM_H_
diff --git a/ui/ozone/platform/drm/ozone_platform_gbm.h b/ui/ozone/platform/drm/ozone_platform_gbm.h
deleted file mode 100644
index 324535d9..0000000
--- a/ui/ozone/platform/drm/ozone_platform_gbm.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_OZONE_PLATFORM_DRM_OZONE_PLATFORM_GBM_H_
-#define UI_OZONE_PLATFORM_DRM_OZONE_PLATFORM_GBM_H_
-
-namespace ui {
-
-class OzonePlatform;
-
-// Constructor hook for use in ozone_platform_list.cc
-OzonePlatform* CreateOzonePlatformGbm();
-
-}  // namespace ui
-
-#endif  // UI_OZONE_PLATFORM_DRM_OZONE_PLATFORM_GBM_H_
diff --git a/ui/views/controls/message_box_view.cc b/ui/views/controls/message_box_view.cc
index 56b50de3..4d16c56 100644
--- a/ui/views/controls/message_box_view.cc
+++ b/ui/views/controls/message_box_view.cc
@@ -134,8 +134,13 @@
 
 MessageBoxView::~MessageBoxView() = default;
 
+views::Textfield* MessageBoxView::GetVisiblePromptField() {
+  return prompt_field_ && prompt_field_->GetVisible() ? prompt_field_ : nullptr;
+}
+
 base::string16 MessageBoxView::GetInputText() {
-  return prompt_field_ ? prompt_field_->GetText() : base::string16();
+  return prompt_field_ && prompt_field_->GetVisible() ? prompt_field_->GetText()
+                                                      : base::string16();
 }
 
 bool MessageBoxView::HasVisibleCheckBox() const {
@@ -143,7 +148,7 @@
 }
 
 bool MessageBoxView::IsCheckBoxSelected() {
-  return checkbox_ && checkbox_->GetChecked();
+  return checkbox_ && checkbox_->GetVisible() && checkbox_->GetChecked();
 }
 
 void MessageBoxView::SetCheckBoxLabel(const base::string16& label) {
@@ -212,7 +217,7 @@
 void MessageBoxView::ViewHierarchyChanged(
     const ViewHierarchyChangedDetails& details) {
   if (details.child == this && details.is_add) {
-    if (prompt_field_)
+    if (prompt_field_ && prompt_field_->GetVisible())
       prompt_field_->SelectAll(true);
 
     NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true);
diff --git a/ui/views/controls/message_box_view.h b/ui/views/controls/message_box_view.h
index 3ffceed..8d790f6b3 100644
--- a/ui/views/controls/message_box_view.h
+++ b/ui/views/controls/message_box_view.h
@@ -45,10 +45,11 @@
 
   ~MessageBoxView() override;
 
-  // Returns the text box.
-  views::Textfield* text_box() { return prompt_field_; }
+  // Returns the visible prompt field, returns nullptr otherwise.
+  views::Textfield* GetVisiblePromptField();
 
-  // Returns user entered data in the prompt field.
+  // Returns user entered data in the prompt field, returns an empty string if
+  // no visible prompt field.
   base::string16 GetInputText();
 
   // Returns true if this message box has a visible checkbox, false otherwise.
diff --git a/ui/views/controls/message_box_view_unittest.cc b/ui/views/controls/message_box_view_unittest.cc
index 4692c789..f8c82ea 100644
--- a/ui/views/controls/message_box_view_unittest.cc
+++ b/ui/views/controls/message_box_view_unittest.cc
@@ -132,4 +132,46 @@
   EXPECT_TRUE(message_box_->HasVisibleCheckBox());
 }
 
+TEST_F(MessageBoxViewTest, CheckGetVisiblePromptField) {
+  EXPECT_FALSE(message_box_->GetVisiblePromptField());
+
+  // Set the prompt field.
+  message_box_->SetPromptField(base::string16());
+  EXPECT_TRUE(message_box_->GetVisiblePromptField());
+}
+
+TEST_F(MessageBoxViewTest, CheckGetInputText) {
+  EXPECT_TRUE(message_box_->GetInputText().empty());
+
+  // Set the prompt field with an empty string. The returned text is still
+  // empty.
+  message_box_->SetPromptField(base::string16());
+  EXPECT_TRUE(message_box_->GetInputText().empty());
+
+  const base::string16 prompt = base::ASCIIToUTF16("prompt");
+  message_box_->SetPromptField(prompt);
+  EXPECT_FALSE(message_box_->GetInputText().empty());
+  EXPECT_EQ(prompt, message_box_->GetInputText());
+
+  // After user types some text, the returned input text should change to the
+  // user input.
+  views::Textfield* text_field = message_box_->GetVisiblePromptField();
+  const base::string16 input = base::ASCIIToUTF16("new input");
+  text_field->SetText(input);
+  EXPECT_FALSE(message_box_->GetInputText().empty());
+  EXPECT_EQ(input, message_box_->GetInputText());
+}
+
+TEST_F(MessageBoxViewTest, CheckIsCheckBoxSelected) {
+  EXPECT_FALSE(message_box_->IsCheckBoxSelected());
+
+  // Set and show a checkbox.
+  message_box_->SetCheckBoxLabel(base::ASCIIToUTF16("test checkbox"));
+  EXPECT_FALSE(message_box_->IsCheckBoxSelected());
+
+  // Select the checkbox.
+  message_box_->SetCheckBoxSelected(true);
+  EXPECT_TRUE(message_box_->IsCheckBoxSelected());
+}
+
 }  // namespace views
diff --git a/ui/webui/resources/cr_components/chromeos/network/BUILD.gn b/ui/webui/resources/cr_components/chromeos/network/BUILD.gn
index 1952014..271c35c 100644
--- a/ui/webui/resources/cr_components/chromeos/network/BUILD.gn
+++ b/ui/webui/resources/cr_components/chromeos/network/BUILD.gn
@@ -253,7 +253,6 @@
     ":cr_policy_network_behavior_mojo.m",
     ":cr_policy_network_indicator_mojo.m",
     ":mojo_interface_provider.m",
-
     ":network_apnlist.m",
     ":network_choose_mobile.m",
     ":network_config.m",
@@ -262,17 +261,15 @@
     ":network_config_select.m",
     ":network_config_toggle.m",
     ":network_icon.m",
-
     ":network_ip_config.m",
     ":network_list.m",
     ":network_list_item.m",
     ":network_list_types.m",
     ":network_listener_behavior.m",
-
     ":network_nameservers.m",
     ":network_password_input.m",
     ":network_property_list_mojo.m",
-    #  ":network_proxy.m",
+    ":network_proxy.m",
     ":network_proxy_exclusions.m",
     ":network_proxy_input.m",
     ":network_select.m",
@@ -511,9 +508,20 @@
 js_library("network_proxy.m") {
   sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network/network_proxy.m.js" ]
   deps = [
-    # TODO: Fill those in.
+    ":cr_policy_network_behavior_mojo.m",
+    ":network_proxy_exclusions.m",
+    ":network_proxy_input.m",
+    ":network_shared_css.m",
+    ":onc_mojo.m",
+    "//third_party/polymer/v3_0/components-chromium/iron-flex-layout:iron-flex-layout-classes",
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+    "//ui/webui/resources/cr_elements/cr_button:cr_button.m",
+    "//ui/webui/resources/cr_elements/cr_input:cr_input.m",
+    "//ui/webui/resources/cr_elements/cr_toggle:cr_toggle.m",
+    "//ui/webui/resources/js:assert.m",
+    "//ui/webui/resources/js:i18n_behavior.m",
   ]
-  extra_deps = [ ":modulize" ]
+  extra_deps = [ ":network_proxy_module" ]
 }
 
 js_library("network_proxy_exclusions.m") {
@@ -612,6 +620,7 @@
     ":network_property_list_mojo_module",
     ":network_proxy_exclusions_module",
     ":network_proxy_input_module",
+    ":network_proxy_module",
     ":network_select_module",
     ":network_shared_css_module",
     ":network_siminfo_module",
@@ -622,9 +631,7 @@
   js_file = "cr_policy_network_indicator_mojo.js"
   html_file = "cr_policy_network_indicator_mojo.html"
   html_type = "dom-module"
-  auto_imports = cr_components_chromeos_auto_imports + [
-    "ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.html|CrPolicyIndicatorBehavior,CrPolicyIndicatorType",
-  ]
+  auto_imports = cr_components_chromeos_auto_imports + [ "ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.html|CrPolicyIndicatorBehavior,CrPolicyIndicatorType" ]
 }
 
 polymer_modulizer("network_apnlist") {
@@ -639,13 +646,14 @@
   html_file = "network_choose_mobile.html"
   html_type = "dom-module"
   auto_imports = cr_components_chromeos_auto_imports
-  namespace_rewrites = cr_components_chromeos_namespace_rewrites + [
-    "cros_network_config.mojom.m.js|cros_network_config.mojom-lite.js",
-    "ip_address.mojom.m.js|ip_address.mojom-lite.js",
-    "mojo_bindings_lite.m.js|mojo_bindings_lite.js",
-    "network_types.mojom.m.js|network_types.mojom-lite.js",
-    "time.mojom.m.js|time.mojom-lite.js",
-  ]
+  namespace_rewrites =
+      cr_components_chromeos_namespace_rewrites + [
+        "cros_network_config.mojom.m.js|cros_network_config.mojom-lite.js",
+        "ip_address.mojom.m.js|ip_address.mojom-lite.js",
+        "mojo_bindings_lite.m.js|mojo_bindings_lite.js",
+        "network_types.mojom.m.js|network_types.mojom-lite.js",
+        "time.mojom.m.js|time.mojom-lite.js",
+      ]
 }
 
 polymer_modulizer("network_config") {
@@ -740,6 +748,14 @@
   namespace_rewrites = cr_components_chromeos_namespace_rewrites
 }
 
+polymer_modulizer("network_proxy") {
+  js_file = "network_proxy.js"
+  html_file = "network_proxy.html"
+  html_type = "dom-module"
+  auto_imports = cr_components_chromeos_auto_imports
+  namespace_rewrites = cr_components_chromeos_namespace_rewrites
+}
+
 polymer_modulizer("network_proxy_input") {
   js_file = "network_proxy_input.js"
   html_file = "network_proxy_input.html"
@@ -779,7 +795,6 @@
     "network_config_element_behavior.js",
     "network_listener_behavior.js",
     "network_list_types.js",
-    "network_proxy.js",
     "onc_mojo.js",
   ]
   namespace_rewrites = cr_components_chromeos_namespace_rewrites
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_proxy.html b/ui/webui/resources/cr_components/chromeos/network/network_proxy.html
index 41cf834..52229e7e 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_proxy.html
+++ b/ui/webui/resources/cr_components/chromeos/network/network_proxy.html
@@ -1,17 +1,18 @@
 <link rel="import" href="../../../html/polymer.html">
 
+<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
+<link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html">
+<link rel="import" href="chrome://resources/cr_elements/md_select_css.html">
+<link rel="import" href="chrome://resources/html/assert.html">
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
-<link rel="import" href="../../../cr_elements/cr_button/cr_button.html">
-<link rel="import" href="../../../cr_elements/cr_input/cr_input.html">
-<link rel="import" href="../../../cr_elements/cr_toggle/cr_toggle.html">
-<link rel="import" href="../../../cr_elements/hidden_style_css.html">
-<link rel="import" href="../../../html/assert.html">
-<link rel="import" href="../../../html/i18n_behavior.html">
-<link rel="import" href="../../../cr_elements/md_select_css.html">
 <link rel="import" href="cr_policy_network_behavior_mojo.html">
 <link rel="import" href="network_proxy_exclusions.html">
 <link rel="import" href="network_proxy_input.html">
 <link rel="import" href="network_shared_css.html">
+<link rel="import" href="onc_mojo.html">
 
 <dom-module id="network-proxy">
   <template>
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_proxy.js b/ui/webui/resources/cr_components/chromeos/network/network_proxy.js
index eeeb53d..c4fea63 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_proxy.js
+++ b/ui/webui/resources/cr_components/chromeos/network/network_proxy.js
@@ -6,8 +6,6 @@
  * @fileoverview Polymer element for displaying and editing network proxy
  * values.
  */
-(function() {
-'use strict';
 
 Polymer({
   is: 'network-proxy',
@@ -563,4 +561,3 @@
     return property === value;
   },
 });
-})();
diff --git a/ui/webui/resources/cr_components/cr_components_resources_v3.grdp b/ui/webui/resources/cr_components/cr_components_resources_v3.grdp
index 7017c3d..6b17fa1 100644
--- a/ui/webui/resources/cr_components/cr_components_resources_v3.grdp
+++ b/ui/webui/resources/cr_components/cr_components_resources_v3.grdp
@@ -116,6 +116,10 @@
            file="${root_gen_dir}/ui/webui/resources/cr_components/chromeos/network/network_proxy_input.m.js"
            use_base_dir="false"
            type="BINDATA" />
+    <include name="IDR_WEBUI_CHROMEOS_NETWORK_PROXY_M_JS"
+           file="${root_gen_dir}/ui/webui/resources/cr_components/chromeos/network/network_proxy.m.js"
+           use_base_dir="false"
+           type="BINDATA" />
     <include name="IDR_WEBUI_CHROMEOS_NETWORK_SELECT_M_JS"
            file="${root_gen_dir}/ui/webui/resources/cr_components/chromeos/network/network_select.m.js"
            use_base_dir="false"