diff --git a/BUILD.gn b/BUILD.gn
index 48eab0e..177e54a 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -816,6 +816,8 @@
       "//third_party/dawn/src/fuzzers:dawn_fuzzers",
       "//third_party/dawn/src/tests:dawn_end2end_tests",
       "//third_party/dawn/src/tests:dawn_unittests",
+      "//third_party/tint/src/fuzzers",
+      "//third_party/tint/src/test:tint_unittests",
     ]
   }
 
diff --git a/DEPS b/DEPS
index 3265d6c..25f7563 100644
--- a/DEPS
+++ b/DEPS
@@ -175,7 +175,7 @@
   # luci-go CIPD package version.
   # Make sure the revision is uploaded by infra-packagers builder.
   # https://ci.chromium.org/p/infra-internal/g/infra-packagers/console
-  'luci_go': 'git_revision:fd10124659e991321df2f8a5d3749687b54ceb0a',
+  'luci_go': 'git_revision:19175e196dd495f6e092845f7d777cb5bf157b3e',
 
   # This can be overridden, e.g. with custom_vars, to build clang from HEAD
   # instead of downloading the prebuilt pinned revision.
@@ -204,11 +204,11 @@
   # 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': 'ead52dc068d55efdebda41d2e8eef13a628f9f2f',
+  'skia_revision': '3230255e060e51b5296c811445162517d8c96afa',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '4e2fbf2b6d4fc2e9bbf239e146973a15bb3a0d40',
+  'v8_revision': '929acfd81ac536f1b7d5699427a01e1238efabd4',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -216,7 +216,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': '687d3153197e5ef162e7bc75e931a09208ba3fe6',
+  'angle_revision': '79e39478028c56b4be4e4549f8c9e53381ae48ce',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -255,7 +255,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
-  'freetype_revision': '2149b51f2543719b1ee78fb50ecf4e6e80f84ad7',
+  'freetype_revision': 'b0729b8fbb18dc1340ade628facf3f1cee498bfb',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
@@ -263,7 +263,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling HarfBuzz
   # and whatever else without interference from each other.
-  'harfbuzz_revision': '7686ff854bbb9698bb1469dcfe6d288c695a76b7',
+  'harfbuzz_revision': '4c34478b28497acfce02b8a544fed4ae20526336',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Emoji Segmenter
   # and whatever else without interference from each other.
@@ -283,7 +283,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': 'c1ef3e5ffa3b18285afe6bd7e4a70567954999cf',
+  'devtools_frontend_revision': '92feb60a1acd5fb8a9be021111df077d3d29bc2d',
   # 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.
@@ -319,11 +319,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'shaderc_revision': '01dd72d6079ebdc0f96859365ba7abb1b62758bf',
+  'shaderc_revision': '3fe94c6a76d2b617e7fb20fdf3cde98001a274e3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '8c40cad1c92d7e85154bbae4cb92539e2200d139',
+  'dawn_revision': '54586e61210cfdfc9835f81b57c794f4ac19356b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -363,7 +363,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'tint_revision': 'c205c28bc3dccaf66b00d9baf43e14c3f2ed030d',
+  'tint_revision': '1691401179376a45eaab52de47c5c11a34235186',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -697,7 +697,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'gRuwnwZrRAywjOPntIYH8-K7mi8twfkj8yOFVr08O2UC',
+          'version': '_ocTBL_keHvY732WpoWBfHmFEJ4jH6ZLqFCR8vCkZHsC',
       },
     ],
     'condition': 'checkout_android',
@@ -910,7 +910,7 @@
   # Tools used when building Chrome for Chrome OS. This affects both the Simple
   # Chrome workflow, as well as the chromeos-chrome ebuild.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '2923d76d948a1c485b9556a2a35ae7c236f3ac9b',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '16ecc391ff9a68eef9375cb5d7f7afca3c2b6aac',
       'condition': 'checkout_chromeos',
   },
 
@@ -1302,7 +1302,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '0f1ec9f510ae0cc8f800d08e8205017b6a8b8f3b',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '6ecb51ac72ea4de3663b4442ad3e72b64f660af1',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1576,7 +1576,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/linux-amd64',
-          'version': 'jstGnw4Pyb9uiuH75QNEy3f6hJN7ET2TFiOVOUiMokcC',
+          'version': '3T-SUsozYAVsudk5nd48kjHvfpos6egORLB8s7ElE8oC',
         },
       ],
       'dep_type': 'cipd',
@@ -1610,7 +1610,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@551a97a6caf8e41bc659ed28a7530950fd1a78a1',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@e7c96aaf8edb25f561c2c8fc45bee7e2893a867b',
     'condition': 'checkout_src_internal',
   },
 
@@ -1629,7 +1629,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': 'AvrhwSKvouEQfjPW1oyNKtm8-iyQah8Rti0GXOOOOIQC',
+        'version': '9ughCqekZmq8OqJKf4e_YPpRqbU8B2McTqbYID6TN2QC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1640,7 +1640,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'VOPDIUBlPNMPh5EpeCcB3tZ9h6bmZOiM2Dfr-95p-ekC',
+        'version': '-wDntdsX3lj1JJzGVLv_aRA4r7BlvIVU36NMDZxj5qEC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/android_webview/browser/aw_browser_main_parts.cc b/android_webview/browser/aw_browser_main_parts.cc
index 6f51ea6..028d911 100644
--- a/android_webview/browser/aw_browser_main_parts.cc
+++ b/android_webview/browser/aw_browser_main_parts.cc
@@ -32,6 +32,7 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/i18n/rtl.h"
+#include "base/logging.h"
 #include "base/message_loop/message_pump_type.h"
 #include "base/path_service.h"
 #include "base/task/current_thread.h"
@@ -167,7 +168,7 @@
   }
 }
 
-void AwBrowserMainParts::PreMainMessageLoopRun() {
+int AwBrowserMainParts::PreMainMessageLoopRun() {
   TRACE_EVENT0("startup", "AwBrowserMainParts::PreMainMessageLoopRun");
   AwBrowserProcess::GetInstance()->PreMainMessageLoopRun();
   browser_client_->InitBrowserContext();
@@ -175,12 +176,12 @@
       AwWebUIControllerFactory::GetInstance());
   content::RenderFrameHost::AllowInjectingJavaScript();
   metrics_logger_ = std::make_unique<metrics::MemoryMetricsLogger>();
+  return content::RESULT_CODE_NORMAL_EXIT;
 }
 
-bool AwBrowserMainParts::MainMessageLoopRun(int* result_code) {
-  // Android WebView does not use default MessageLoop. It has its own
-  // Android specific MessageLoop.
-  return true;
+void AwBrowserMainParts::WillRunMainMessageLoop(
+    std::unique_ptr<base::RunLoop>& run_loop) {
+  NOTREACHED();
 }
 
 void AwBrowserMainParts::PostCreateThreads() {
diff --git a/android_webview/browser/aw_browser_main_parts.h b/android_webview/browser/aw_browser_main_parts.h
index a9fa5a91..4fe381526 100644
--- a/android_webview/browser/aw_browser_main_parts.h
+++ b/android_webview/browser/aw_browser_main_parts.h
@@ -30,8 +30,9 @@
   // Overriding methods from content::BrowserMainParts.
   int PreEarlyInitialization() override;
   int PreCreateThreads() override;
-  void PreMainMessageLoopRun() override;
-  bool MainMessageLoopRun(int* result_code) override;
+  int PreMainMessageLoopRun() override;
+  void WillRunMainMessageLoop(
+      std::unique_ptr<base::RunLoop>& run_loop) override;
   void PostCreateThreads() override;
 
  private:
diff --git a/ash/accessibility/accessibility_controller_impl.cc b/ash/accessibility/accessibility_controller_impl.cc
index 14560ea6..68d1744 100644
--- a/ash/accessibility/accessibility_controller_impl.cc
+++ b/ash/accessibility/accessibility_controller_impl.cc
@@ -1114,8 +1114,6 @@
 
 void AccessibilityControllerImpl::StartPointScan() {
   if (::switches::IsSwitchAccessPointScanningEnabled()) {
-    if (!point_scan_controller_)
-      point_scan_controller_ = std::make_unique<PointScanController>();
     point_scan_controller_->Start();
   }
 }
@@ -1131,6 +1129,12 @@
     point_scan_controller_->HideAll();
 }
 
+void AccessibilityControllerImpl::SetPointScanSpeedDipsPerSecond(
+    int point_scan_speed_dips_per_second) {
+  point_scan_controller_->SetSpeedDipsPerSecond(
+      point_scan_speed_dips_per_second);
+}
+
 void AccessibilityControllerImpl::
     DisablePolicyRecommendationRestorerForTesting() {
   Shell::Get()->policy_recommendation_restorer()->DisableForTesting();
@@ -1790,6 +1794,11 @@
 
 void AccessibilityControllerImpl::UpdateSwitchAccessPointScanSpeedFromPref() {
   // TODO(accessibility): Log histogram for point scan speed
+  DCHECK(active_user_prefs_);
+  const int point_scan_speed_dips_per_second = active_user_prefs_->GetInteger(
+      prefs::kAccessibilitySwitchAccessPointScanSpeedDipsPerSecond);
+
+  SetPointScanSpeedDipsPerSecond(point_scan_speed_dips_per_second);
   SyncSwitchAccessPrefsToSignInProfile();
 }
 
@@ -1821,7 +1830,9 @@
 void AccessibilityControllerImpl::ActivateSwitchAccess() {
   switch_access_bubble_controller_ =
       std::make_unique<SwitchAccessMenuBubbleController>();
+  point_scan_controller_ = std::make_unique<PointScanController>();
   UpdateKeyCodesAfterSwitchAccessEnabled();
+  UpdateSwitchAccessPointScanSpeedFromPref();
   if (skip_switch_access_notification_) {
     skip_switch_access_notification_ = false;
     return;
@@ -1833,6 +1844,7 @@
 void AccessibilityControllerImpl::DeactivateSwitchAccess() {
   if (client_)
     client_->OnSwitchAccessDisabled();
+  point_scan_controller_.reset();
   switch_access_bubble_controller_.reset();
 }
 
diff --git a/ash/accessibility/accessibility_controller_impl.h b/ash/accessibility/accessibility_controller_impl.h
index 4d2ae0e..a0e9feba2 100644
--- a/ash/accessibility/accessibility_controller_impl.h
+++ b/ash/accessibility/accessibility_controller_impl.h
@@ -377,6 +377,8 @@
                             std::vector<std::string> actions_to_show) override;
   void StartPointScan() override;
   void StopPointScan() override;
+  void SetPointScanSpeedDipsPerSecond(
+      int point_scan_speed_dips_per_second) override;
   void SetDictationActive(bool is_active) override;
   void ToggleDictationFromSource(DictationToggleSource source) override;
   void HandleAutoclickScrollableBoundsFound(
diff --git a/ash/accessibility/point_scan_controller.cc b/ash/accessibility/point_scan_controller.cc
index 7cf15996..424dd508 100644
--- a/ash/accessibility/point_scan_controller.cc
+++ b/ash/accessibility/point_scan_controller.cc
@@ -9,25 +9,16 @@
 #include "ui/display/screen.h"
 
 namespace {
-// Scanning time in seconds from the start of the screen (offset_start) to the
-// end of the screen (offset_bound).
-constexpr float kHorizontalScanTimeSecs = 90;
-constexpr float kVerticalScanTimeSecs = 60;
-constexpr float kHorizontalRangeScanTimeSecs = 30;
-constexpr float kVerticalRangeScanTimeSecs = 25;
+
 constexpr int kDefaultRangeWidthDips = 150;
 constexpr float kDefaultRangeHeightDips = 120;
+constexpr float kLineScanSlowDownFactor = 0.5f;
 
 }  // namespace
 
 namespace ash {
 
-PointScanController::PointScanController() {
-  horizontal_line_layer_info_.animation_rate = kHorizontalScanTimeSecs;
-  horizontal_range_layer_info_.animation_rate = kHorizontalRangeScanTimeSecs;
-  vertical_line_layer_info_.animation_rate = kVerticalScanTimeSecs;
-  vertical_range_layer_info_.animation_rate = kVerticalRangeScanTimeSecs;
-}
+PointScanController::PointScanController() = default;
 
 PointScanController::~PointScanController() = default;
 
@@ -166,6 +157,19 @@
   }
 }
 
+void PointScanController::SetSpeedDipsPerSecond(int speed_dips_per_second) {
+  const gfx::Rect& display_bounds =
+      display::Screen::GetScreen()->GetPrimaryDisplay().bounds();
+  float width = display_bounds.width();
+  float height = display_bounds.height();
+  horizontal_range_layer_info_.animation_rate = width / speed_dips_per_second;
+  horizontal_line_layer_info_.animation_rate =
+      width / (speed_dips_per_second * kLineScanSlowDownFactor);
+  vertical_range_layer_info_.animation_rate = height / speed_dips_per_second;
+  vertical_line_layer_info_.animation_rate =
+      height / (speed_dips_per_second * kLineScanSlowDownFactor);
+}
+
 void PointScanController::OnDeviceScaleFactorChanged() {}
 
 void PointScanController::OnAnimationStep(base::TimeTicks timestamp) {
diff --git a/ash/accessibility/point_scan_controller.h b/ash/accessibility/point_scan_controller.h
index 0b8193d..26d9aa9 100644
--- a/ash/accessibility/point_scan_controller.h
+++ b/ash/accessibility/point_scan_controller.h
@@ -26,6 +26,8 @@
   PointScanController& operator=(const PointScanController&) = delete;
 
   enum class PointScanState {
+    // Point scanning is not scanning.
+    kOff,
     // Point scanning is currently range scanning horizontally.
     kHorizontalRangeScanning,
     // Point scanning is currently scanning horizontally.
@@ -34,8 +36,6 @@
     kVerticalRangeScanning,
     // Point scanning is currently scanning vertically.
     kVerticalScanning,
-    // Point scanning is not scanning.
-    kOff,
   };
 
   // Starts point scanning, by sweeping a range across the screen and waiting
@@ -50,6 +50,7 @@
   void ResetAnimation();
   base::Optional<gfx::PointF> OnPointSelect();
   bool IsPointScanEnabled();
+  void SetSpeedDipsPerSecond(int speed_dips_per_second);
 
  private:
   // AccessibilityLayerDelegate implementation:
@@ -69,7 +70,7 @@
   PointScanLayerAnimationInfo vertical_line_layer_info_;
   std::unique_ptr<PointScanLayer> vertical_line_layer_;
 
-  PointScanState state_;
+  PointScanState state_ = PointScanState::kOff;
 };
 
 }  // namespace ash
diff --git a/ash/login/ui/lock_screen.cc b/ash/login/ui/lock_screen.cc
index c7d2e5e5..99f42d8 100644
--- a/ash/login/ui/lock_screen.cc
+++ b/ash/login/ui/lock_screen.cc
@@ -20,12 +20,12 @@
 #include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
 #include "ash/wallpaper/wallpaper_controller_impl.h"
+#include "ash/wm/window_util.h"
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/command_line.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
-#include "ui/views/widget/widget.h"
 #include "ui/wm/core/capture_controller.h"
 
 namespace ash {
@@ -55,6 +55,14 @@
 }
 
 LockScreen::LockScreen(ScreenType type) : type_(type) {
+  auto* active_window = window_util::GetActiveWindow();
+  if (active_window) {
+    auto* active_widget =
+        views::Widget::GetWidgetForNativeWindow(active_window);
+    if (active_widget)
+      paint_as_active_lock_ = active_widget->LockPaintAsActive();
+  }
+
   tray_action_observation_.Observe(Shell::Get()->tray_action());
   saved_clipboard_ = ui::Clipboard::TakeForCurrentThread();
 }
diff --git a/ash/login/ui/lock_screen.h b/ash/login/ui/lock_screen.h
index e393f43..e5e2553 100644
--- a/ash/login/ui/lock_screen.h
+++ b/ash/login/ui/lock_screen.h
@@ -16,6 +16,7 @@
 #include "base/macros.h"
 #include "base/scoped_observation.h"
 #include "ui/base/clipboard/clipboard.h"
+#include "ui/views/widget/widget.h"
 
 namespace views {
 class View;
@@ -101,6 +102,8 @@
 
   std::unique_ptr<ui::Clipboard> saved_clipboard_;
 
+  std::unique_ptr<views::Widget::PaintAsActiveLock> paint_as_active_lock_;
+
   base::ScopedObservation<TrayAction, TrayActionObserver>
       tray_action_observation_{this};
   ScopedSessionObserver session_observer_{this};
diff --git a/ash/login/ui/lock_screen_media_controls_view.cc b/ash/login/ui/lock_screen_media_controls_view.cc
index d5d3345..9b3a180 100644
--- a/ash/login/ui/lock_screen_media_controls_view.cc
+++ b/ash/login/ui/lock_screen_media_controls_view.cc
@@ -235,7 +235,7 @@
 
   // Media controls should observe power events and handle the case of being
   // created in suspended state.
-  base::PowerMonitor::AddObserver(this);
+  base::PowerMonitor::AddPowerSuspendObserver(this);
   if (base::PowerMonitor::IsProcessSuspended()) {
     // Post OnSuspend call to run after LockContentsView is initialized.
     base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -451,7 +451,7 @@
     }
   }
 
-  base::PowerMonitor::RemoveObserver(this);
+  base::PowerMonitor::RemovePowerSuspendObserver(this);
 }
 
 gfx::Size LockScreenMediaControlsView::CalculatePreferredSize() const {
diff --git a/ash/login/ui/lock_screen_media_controls_view.h b/ash/login/ui/lock_screen_media_controls_view.h
index b59ac1a7..ef548750 100644
--- a/ash/login/ui/lock_screen_media_controls_view.h
+++ b/ash/login/ui/lock_screen_media_controls_view.h
@@ -41,7 +41,7 @@
     : public views::View,
       public media_session::mojom::MediaControllerObserver,
       public media_session::mojom::MediaControllerImageObserver,
-      public base::PowerObserver,
+      public base::PowerSuspendObserver,
       public ui::ImplicitAnimationObserver {
  public:
   METADATA_HEADER(LockScreenMediaControlsView);
@@ -132,7 +132,7 @@
   // ui::EventHandler:
   void OnGestureEvent(ui::GestureEvent* event) override;
 
-  // base::PowerObserver:
+  // base::PowerSuspendObserver:
   void OnSuspend() override;
 
   void ButtonPressed(media_session::mojom::MediaSessionAction action);
diff --git a/ash/projector/projector_controller_impl.cc b/ash/projector/projector_controller_impl.cc
index 1085ae5..1ac328a 100644
--- a/ash/projector/projector_controller_impl.cc
+++ b/ash/projector/projector_controller_impl.cc
@@ -51,14 +51,21 @@
   }
 }
 
-void ProjectorControllerImpl::ShowToolbar() {
+void ProjectorControllerImpl::SetProjectorToolsVisible(bool is_visible) {
   // TODO(yilkal): Projector toolbar shouldn't be shown if soda is not
   // available.
-  ui_controller_->ShowToolbar();
+  if (is_visible)
+    ui_controller_->ShowToolbar();
+  else
+    ui_controller_->CloseToolbar();
 }
 
-void ProjectorControllerImpl::CloseToolbar() {
-  ui_controller_->CloseToolbar();
+void ProjectorControllerImpl::StartProjectorSession() {
+  // TODO(https://crbug.com/1185262): Start projector session.
+}
+
+bool ProjectorControllerImpl::IsEligible() const {
+  return is_speech_recognition_available_;
 }
 
 void ProjectorControllerImpl::SetCaptionState(bool is_on) {
diff --git a/ash/projector/projector_controller_impl.h b/ash/projector/projector_controller_impl.h
index 39aebb69..26043bd 100644
--- a/ash/projector/projector_controller_impl.h
+++ b/ash/projector/projector_controller_impl.h
@@ -38,12 +38,9 @@
                        base::TimeDelta audio_end_time,
                        const std::vector<base::TimeDelta>& word_offsets,
                        bool is_final) override;
-
-  // Shows projector toolbar.
-  void ShowToolbar();
-  // Close projector toolbar.
-  void CloseToolbar();
-
+  void SetProjectorToolsVisible(bool is_visible) override;
+  void StartProjectorSession() override;
+  bool IsEligible() const override;
   // Set caption on/off state.
   void SetCaptionState(bool is_on);
   // Mark a key idea.
@@ -65,7 +62,6 @@
       std::unique_ptr<ProjectorMetadataController> metadata_controller);
 
   ProjectorUiController* ui_controller() { return ui_controller_.get(); }
-  bool is_eligible() const { return is_speech_recognition_available_; }
   ProjectorSessionImpl* projector_session() { return projector_session_.get(); }
 
  private:
diff --git a/ash/projector/projector_controller_unittest.cc b/ash/projector/projector_controller_unittest.cc
index 919b3c0..258a6c0 100644
--- a/ash/projector/projector_controller_unittest.cc
+++ b/ash/projector/projector_controller_unittest.cc
@@ -90,7 +90,7 @@
 TEST_F(ProjectorControllerTest, ShowToolbar) {
   // Verify that |ShowToolbar| in |ProjectorUiController| is called.
   EXPECT_CALL(*mock_ui_controller_, ShowToolbar()).Times(1);
-  controller_->ShowToolbar();
+  controller_->SetProjectorToolsVisible(true);
 }
 
 TEST_F(ProjectorControllerTest, SaveScreencast) {
@@ -165,10 +165,10 @@
 
 TEST_F(ProjectorControllerTest, OnSpeechRecognitionAvailable) {
   controller_->OnSpeechRecognitionAvailable(true);
-  EXPECT_TRUE(controller_->is_eligible());
+  EXPECT_TRUE(controller_->IsEligible());
 
   controller_->OnSpeechRecognitionAvailable(false);
-  EXPECT_FALSE(controller_->is_eligible());
+  EXPECT_FALSE(controller_->IsEligible());
 }
 
 }  // namespace ash
diff --git a/ash/projector/projector_feature_pod_controller.cc b/ash/projector/projector_feature_pod_controller.cc
index e926c366..2196b4b 100644
--- a/ash/projector/projector_feature_pod_controller.cc
+++ b/ash/projector/projector_feature_pod_controller.cc
@@ -62,10 +62,10 @@
 
   if (projector_session->is_active()) {
     projector_session->Stop();
-    projector_controller->CloseToolbar();
+    projector_controller->SetProjectorToolsVisible(false);
   } else {
     projector_session->Start();
-    projector_controller->ShowToolbar();
+    projector_controller->SetProjectorToolsVisible(true);
   }
 }
 
diff --git a/ash/projector/projector_ui_controller.cc b/ash/projector/projector_ui_controller.cc
index e204edb..ee62479d 100644
--- a/ash/projector/projector_ui_controller.cc
+++ b/ash/projector/projector_ui_controller.cc
@@ -83,4 +83,8 @@
     Shell::Get()->laser_pointer_controller()->SetEnabled(false);
 }
 
+bool ProjectorUiController::IsToolbarVisible() const {
+  return model_.bar_enabled();
+}
+
 }  // namespace ash
diff --git a/ash/projector/projector_ui_controller.h b/ash/projector/projector_ui_controller.h
index 2495639..4b12381 100644
--- a/ash/projector/projector_ui_controller.h
+++ b/ash/projector/projector_ui_controller.h
@@ -37,6 +37,8 @@
 
   ProjectorUiModel* model() { return &model_; }
 
+  bool IsToolbarVisible() const;
+
  private:
   // Reset tools, including resetting the state in model, closing the sub
   // widgets, etc.
diff --git a/ash/public/cpp/accessibility_controller.h b/ash/public/cpp/accessibility_controller.h
index 8982b82..afc9846 100644
--- a/ash/public/cpp/accessibility_controller.h
+++ b/ash/public/cpp/accessibility_controller.h
@@ -100,6 +100,10 @@
   // Stops point scanning in Switch Access.
   virtual void StopPointScan() = 0;
 
+  // Sets point scanning speed in Switch Access.
+  virtual void SetPointScanSpeedDipsPerSecond(
+      int point_scan_speed_dips_per_second) = 0;
+
   // Set whether dictation is active.
   virtual void SetDictationActive(bool is_active) = 0;
 
diff --git a/ash/public/cpp/projector/projector_controller.h b/ash/public/cpp/projector/projector_controller.h
index 66bbc12d..93160571 100644
--- a/ash/public/cpp/projector/projector_controller.h
+++ b/ash/public/cpp/projector/projector_controller.h
@@ -37,6 +37,16 @@
                                base::TimeDelta end_time,
                                const std::vector<base::TimeDelta>& word_offsets,
                                bool is_final) = 0;
+
+  // Sets projector toolbar visibility.
+  virtual void SetProjectorToolsVisible(bool is_visible) = 0;
+
+  // Starts a projector session.
+  // TODO(yilkal) : Pass the scope of the selection.
+  virtual void StartProjectorSession() = 0;
+
+  // Returns true if Projector is eligible to start a new session.
+  virtual bool IsEligible() const = 0;
 };
 
 }  // namespace ash
diff --git a/ash/shelf/shelf.cc b/ash/shelf/shelf.cc
index 6cedb14..0944db4 100644
--- a/ash/shelf/shelf.cc
+++ b/ash/shelf/shelf.cc
@@ -36,28 +36,33 @@
 #include "ui/display/types/display_constants.h"
 #include "ui/gfx/geometry/rect.h"
 
+namespace ash {
+
 namespace {
 
-bool IsAppListBackground(ash::ShelfBackgroundType background_type) {
+bool IsAppListBackground(ShelfBackgroundType background_type) {
   switch (background_type) {
-    case ash::ShelfBackgroundType::kAppList:
-    case ash::ShelfBackgroundType::kHomeLauncher:
-    case ash::ShelfBackgroundType::kMaximizedWithAppList:
+    case ShelfBackgroundType::kAppList:
+    case ShelfBackgroundType::kHomeLauncher:
+    case ShelfBackgroundType::kMaximizedWithAppList:
       return true;
-    case ash::ShelfBackgroundType::kDefaultBg:
-    case ash::ShelfBackgroundType::kMaximized:
-    case ash::ShelfBackgroundType::kOobe:
-    case ash::ShelfBackgroundType::kLogin:
-    case ash::ShelfBackgroundType::kLoginNonBlurredWallpaper:
-    case ash::ShelfBackgroundType::kOverview:
-    case ash::ShelfBackgroundType::kInApp:
+    case ShelfBackgroundType::kDefaultBg:
+    case ShelfBackgroundType::kMaximized:
+    case ShelfBackgroundType::kOobe:
+    case ShelfBackgroundType::kLogin:
+    case ShelfBackgroundType::kLoginNonBlurredWallpaper:
+    case ShelfBackgroundType::kOverview:
+    case ShelfBackgroundType::kInApp:
       return false;
   }
 }
 
-}  // namespace
+bool IsBottomAlignment(ShelfAlignment alignment) {
+  return alignment == ShelfAlignment::kBottom ||
+         alignment == ShelfAlignment::kBottomLocked;
+}
 
-namespace ash {
+}  // namespace
 
 // Records smoothness of bounds animations for the HotseatWidget.
 class HotseatWidgetAnimationMetricsReporter {
@@ -464,12 +469,17 @@
     return;
   }
 
+  bool needs_relayout =
+      !IsBottomAlignment(alignment_) || !IsBottomAlignment(alignment);
+
   ShelfAlignment old_alignment = alignment_;
   alignment_ = alignment;
   tooltip_->Close();
-  shelf_layout_manager_->LayoutShelf();
-  Shell::Get()->NotifyShelfAlignmentChanged(GetWindow()->GetRootWindow(),
-                                            old_alignment);
+  if (needs_relayout) {
+    shelf_layout_manager_->LayoutShelf();
+    Shell::Get()->NotifyShelfAlignmentChanged(GetWindow()->GetRootWindow(),
+                                              old_alignment);
+  }
 }
 
 bool Shelf::IsHorizontalAlignment() const {
diff --git a/ash/system/unified/notification_hidden_view.cc b/ash/system/unified/notification_hidden_view.cc
index 58b945c..2c44c9e 100644
--- a/ash/system/unified/notification_hidden_view.cc
+++ b/ash/system/unified/notification_hidden_view.cc
@@ -32,56 +32,61 @@
       ->ShowLockScreenNotificationSettings();
 }
 
+SkColor GetBackgroundColor() {
+  return AshColorProvider::Get()->GetControlsLayerColor(
+      AshColorProvider::ControlsLayerType::kControlBackgroundColorInactive);
+}
+
 }  // namespace
 
-NotificationHiddenView::NotificationHiddenView() {
-  auto* label = new views::Label;
-  label->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor(
-      AshColorProvider::ContentLayerType::kTextColorPrimary));
-  label->SetAutoColorReadabilityEnabled(false);
-  label->SetText(
+NotificationHiddenView::NotificationHiddenView()
+    : container_(AddChildView(std::make_unique<views::View>())),
+      label_(container_->AddChildView(std::make_unique<views::Label>())) {
+  label_->SetAutoColorReadabilityEnabled(false);
+  label_->SetText(
       l10n_util::GetStringUTF16(IDS_ASH_MESSAGE_CENTER_LOCKSCREEN_UNIFIED));
-  label->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT);
-  label->SetLineHeight(kUnifiedNotificationHiddenLineHeight);
-  label->SetBorder(views::CreateEmptyBorder(kUnifiedNotificationHiddenPadding));
+  label_->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT);
+  label_->SetLineHeight(kUnifiedNotificationHiddenLineHeight);
+  label_->SetBorder(
+      views::CreateEmptyBorder(kUnifiedNotificationHiddenPadding));
 
-  auto* container = new views::View;
-  container->SetBackground(views::CreateBackgroundFromPainter(
-      views::Painter::CreateSolidRoundRectPainter(
-          AshColorProvider::Get()->GetControlsLayerColor(
-              AshColorProvider::ControlsLayerType::
-                  kControlBackgroundColorInactive),
-          kUnifiedTrayCornerRadius)));
+  container_->SetBackground(views::CreateRoundedRectBackground(
+      GetBackgroundColor(), kUnifiedTrayCornerRadius));
 
-  auto* layout = container->SetLayoutManager(std::make_unique<views::BoxLayout>(
-      views::BoxLayout::Orientation::kHorizontal));
-
-  container->AddChildView(label);
-  layout->SetFlexForView(label, 1);
+  auto* layout =
+      container_->SetLayoutManager(std::make_unique<views::BoxLayout>(
+          views::BoxLayout::Orientation::kHorizontal));
+  layout->SetFlexForView(label_, 1);
 
   // Shows the "Change" button, unless the locks screen notification is
   // prohibited by policy or flag.
   if (AshMessageCenterLockScreenController::IsAllowed()) {
-    change_button_ = new RoundedLabelButton(
-        base::BindRepeating(&NotificationHiddenView::ChangeButtonPressed,
-                            base::Unretained(this)),
-        l10n_util::GetStringUTF16(IDS_ASH_MESSAGE_CENTER_LOCKSCREEN_CHANGE));
+    change_button_ =
+        container_->AddChildView(std::make_unique<RoundedLabelButton>(
+            base::BindRepeating(&NotificationHiddenView::ChangeButtonPressed,
+                                base::Unretained(this)),
+            l10n_util::GetStringUTF16(
+                IDS_ASH_MESSAGE_CENTER_LOCKSCREEN_CHANGE)));
     change_button_->SetTooltipText(l10n_util::GetStringUTF16(
         IDS_ASH_MESSAGE_CENTER_LOCKSCREEN_CHANGE_TOOLTIP));
-
-    container->AddChildView(change_button_);
   }
 
   SetBorder(
       views::CreateEmptyBorder(gfx::Insets(kUnifiedNotificationCenterSpacing)));
   SetLayoutManager(std::make_unique<views::FillLayout>());
-  AddChildView(container);
 }
 
 const char* NotificationHiddenView::GetClassName() const {
   return "NotificationHiddenView";
 }
 
+void NotificationHiddenView::OnThemeChanged() {
+  views::View::OnThemeChanged();
+  label_->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor(
+      AshColorProvider::ContentLayerType::kTextColorPrimary));
+  container_->background()->SetNativeControlColor(GetBackgroundColor());
+}
+
 void NotificationHiddenView::ChangeButtonPressed() {
   // TODO(yoshiki): Refactor LockScreenController and remove the static cast.
   // TODO(yoshiki): Show the setting after unlocking.
diff --git a/ash/system/unified/notification_hidden_view.h b/ash/system/unified/notification_hidden_view.h
index 84195479..1c7fcbe 100644
--- a/ash/system/unified/notification_hidden_view.h
+++ b/ash/system/unified/notification_hidden_view.h
@@ -9,6 +9,7 @@
 
 namespace views {
 class Button;
+class Label;
 }
 
 namespace ash {
@@ -23,12 +24,15 @@
 
   // views::View:
   const char* GetClassName() const override;
+  void OnThemeChanged() override;
 
   views::Button* change_button_for_testing() { return change_button_; }
 
  private:
   void ChangeButtonPressed();
 
+  views::View* const container_;
+  views::Label* const label_;
   views::Button* change_button_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(NotificationHiddenView);
diff --git a/ash/system/unified/unified_system_tray_controller.cc b/ash/system/unified/unified_system_tray_controller.cc
index 95e64811..e926ae2 100644
--- a/ash/system/unified/unified_system_tray_controller.cc
+++ b/ash/system/unified/unified_system_tray_controller.cc
@@ -448,7 +448,7 @@
   if (features::IsCaptureModeEnabled())
     AddFeaturePodItem(std::make_unique<CaptureModeFeaturePodController>(this));
   if (chromeos::features::IsProjectorFeaturePodEnabled() &&
-      Shell::Get()->projector_controller()->is_eligible()) {
+      Shell::Get()->projector_controller()->IsEligible()) {
     AddFeaturePodItem(std::make_unique<ProjectorFeaturePodController>(this));
   }
   AddFeaturePodItem(std::make_unique<NearbyShareFeaturePodController>(this));
diff --git a/ash/wallpaper/wallpaper_controller_impl.cc b/ash/wallpaper/wallpaper_controller_impl.cc
index d70a752..f23a8ed6 100644
--- a/ash/wallpaper/wallpaper_controller_impl.cc
+++ b/ash/wallpaper/wallpaper_controller_impl.cc
@@ -1433,6 +1433,7 @@
   if (wallpaper_mode_ == WALLPAPER_IMAGE &&
       (state == session_manager::SessionState::ACTIVE ||
        state == session_manager::SessionState::LOCKED ||
+       state == session_manager::SessionState::LOGGED_IN_NOT_ACTIVE ||
        state == session_manager::SessionState::LOGIN_SECONDARY)) {
     UpdateWallpaperForAllRootWindows(/*lock_state_changed=*/true);
   } else {
diff --git a/ash/wm/lock_state_controller.cc b/ash/wm/lock_state_controller.cc
index dd31e3b1..e16a825 100644
--- a/ash/wm/lock_state_controller.cc
+++ b/ash/wm/lock_state_controller.cc
@@ -437,7 +437,6 @@
 }
 
 void LockStateController::UnlockAnimationAfterUIDestroyedFinished() {
-  Shell::Get()->wallpaper_controller()->UpdateWallpaperBlurForLockState(false);
   RestoreUnlockedProperties();
 }
 
diff --git a/ash/wm/session_state_animator_impl.cc b/ash/wm/session_state_animator_impl.cc
index ffc62cb..5b767708 100644
--- a/ash/wm/session_state_animator_impl.cc
+++ b/ash/wm/session_state_animator_impl.cc
@@ -10,6 +10,7 @@
 
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/shell.h"
+#include "ash/wm/desks/desks_util.h"
 #include "ash/wm/window_animations.h"
 #include "base/barrier_closure.h"
 #include "ui/aura/client/aura_constants.h"
@@ -272,11 +273,18 @@
     aura::Window* non_lock_screen_containers = Shell::GetContainer(
         root_window, kShellWindowId_NonLockScreenContainersContainer);
     // |non_lock_screen_containers| may already be removed in some tests.
+    constexpr int ContainersToAnimate[] = {
+        kShellWindowId_HomeScreenContainer,
+        kShellWindowId_AlwaysOnTopContainer,
+        kShellWindowId_PipContainer,
+        kShellWindowId_SystemModalContainer,
+    };
     if (non_lock_screen_containers) {
       for (aura::Window* window : non_lock_screen_containers->children()) {
-        if (window->id() == kShellWindowId_ShelfContainer)
-          continue;
-        containers->push_back(window);
+        if ((base::Contains(ContainersToAnimate, window->id()) ||
+             desks_util::IsActiveDeskContainer(window))) {
+          containers->push_back(window);
+        }
       }
     }
   }
diff --git a/base/allocator/partition_allocator/address_pool_manager.cc b/base/allocator/partition_allocator/address_pool_manager.cc
index 0476c233..5d94826 100644
--- a/base/allocator/partition_allocator/address_pool_manager.cc
+++ b/base/allocator/partition_allocator/address_pool_manager.cc
@@ -353,7 +353,8 @@
                                     size_t length) {
   AutoLock guard(AddressPoolManagerBitmap::GetLock());
   // Currently, address regions allocated by kNormalBucketHandle are never freed
-  // in PartitionAlloc. Thus we have LIKELY for kDirectMapHandle
+  // in PartitionAlloc, except on error paths. Thus we have LIKELY for
+  // kDirectMapHandle
   if (LIKELY(handle == kDirectMapHandle)) {
     ResetBitmap(AddressPoolManagerBitmap::directmap_bits_,
                 address / PageAllocationGranularity(),
diff --git a/base/allocator/partition_allocator/page_allocator.cc b/base/allocator/partition_allocator/page_allocator.cc
index 04a4fdff..5104758 100644
--- a/base/allocator/partition_allocator/page_allocator.cc
+++ b/base/allocator/partition_allocator/page_allocator.cc
@@ -227,6 +227,20 @@
                               accessibility_disposition);
 }
 
+bool TryRecommitSystemPages(
+    void* address,
+    size_t length,
+    PageAccessibilityConfiguration accessibility,
+    PageAccessibilityDisposition accessibility_disposition) {
+  // Duplicated because we want errors to be reported at a lower level in the
+  // crashing case.
+  PA_DCHECK(!(reinterpret_cast<uintptr_t>(address) & SystemPageOffsetMask()));
+  PA_DCHECK(!(length & SystemPageOffsetMask()));
+  PA_DCHECK(accessibility != PageInaccessible);
+  return TryRecommitSystemPagesInternal(address, length, accessibility,
+                                        accessibility_disposition);
+}
+
 void DiscardSystemPages(void* address, size_t length) {
   PA_DCHECK(!(length & SystemPageOffsetMask()));
   DiscardSystemPagesInternal(address, length);
diff --git a/base/allocator/partition_allocator/page_allocator.h b/base/allocator/partition_allocator/page_allocator.h
index 2ae27448f..34516dd 100644
--- a/base/allocator/partition_allocator/page_allocator.h
+++ b/base/allocator/partition_allocator/page_allocator.h
@@ -161,6 +161,13 @@
     PageAccessibilityConfiguration page_accessibility,
     PageAccessibilityDisposition accessibility_disposition);
 
+// Like RecommitSystemPages(), but returns false instead of crashing.
+BASE_EXPORT bool TryRecommitSystemPages(
+    void* address,
+    size_t length,
+    PageAccessibilityConfiguration page_accessibility,
+    PageAccessibilityDisposition accessibility_disposition) WARN_UNUSED_RESULT;
+
 // Discard one or more system pages starting at |address| and continuing for
 // |length| bytes. |length| must be a multiple of |SystemPageSize()|.
 //
diff --git a/base/allocator/partition_allocator/page_allocator_internals_fuchsia.h b/base/allocator/partition_allocator/page_allocator_internals_fuchsia.h
index 05cfbcf..ee1e058 100644
--- a/base/allocator/partition_allocator/page_allocator_internals_fuchsia.h
+++ b/base/allocator/partition_allocator/page_allocator_internals_fuchsia.h
@@ -208,6 +208,20 @@
   }
 }
 
+bool TryRecommitSystemPagesInternal(
+    void* address,
+    size_t length,
+    PageAccessibilityConfiguration accessibility,
+    PageAccessibilityDisposition accessibility_disposition) {
+  // On Fuchsia systems, the caller needs to simply read the memory to recommit
+  // it. However, if decommit changed the permissions, recommit has to change
+  // them back.
+  if (accessibility_disposition == PageUpdatePermissions) {
+    return TrySetSystemPagesAccess(address, length, accessibility);
+  }
+  return true;
+}
+
 }  // namespace base
 
 #endif  // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_INTERNALS_FUCHSIA_H_
diff --git a/base/allocator/partition_allocator/page_allocator_internals_posix.h b/base/allocator/partition_allocator/page_allocator_internals_posix.h
index 014f0f0..6bdf30ab 100644
--- a/base/allocator/partition_allocator/page_allocator_internals_posix.h
+++ b/base/allocator/partition_allocator/page_allocator_internals_posix.h
@@ -286,6 +286,29 @@
 #endif
 }
 
+bool TryRecommitSystemPagesInternal(
+    void* address,
+    size_t length,
+    PageAccessibilityConfiguration accessibility,
+    PageAccessibilityDisposition accessibility_disposition) {
+  // On POSIX systems, the caller needs to simply read the memory to recommit
+  // it. However, if decommit changed the permissions, recommit has to change
+  // them back.
+  if (accessibility_disposition == PageUpdatePermissions) {
+    bool ok = TrySetSystemPagesAccess(address, length, accessibility);
+    if (!ok)
+      return false;
+  }
+
+#if defined(OS_APPLE)
+  // On macOS, to update accounting, we need to make another syscall. For more
+  // details, see https://crbug.com/823915.
+  madvise(address, length, MADV_FREE_REUSE);
+#endif
+
+  return true;
+}
+
 void DiscardSystemPagesInternal(void* address, size_t length) {
 #if defined(OS_APPLE)
   int ret = madvise(address, length, MADV_FREE_REUSABLE);
diff --git a/base/allocator/partition_allocator/page_allocator_internals_win.h b/base/allocator/partition_allocator/page_allocator_internals_win.h
index 69908b58..668adf2 100644
--- a/base/allocator/partition_allocator/page_allocator_internals_win.h
+++ b/base/allocator/partition_allocator/page_allocator_internals_win.h
@@ -123,6 +123,16 @@
   SetSystemPagesAccess(address, length, accessibility);
 }
 
+bool TryRecommitSystemPagesInternal(
+    void* address,
+    size_t length,
+    PageAccessibilityConfiguration accessibility,
+    PageAccessibilityDisposition accessibility_disposition) {
+  // Ignore accessibility_disposition, because decommitting is equivalent to
+  // making pages inaccessible.
+  return TrySetSystemPagesAccess(address, length, accessibility);
+}
+
 void DiscardSystemPagesInternal(void* address, size_t length) {
   // On Windows, discarded pages are not returned to the system immediately and
   // not guaranteed to be zeroed when returned to the application.
diff --git a/base/allocator/partition_allocator/partition_alloc_unittest.cc b/base/allocator/partition_allocator/partition_alloc_unittest.cc
index 1cf547f..7297f09 100644
--- a/base/allocator/partition_allocator/partition_alloc_unittest.cc
+++ b/base/allocator/partition_allocator/partition_alloc_unittest.cc
@@ -64,11 +64,11 @@
   // https://crbug.com/674665.
   const size_t kAddressSpaceLimit = static_cast<size_t>(6144) * 1024 * 1024;
   struct rlimit limit;
-  if (getrlimit(RLIMIT_AS, &limit) != 0)
+  if (getrlimit(RLIMIT_DATA, &limit) != 0)
     return false;
   if (limit.rlim_cur == RLIM_INFINITY || limit.rlim_cur > kAddressSpaceLimit) {
     limit.rlim_cur = kAddressSpaceLimit;
-    if (setrlimit(RLIMIT_AS, &limit) != 0)
+    if (setrlimit(RLIMIT_DATA, &limit) != 0)
       return false;
   }
   return true;
@@ -82,10 +82,10 @@
   return true;
 #elif defined(OS_POSIX)
   struct rlimit limit;
-  if (getrlimit(RLIMIT_AS, &limit) != 0)
+  if (getrlimit(RLIMIT_DATA, &limit) != 0)
     return false;
   limit.rlim_cur = limit.rlim_max;
-  if (setrlimit(RLIMIT_AS, &limit) != 0)
+  if (setrlimit(RLIMIT_DATA, &limit) != 0)
     return false;
   return true;
 #else
@@ -1653,29 +1653,28 @@
 // Performing them as death tests causes them to be forked into their own
 // process, so they won't pollute other tests.
 //
-// Disabled tests as they are (1) slow, and (2) don't work. They are slow
-// because with DCHECK_IS_ON() they memset() multiple tens of GiB of memory per
-// test, and they don't work because some EXPECT_*() fail, but since they are
-// wrapped into EXPECT_DEATH(), this is not reported.
-// See crbug.com/1168168 for details.
-TEST_F(PartitionAllocDeathTest, DISABLED_RepeatedAllocReturnNullDirect) {
+// These tests are *very* slow when DCHECK_IS_ON(), because they memset() many
+// GiB of data (see crbug.com/1168168).
+// TODO(lizeb): make these tests faster.
+TEST_F(PartitionAllocDeathTest, RepeatedAllocReturnNullDirect) {
   // A direct-mapped allocation size.
   EXPECT_DEATH(DoReturnNullTest(32 * 1024 * 1024, kPartitionAllocFlags),
                "DoReturnNullTest");
 }
 
 // Repeating above test with Realloc
-TEST_F(PartitionAllocDeathTest, DISABLED_RepeatedReallocReturnNullDirect) {
+TEST_F(PartitionAllocDeathTest, RepeatedReallocReturnNullDirect) {
   EXPECT_DEATH(DoReturnNullTest(32 * 1024 * 1024, kPartitionReallocFlags),
                "DoReturnNullTest");
 }
 
 // Repeating above test with TryRealloc
-TEST_F(PartitionAllocDeathTest, DISABLED_RepeatedTryReallocReturnNullDirect) {
+TEST_F(PartitionAllocDeathTest, RepeatedTryReallocReturnNullDirect) {
   EXPECT_DEATH(DoReturnNullTest(32 * 1024 * 1024, kPartitionRootTryRealloc),
                "DoReturnNullTest");
 }
 
+// See crbug.com/1187404 to re-enable the tests below.
 // Test "return null" with a 512 kB block size.
 TEST_F(PartitionAllocDeathTest, DISABLED_RepeatedAllocReturnNull) {
   // A single-slot but non-direct-mapped allocation size.
diff --git a/base/allocator/partition_allocator/partition_bucket.cc b/base/allocator/partition_allocator/partition_bucket.cc
index 6d79130..e8618be 100644
--- a/base/allocator/partition_allocator/partition_bucket.cc
+++ b/base/allocator/partition_allocator/partition_bucket.cc
@@ -39,7 +39,8 @@
 
   char* ptr = nullptr;
   // Allocate from GigaCage, if enabled.
-  if (features::IsPartitionAllocGigaCageEnabled()) {
+  bool with_giga_cage = features::IsPartitionAllocGigaCageEnabled();
+  if (with_giga_cage) {
     ptr = internal::AddressPoolManager::GetInstance()->Reserve(
         GetDirectMapPool(), nullptr, reserved_size);
   } else {
@@ -56,7 +57,26 @@
   char* slot = ptr + PartitionPageSize();
   RecommitSystemPages(ptr + SystemPageSize(), SystemPageSize(), PageReadWrite,
                       PageUpdatePermissions);
-  root->RecommitSystemPagesForData(slot, slot_size, PageUpdatePermissions);
+  // It is typically possible to map a large range of inaccessible pages, and
+  // this is leveraged in multiple places, including the GigaCage. However, this
+  // doesn't mean that we can commit all this memory.  For the vast majority of
+  // allocations, this just means that we crash in a slightly different places,
+  // but for callers ready to handle failures, we have to return nullptr.
+  // See crbug.com/1187404.
+  //
+  // Note that we didn't check above, because if we cannot even commit a single
+  // page, then this is likely hopeless anyway, and we will crash very soon.
+  bool ok = root->TryRecommitSystemPagesForData(slot, slot_size,
+                                                PageUpdatePermissions);
+  if (!ok) {
+    if (with_giga_cage) {
+      internal::AddressPoolManager::GetInstance()->UnreserveAndDecommit(
+          GetDirectMapPool(), ptr, reserved_size);
+    } else {
+      FreePages(ptr, reserved_size);
+    }
+    return nullptr;
+  }
 
   auto* metadata = reinterpret_cast<PartitionDirectMapMetadata<thread_safe>*>(
       PartitionSuperPageToMetadataArea(ptr));
@@ -408,6 +428,7 @@
   // knowledge which pages have been committed before (it doesn't matter on
   // Windows anyway).
   if (root->use_lazy_commit) {
+    // TODO(lizeb): Handle commit failure.
     root->RecommitSystemPagesForData(commit_start, commit_end - commit_start,
                                      PageUpdatePermissions);
   }
@@ -612,6 +633,7 @@
         // optimization. Otherwise fall back to PageUpdatePermissions (slower).
         // (Insider knowledge: as of writing this comment, lazy commit is only
         // used on Windows and this flag is ignored there, thus no perf impact.)
+        // TODO(lizeb): Handle commit failure.
         root->RecommitSystemPagesForData(
             addr, new_slot_span->bucket->get_bytes_per_span(),
             root->never_used_lazy_commit ? PageKeepPermissionsIfPossible
diff --git a/base/allocator/partition_allocator/partition_root.h b/base/allocator/partition_allocator/partition_root.h
index cbdcd99c..6235db1 100644
--- a/base/allocator/partition_allocator/partition_root.h
+++ b/base/allocator/partition_allocator/partition_root.h
@@ -273,6 +273,11 @@
       size_t length,
       PageAccessibilityDisposition accessibility_disposition)
       EXCLUSIVE_LOCKS_REQUIRED(lock_);
+  ALWAYS_INLINE bool TryRecommitSystemPagesForData(
+      void* address,
+      size_t length,
+      PageAccessibilityDisposition accessibility_disposition)
+      EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
   [[noreturn]] NOINLINE void OutOfMemory(size_t size);
 
@@ -1046,6 +1051,19 @@
   IncreaseCommittedPages(length);
 }
 
+template <bool thread_safe>
+ALWAYS_INLINE bool PartitionRoot<thread_safe>::TryRecommitSystemPagesForData(
+    void* address,
+    size_t length,
+    PageAccessibilityDisposition accessibility_disposition) {
+  bool ok = TryRecommitSystemPages(address, length, PageReadWrite,
+                                   accessibility_disposition);
+  if (ok)
+    IncreaseCommittedPages(length);
+
+  return ok;
+}
+
 // static
 // Returns the size available to the app. It can be equal or higher than the
 // requested size. If higher, the overage won't exceed what's actually usable
diff --git a/base/bind.h b/base/bind.h
index b238c5a..359e3533 100644
--- a/base/bind.h
+++ b/base/bind.h
@@ -70,15 +70,10 @@
                      !std::is_const<std::remove_reference_t<Functor>>()),
                 "BindOnce requires non-const rvalue for OnceCallback binding."
                 " I.e.: base::BindOnce(std::move(callback)).");
-#if defined(OS_APPLE) || defined(OS_CHROMEOS) || defined(OS_FUCHSIA) || \
-    defined(OS_LINUX) || defined(OS_WIN) ||                             \
-    defined(NCTEST_BIND_ONCE_WITH_PASSED)
-  // TODO(https://crbug.com/1180750): Enable this everywhere.
   static_assert(
       conjunction<
           internal::AssertBindArgIsNotBasePassed<std::decay_t<Args>>...>::value,
       "Use std::move() instead of base::Passed() with base::BindOnce()");
-#endif
 
   return internal::BindImpl<OnceCallback>(std::forward<Functor>(functor),
                                           std::forward<Args>(args)...);
diff --git a/base/power_monitor/power_monitor.cc b/base/power_monitor/power_monitor.cc
index d6aa6956..bddc00e 100644
--- a/base/power_monitor/power_monitor.cc
+++ b/base/power_monitor/power_monitor.cc
@@ -27,12 +27,34 @@
   return GetInstance()->source_.get() != nullptr;
 }
 
-void PowerMonitor::AddObserver(PowerObserver* obs) {
-  GetInstance()->observers_->AddObserver(obs);
+// static
+void PowerMonitor::AddPowerSuspendObserver(PowerSuspendObserver* obs) {
+  GetInstance()->power_suspend_observers_->AddObserver(obs);
 }
 
-void PowerMonitor::RemoveObserver(PowerObserver* obs) {
-  GetInstance()->observers_->RemoveObserver(obs);
+// static
+void PowerMonitor::RemovePowerSuspendObserver(PowerSuspendObserver* obs) {
+  GetInstance()->power_suspend_observers_->RemoveObserver(obs);
+}
+
+// static
+void PowerMonitor::AddPowerStateObserver(PowerStateObserver* obs) {
+  GetInstance()->power_state_observers_->AddObserver(obs);
+}
+
+// static
+void PowerMonitor::RemovePowerStateObserver(PowerStateObserver* obs) {
+  GetInstance()->power_state_observers_->RemoveObserver(obs);
+}
+
+// static
+void PowerMonitor::AddPowerThermalObserver(PowerThermalObserver* obs) {
+  GetInstance()->thermal_state_observers_->AddObserver(obs);
+}
+
+// static
+void PowerMonitor::RemovePowerThermalObserver(PowerThermalObserver* obs) {
+  GetInstance()->thermal_state_observers_->RemoveObserver(obs);
 }
 
 PowerMonitorSource* PowerMonitor::Source() {
@@ -54,14 +76,15 @@
 }
 
 // static
-PowerObserver::DeviceThermalState PowerMonitor::GetCurrentThermalState() {
+PowerThermalObserver::DeviceThermalState
+PowerMonitor::GetCurrentThermalState() {
   DCHECK(IsInitialized());
   return GetInstance()->source_->GetCurrentThermalState();
 }
 
 // static
 void PowerMonitor::SetCurrentThermalState(
-    PowerObserver::DeviceThermalState state) {
+    PowerThermalObserver::DeviceThermalState state) {
   DCHECK(IsInitialized());
   GetInstance()->source_->SetCurrentThermalState(state);
 }
@@ -77,8 +100,8 @@
   DCHECK(IsInitialized());
   DVLOG(1) << "PowerStateChange: " << (battery_in_use ? "On" : "Off")
            << " battery";
-  GetInstance()->observers_->Notify(
-      FROM_HERE, &PowerObserver::OnPowerStateChange, battery_in_use);
+  GetInstance()->power_state_observers_->Notify(
+      FROM_HERE, &PowerStateObserver::OnPowerStateChange, battery_in_use);
 }
 
 void PowerMonitor::NotifySuspend() {
@@ -87,7 +110,8 @@
                        TRACE_EVENT_SCOPE_PROCESS);
   DVLOG(1) << "Power Suspending";
   g_is_process_suspended.store(true, std::memory_order_relaxed);
-  GetInstance()->observers_->Notify(FROM_HERE, &PowerObserver::OnSuspend);
+  GetInstance()->power_suspend_observers_->Notify(
+      FROM_HERE, &PowerSuspendObserver::OnSuspend);
 }
 
 void PowerMonitor::NotifyResume() {
@@ -96,16 +120,17 @@
                        TRACE_EVENT_SCOPE_PROCESS);
   DVLOG(1) << "Power Resuming";
   g_is_process_suspended.store(false, std::memory_order_relaxed);
-  GetInstance()->observers_->Notify(FROM_HERE, &PowerObserver::OnResume);
+  GetInstance()->power_suspend_observers_->Notify(
+      FROM_HERE, &PowerSuspendObserver::OnResume);
 }
 
 void PowerMonitor::NotifyThermalStateChange(
-    PowerObserver::DeviceThermalState new_state) {
+    PowerThermalObserver::DeviceThermalState new_state) {
   DCHECK(IsInitialized());
   DVLOG(1) << "ThermalStateChange: "
            << PowerMonitorSource::DeviceThermalStateToString(new_state);
-  GetInstance()->observers_->Notify(
-      FROM_HERE, &PowerObserver::OnThermalStateChange, new_state);
+  GetInstance()->thermal_state_observers_->Notify(
+      FROM_HERE, &PowerThermalObserver::OnThermalStateChange, new_state);
 }
 
 PowerMonitor* PowerMonitor::GetInstance() {
@@ -114,8 +139,13 @@
 }
 
 PowerMonitor::PowerMonitor()
-    : observers_(
-          base::MakeRefCounted<ObserverListThreadSafe<PowerObserver>>()) {}
+    : power_state_observers_(
+          base::MakeRefCounted<ObserverListThreadSafe<PowerStateObserver>>()),
+      power_suspend_observers_(
+          base::MakeRefCounted<ObserverListThreadSafe<PowerSuspendObserver>>()),
+      thermal_state_observers_(
+          base::MakeRefCounted<
+              ObserverListThreadSafe<PowerThermalObserver>>()) {}
 
 PowerMonitor::~PowerMonitor() = default;
 
diff --git a/base/power_monitor/power_monitor.h b/base/power_monitor/power_monitor.h
index 5be1764a..11f1e15 100644
--- a/base/power_monitor/power_monitor.h
+++ b/base/power_monitor/power_monitor.h
@@ -42,10 +42,13 @@
   // Must not be called from within a notification callback.
   //
   // It is safe to add observers before the PowerMonitor is initialized. It is
-  // safe to call RemoveObserver with a PowerObserver that was not added as an
-  // observer.
-  static void AddObserver(PowerObserver* observer);
-  static void RemoveObserver(PowerObserver* observer);
+  // safe to remove an observer even if it was not added as an observer.
+  static void AddPowerSuspendObserver(PowerSuspendObserver* observer);
+  static void RemovePowerSuspendObserver(PowerSuspendObserver* observer);
+  static void AddPowerStateObserver(PowerStateObserver* observer);
+  static void RemovePowerStateObserver(PowerStateObserver* observer);
+  static void AddPowerThermalObserver(PowerThermalObserver* observer);
+  static void RemovePowerThermalObserver(PowerThermalObserver* observer);
 
   // Is the computer currently on battery power. May only be called if the
   // PowerMonitor has been initialized.
@@ -59,10 +62,11 @@
 
   // Read the current DeviceThermalState if known. Can be called on any thread.
   // May only be called if the PowerMonitor has been initialized.
-  static PowerObserver::DeviceThermalState GetCurrentThermalState();
+  static PowerThermalObserver::DeviceThermalState GetCurrentThermalState();
 
   // Update the result of thermal state.
-  static void SetCurrentThermalState(PowerObserver::DeviceThermalState state);
+  static void SetCurrentThermalState(
+      PowerThermalObserver::DeviceThermalState state);
 
 #if defined(OS_ANDROID)
   // Read and return the current remaining battery capacity (microampere-hours).
@@ -74,7 +78,7 @@
 
   // Uninitializes the PowerMonitor. Should be called at the end of any unit
   // test that mocks out the PowerMonitor, to avoid affecting subsequent tests.
-  // There must be no live PowerObservers when invoked. Safe to call even if the
+  // There must be no live observers when invoked. Safe to call even if the
   // PowerMonitor hasn't been initialized.
   static void ShutdownForTesting();
 
@@ -91,11 +95,16 @@
   static void NotifySuspend();
   static void NotifyResume();
   static void NotifyThermalStateChange(
-      PowerObserver::DeviceThermalState new_state);
+      PowerThermalObserver::DeviceThermalState new_state);
 
   static PowerMonitor* GetInstance();
 
-  scoped_refptr<ObserverListThreadSafe<PowerObserver>> observers_;
+  scoped_refptr<ObserverListThreadSafe<PowerStateObserver>>
+      power_state_observers_;
+  scoped_refptr<ObserverListThreadSafe<PowerSuspendObserver>>
+      power_suspend_observers_;
+  scoped_refptr<ObserverListThreadSafe<PowerThermalObserver>>
+      thermal_state_observers_;
   std::unique_ptr<PowerMonitorSource> source_;
 
   DISALLOW_COPY_AND_ASSIGN(PowerMonitor);
diff --git a/base/power_monitor/power_monitor_device_source.h b/base/power_monitor/power_monitor_device_source.h
index 937f418..4fe6b73 100644
--- a/base/power_monitor/power_monitor_device_source.h
+++ b/base/power_monitor/power_monitor_device_source.h
@@ -48,12 +48,14 @@
   static void SetPowerSource(bool on_battery);
   static void HandleSystemSuspending();
   static void HandleSystemResumed();
-  static void ThermalEventReceived(PowerObserver::DeviceThermalState state);
+  static void ThermalEventReceived(
+      PowerThermalObserver::DeviceThermalState state);
 
   // These two methods is used for handling thermal state update requests, such
   // as asking for initial state when starting lisitening to thermal change.
-  PowerObserver::DeviceThermalState GetCurrentThermalState() override;
-  void SetCurrentThermalState(PowerObserver::DeviceThermalState state) override;
+  PowerThermalObserver::DeviceThermalState GetCurrentThermalState() override;
+  void SetCurrentThermalState(
+      PowerThermalObserver::DeviceThermalState state) override;
 #endif
 
  private:
@@ -103,7 +105,7 @@
 
 #if defined(OS_MAC)
   // PowerMonitorSource:
-  PowerObserver::DeviceThermalState GetCurrentThermalState() override;
+  PowerThermalObserver::DeviceThermalState GetCurrentThermalState() override;
 
   // Reference to the system IOPMrootDomain port.
   io_connect_t power_manager_port_ = IO_OBJECT_NULL;
@@ -131,8 +133,8 @@
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  PowerObserver::DeviceThermalState current_thermal_state_ =
-      PowerObserver::DeviceThermalState::kUnknown;
+  PowerThermalObserver::DeviceThermalState current_thermal_state_ =
+      PowerThermalObserver::DeviceThermalState::kUnknown;
 #endif
   DISALLOW_COPY_AND_ASSIGN(PowerMonitorDeviceSource);
 };
diff --git a/base/power_monitor/power_monitor_device_source_chromeos.cc b/base/power_monitor/power_monitor_device_source_chromeos.cc
index 79533d5..dd38891a 100644
--- a/base/power_monitor/power_monitor_device_source_chromeos.cc
+++ b/base/power_monitor/power_monitor_device_source_chromeos.cc
@@ -39,7 +39,7 @@
 
 // static
 void PowerMonitorDeviceSource::ThermalEventReceived(
-    PowerObserver::DeviceThermalState state) {
+    PowerThermalObserver::DeviceThermalState state) {
   if (!PowerMonitor::IsInitialized()) {
     PowerMonitor::Initialize(std::make_unique<PowerMonitorDeviceSource>());
   }
@@ -48,13 +48,13 @@
   ProcessThermalEvent(state);
 }
 
-PowerObserver::DeviceThermalState
+PowerThermalObserver::DeviceThermalState
 PowerMonitorDeviceSource::GetCurrentThermalState() {
   return current_thermal_state_;
 }
 
 void PowerMonitorDeviceSource::SetCurrentThermalState(
-    PowerObserver::DeviceThermalState state) {
+    PowerThermalObserver::DeviceThermalState state) {
   current_thermal_state_ = state;
 }
 
diff --git a/base/power_monitor/power_monitor_device_source_mac.mm b/base/power_monitor/power_monitor_device_source_mac.mm
index 7ab0b5c9..e80c61e 100644
--- a/base/power_monitor/power_monitor_device_source_mac.mm
+++ b/base/power_monitor/power_monitor_device_source_mac.mm
@@ -67,7 +67,7 @@
   return found_battery;
 }
 
-PowerObserver::DeviceThermalState
+PowerThermalObserver::DeviceThermalState
 PowerMonitorDeviceSource::GetCurrentThermalState() {
   return thermal_state_observer_->GetCurrentThermalState();
 }
diff --git a/base/power_monitor/power_monitor_device_source_unittest.cc b/base/power_monitor/power_monitor_device_source_unittest.cc
index b8fabee..6545dc99 100644
--- a/base/power_monitor/power_monitor_device_source_unittest.cc
+++ b/base/power_monitor/power_monitor_device_source_unittest.cc
@@ -10,7 +10,7 @@
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using DeviceThermalState = base::PowerObserver::DeviceThermalState;
+using DeviceThermalState = base::PowerThermalObserver::DeviceThermalState;
 
 namespace base {
 
diff --git a/base/power_monitor/power_monitor_source.cc b/base/power_monitor/power_monitor_source.cc
index ff985812..1919546 100644
--- a/base/power_monitor/power_monitor_source.cc
+++ b/base/power_monitor/power_monitor_source.cc
@@ -17,12 +17,13 @@
   return on_battery_power_;
 }
 
-PowerObserver::DeviceThermalState PowerMonitorSource::GetCurrentThermalState() {
-  return PowerObserver::DeviceThermalState::kUnknown;
+PowerThermalObserver::DeviceThermalState
+PowerMonitorSource::GetCurrentThermalState() {
+  return PowerThermalObserver::DeviceThermalState::kUnknown;
 }
 
 void PowerMonitorSource::SetCurrentThermalState(
-    PowerObserver::DeviceThermalState state) {}
+    PowerThermalObserver::DeviceThermalState state) {}
 
 #if defined(OS_ANDROID)
 int PowerMonitorSource::GetRemainingBatteryCapacity() {
@@ -74,7 +75,7 @@
 
 // static
 void PowerMonitorSource::ProcessThermalEvent(
-    PowerObserver::DeviceThermalState new_thermal_state) {
+    PowerThermalObserver::DeviceThermalState new_thermal_state) {
   if (!PowerMonitor::IsInitialized())
     return;
   PowerMonitor::NotifyThermalStateChange(new_thermal_state);
@@ -91,17 +92,17 @@
 
 // static
 const char* PowerMonitorSource::DeviceThermalStateToString(
-    PowerObserver::DeviceThermalState state) {
+    PowerThermalObserver::DeviceThermalState state) {
   switch (state) {
-    case PowerObserver::DeviceThermalState::kUnknown:
+    case PowerThermalObserver::DeviceThermalState::kUnknown:
       return "Unknown";
-    case PowerObserver::DeviceThermalState::kNominal:
+    case PowerThermalObserver::DeviceThermalState::kNominal:
       return "Nominal";
-    case PowerObserver::DeviceThermalState::kFair:
+    case PowerThermalObserver::DeviceThermalState::kFair:
       return "Fair";
-    case PowerObserver::DeviceThermalState::kSerious:
+    case PowerThermalObserver::DeviceThermalState::kSerious:
       return "Serious";
-    case PowerObserver::DeviceThermalState::kCritical:
+    case PowerThermalObserver::DeviceThermalState::kCritical:
       return "Critical";
   }
   NOTREACHED();
diff --git a/base/power_monitor/power_monitor_source.h b/base/power_monitor/power_monitor_source.h
index 951c65b7..bd4626d 100644
--- a/base/power_monitor/power_monitor_source.h
+++ b/base/power_monitor/power_monitor_source.h
@@ -34,10 +34,11 @@
 
   // Reads the current DeviceThermalState, if available on the platform.
   // Otherwise, returns kUnknown.
-  virtual PowerObserver::DeviceThermalState GetCurrentThermalState();
+  virtual PowerThermalObserver::DeviceThermalState GetCurrentThermalState();
 
   // Update the result of thermal state.
-  virtual void SetCurrentThermalState(PowerObserver::DeviceThermalState state);
+  virtual void SetCurrentThermalState(
+      PowerThermalObserver::DeviceThermalState state);
 
 #if defined(OS_ANDROID)
   // Read and return the current remaining battery capacity (microampere-hours).
@@ -45,7 +46,7 @@
 #endif  // defined(OS_ANDROID)
 
   static const char* DeviceThermalStateToString(
-      PowerObserver::DeviceThermalState state);
+      PowerThermalObserver::DeviceThermalState state);
 
  protected:
   friend class PowerMonitorTest;
@@ -57,7 +58,7 @@
   // the UI thread or, in child processes, the IO thread.
   static void ProcessPowerEvent(PowerEvent event_id);
   static void ProcessThermalEvent(
-      PowerObserver::DeviceThermalState new_thermal_state);
+      PowerThermalObserver::DeviceThermalState new_thermal_state);
 
   // Platform-specific method to check whether the system is currently
   // running on battery power.  Returns true if running on batteries,
diff --git a/base/power_monitor/power_monitor_unittest.cc b/base/power_monitor/power_monitor_unittest.cc
index db18fbfa..d165230 100644
--- a/base/power_monitor/power_monitor_unittest.cc
+++ b/base/power_monitor/power_monitor_unittest.cc
@@ -40,8 +40,10 @@
   PowerMonitorInitialize();
 
   PowerMonitorTestObserver observers[kObservers];
-  for (auto& index : observers)
-    PowerMonitor::AddObserver(&index);
+  for (auto& index : observers) {
+    PowerMonitor::AddPowerSuspendObserver(&index);
+    PowerMonitor::AddPowerStateObserver(&index);
+  }
 
   // Sending resume when not suspended should have no effect.
   source()->GenerateResumeEvent();
@@ -83,22 +85,24 @@
   source()->GeneratePowerStateEvent(false);
   EXPECT_EQ(observers[0].power_state_changes(), 2);
 
-  for (auto& index : observers)
-    PowerMonitor::RemoveObserver(&index);
+  for (auto& index : observers) {
+    PowerMonitor::RemovePowerSuspendObserver(&index);
+    PowerMonitor::RemovePowerStateObserver(&index);
+  }
 }
 
 TEST_F(PowerMonitorTest, ThermalThrottling) {
   PowerMonitorTestObserver observer;
-  PowerMonitor::AddObserver(&observer);
+  PowerMonitor::AddPowerThermalObserver(&observer);
 
   PowerMonitorInitialize();
 
-  constexpr PowerObserver::DeviceThermalState kThermalStates[] = {
-      PowerObserver::DeviceThermalState::kUnknown,
-      PowerObserver::DeviceThermalState::kNominal,
-      PowerObserver::DeviceThermalState::kFair,
-      PowerObserver::DeviceThermalState::kSerious,
-      PowerObserver::DeviceThermalState::kCritical};
+  constexpr PowerThermalObserver::DeviceThermalState kThermalStates[] = {
+      PowerThermalObserver::DeviceThermalState::kUnknown,
+      PowerThermalObserver::DeviceThermalState::kNominal,
+      PowerThermalObserver::DeviceThermalState::kFair,
+      PowerThermalObserver::DeviceThermalState::kSerious,
+      PowerThermalObserver::DeviceThermalState::kCritical};
 
   for (const auto state : kThermalStates) {
     source()->GenerateThermalThrottlingEvent(state);
@@ -106,7 +110,7 @@
     EXPECT_EQ(observer.last_thermal_state(), state);
   }
 
-  PowerMonitor::RemoveObserver(&observer);
+  PowerMonitor::RemovePowerThermalObserver(&observer);
 }
 
 TEST_F(PowerMonitorTest, AddObserverBeforeAndAfterInitialization) {
@@ -114,12 +118,12 @@
   PowerMonitorTestObserver observer2;
 
   // An observer is added before the PowerMonitor initialization.
-  PowerMonitor::AddObserver(&observer1);
+  PowerMonitor::AddPowerSuspendObserver(&observer1);
 
   PowerMonitorInitialize();
 
   // An observer is added after the PowerMonitor initialization.
-  PowerMonitor::AddObserver(&observer2);
+  PowerMonitor::AddPowerSuspendObserver(&observer2);
 
   // Simulate suspend/resume notifications.
   source()->GenerateSuspendEvent();
@@ -132,8 +136,8 @@
   EXPECT_EQ(observer1.resumes(), 1);
   EXPECT_EQ(observer2.resumes(), 1);
 
-  PowerMonitor::RemoveObserver(&observer1);
-  PowerMonitor::RemoveObserver(&observer2);
+  PowerMonitor::RemovePowerSuspendObserver(&observer1);
+  PowerMonitor::RemovePowerSuspendObserver(&observer2);
 }
 
 }  // namespace base
diff --git a/base/power_monitor/power_observer.h b/base/power_monitor/power_observer.h
index e6e3d89..8dabe0c5 100644
--- a/base/power_monitor/power_observer.h
+++ b/base/power_monitor/power_observer.h
@@ -10,7 +10,29 @@
 
 namespace base {
 
-class BASE_EXPORT PowerObserver {
+class BASE_EXPORT PowerSuspendObserver {
+ public:
+  // Notification that the system is suspending.
+  virtual void OnSuspend() {}
+
+  // Notification that the system is resuming.
+  virtual void OnResume() {}
+
+ protected:
+  virtual ~PowerSuspendObserver() = default;
+};
+
+class BASE_EXPORT PowerStateObserver {
+ public:
+  // Notification of a change in power status of the computer, such
+  // as from switching between battery and A/C power.
+  virtual void OnPowerStateChange(bool on_battery_power) = 0;
+
+ protected:
+  virtual ~PowerStateObserver() = default;
+};
+
+class BASE_EXPORT PowerThermalObserver {
  public:
   // Values to indicate the system's thermal states: from kNominal onwards to
   // kCritical they represent increasing SoC die temperatures, usually needing
@@ -27,16 +49,6 @@
     kCritical,
   };
 
-  // Notification of a change in power status of the computer, such
-  // as from switching between battery and A/C power.
-  virtual void OnPowerStateChange(bool on_battery_power) {}
-
-  // Notification that the system is suspending.
-  virtual void OnSuspend() {}
-
-  // Notification that the system is resuming.
-  virtual void OnResume() {}
-
   // Notification of a change in the thermal status of the system, such as
   // entering a critical temperature range. Depending on the severity, the SoC
   // or the OS might take steps to reduce said temperature e.g., throttling the
@@ -44,10 +56,10 @@
   // state by reducing expensive computing tasks (e.g. video encoding), or
   // notifying the user. The same |new_state| might be received repeatedly.
   // TODO(crbug.com/1071431): implemented on MacOS, extend to Linux/CrOs.
-  virtual void OnThermalStateChange(DeviceThermalState new_state) {}
+  virtual void OnThermalStateChange(DeviceThermalState new_state) = 0;
 
  protected:
-  virtual ~PowerObserver() = default;
+  virtual ~PowerThermalObserver() = default;
 };
 
 }  // namespace base
diff --git a/base/power_monitor/thermal_state_observer_mac.h b/base/power_monitor/thermal_state_observer_mac.h
index 70466a3..a15c42b 100644
--- a/base/power_monitor/thermal_state_observer_mac.h
+++ b/base/power_monitor/thermal_state_observer_mac.h
@@ -20,17 +20,17 @@
 class BASE_EXPORT ThermalStateObserverMac {
  public:
   using StateUpdateCallback =
-      base::RepeatingCallback<void(PowerObserver::DeviceThermalState)>;
+      base::RepeatingCallback<void(PowerThermalObserver::DeviceThermalState)>;
 
   explicit ThermalStateObserverMac(StateUpdateCallback state_update_callback);
   ~ThermalStateObserverMac();
 
-  PowerObserver::DeviceThermalState GetCurrentThermalState();
+  PowerThermalObserver::DeviceThermalState GetCurrentThermalState();
 
  private:
   FRIEND_TEST_ALL_PREFIXES(ThermalStateObserverMacTest, StateChange);
-  PowerObserver::DeviceThermalState state_for_testing_ =
-      PowerObserver::DeviceThermalState::kUnknown;
+  PowerThermalObserver::DeviceThermalState state_for_testing_ =
+      PowerThermalObserver::DeviceThermalState::kUnknown;
 
   id thermal_state_update_observer_;
 };
diff --git a/base/power_monitor/thermal_state_observer_mac.mm b/base/power_monitor/thermal_state_observer_mac.mm
index 54b81aaa..f96ec59 100644
--- a/base/power_monitor/thermal_state_observer_mac.mm
+++ b/base/power_monitor/thermal_state_observer_mac.mm
@@ -12,21 +12,21 @@
 
 namespace {
 
-base::PowerObserver::DeviceThermalState
+base::PowerThermalObserver::DeviceThermalState
 NSProcessInfoThermalStateToDeviceThermalState(
     NSProcessInfoThermalState nsinfo_state) NS_AVAILABLE_MAC(10_10_3) {
   switch (nsinfo_state) {
     case NSProcessInfoThermalStateNominal:
-      return base::PowerObserver::DeviceThermalState::kNominal;
+      return base::PowerThermalObserver::DeviceThermalState::kNominal;
     case NSProcessInfoThermalStateFair:
-      return base::PowerObserver::DeviceThermalState::kFair;
+      return base::PowerThermalObserver::DeviceThermalState::kFair;
     case NSProcessInfoThermalStateSerious:
-      return base::PowerObserver::DeviceThermalState::kSerious;
+      return base::PowerThermalObserver::DeviceThermalState::kSerious;
     case NSProcessInfoThermalStateCritical:
-      return base::PowerObserver::DeviceThermalState::kCritical;
+      return base::PowerThermalObserver::DeviceThermalState::kCritical;
   }
   NOTREACHED();
-  return base::PowerObserver::DeviceThermalState::kUnknown;
+  return base::PowerThermalObserver::DeviceThermalState::kUnknown;
 }
 }
 
@@ -35,14 +35,15 @@
 ThermalStateObserverMac::ThermalStateObserverMac(
     StateUpdateCallback state_update_callback) NS_AVAILABLE_MAC(10_10_3) {
   auto on_state_change_block = ^(NSNotification* notification) {
-    auto state = PowerObserver::DeviceThermalState::kUnknown;
+    auto state = PowerThermalObserver::DeviceThermalState::kUnknown;
     // |thermalState| is basically a scale of power usage and its associated
     // thermal dissipation increase, from Nominal upwards, see:
     // https://developer.apple.com/library/archive/documentation/Performance/Conceptual/power_efficiency_guidelines_osx/RespondToThermalStateChanges.html
     NSProcessInfoThermalState nsinfo_state =
         [[NSProcessInfo processInfo] thermalState];
     state = NSProcessInfoThermalStateToDeviceThermalState(nsinfo_state);
-    if (state_for_testing_ != PowerObserver::DeviceThermalState::kUnknown)
+    if (state_for_testing_ !=
+        PowerThermalObserver::DeviceThermalState::kUnknown)
       state = state_for_testing_;
     DVLOG(1) << __func__ << ": "
              << PowerMonitorSource::DeviceThermalStateToString(state);
@@ -64,9 +65,9 @@
       removeObserver:thermal_state_update_observer_];
 }
 
-PowerObserver::DeviceThermalState
+PowerThermalObserver::DeviceThermalState
 ThermalStateObserverMac::GetCurrentThermalState() NS_AVAILABLE_MAC(10_10_3) {
-  if (state_for_testing_ != PowerObserver::DeviceThermalState::kUnknown)
+  if (state_for_testing_ != PowerThermalObserver::DeviceThermalState::kUnknown)
     return state_for_testing_;
   NSProcessInfoThermalState nsinfo_state =
       [[NSProcessInfo processInfo] thermalState];
diff --git a/base/power_monitor/thermal_state_observer_mac_unittest.mm b/base/power_monitor/thermal_state_observer_mac_unittest.mm
index 3ecaae78..53237ec 100644
--- a/base/power_monitor/thermal_state_observer_mac_unittest.mm
+++ b/base/power_monitor/thermal_state_observer_mac_unittest.mm
@@ -13,7 +13,7 @@
 #include "base/power_monitor/power_monitor_source.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using DeviceThermalState = base::PowerObserver::DeviceThermalState;
+using DeviceThermalState = base::PowerThermalObserver::DeviceThermalState;
 
 namespace base {
 
diff --git a/base/synchronization/waitable_event_watcher_unittest.cc b/base/synchronization/waitable_event_watcher_unittest.cc
index 81ab5cf..27e6fc3 100644
--- a/base/synchronization/waitable_event_watcher_unittest.cc
+++ b/base/synchronization/waitable_event_watcher_unittest.cc
@@ -204,7 +204,8 @@
   RunLoop().Run();
 }
 
-TEST_P(WaitableEventWatcherTest, MultipleWatchersManual) {
+// Disabled due to flakes; see https://crbug.com/1188547.
+TEST_P(WaitableEventWatcherTest, DISABLED_MultipleWatchersManual) {
   test::TaskEnvironment task_environment(GetParam());
 
   WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL,
diff --git a/base/task/sequence_manager/thread_controller_power_monitor.cc b/base/task/sequence_manager/thread_controller_power_monitor.cc
index 3098a99..ad9f591 100644
--- a/base/task/sequence_manager/thread_controller_power_monitor.cc
+++ b/base/task/sequence_manager/thread_controller_power_monitor.cc
@@ -26,7 +26,7 @@
 ThreadControllerPowerMonitor::ThreadControllerPowerMonitor() = default;
 
 ThreadControllerPowerMonitor::~ThreadControllerPowerMonitor() {
-  PowerMonitor::RemoveObserver(this);
+  PowerMonitor::RemovePowerSuspendObserver(this);
 }
 
 void ThreadControllerPowerMonitor::BindToCurrentThread() {
@@ -34,10 +34,10 @@
   // ThreadController::SetDefaultTaskRunner() re-initializes the
   // ThreadController).
   if (is_observer_registered_)
-    PowerMonitor::RemoveObserver(this);
+    PowerMonitor::RemovePowerSuspendObserver(this);
 
   // Register the observer to deliver notifications on the current thread.
-  PowerMonitor::AddObserver(this);
+  PowerMonitor::AddPowerSuspendObserver(this);
   is_observer_registered_ = true;
 }
 
diff --git a/base/task/sequence_manager/thread_controller_power_monitor.h b/base/task/sequence_manager/thread_controller_power_monitor.h
index 46b44c8..3069e7b 100644
--- a/base/task/sequence_manager/thread_controller_power_monitor.h
+++ b/base/task/sequence_manager/thread_controller_power_monitor.h
@@ -14,7 +14,7 @@
 // A helper class that keeps track of the power state and handles power
 // notifications. The class register itself to the PowerMonitor and receives
 // notifications on the bound thread (see BindToCurrentThread(...)).
-class BASE_EXPORT ThreadControllerPowerMonitor : public PowerObserver {
+class BASE_EXPORT ThreadControllerPowerMonitor : public PowerSuspendObserver {
  public:
   ThreadControllerPowerMonitor();
   ~ThreadControllerPowerMonitor() override;
@@ -37,7 +37,7 @@
   static void OverrideUsePowerMonitorForTesting(bool use_power_monitor);
   static void ResetForTesting();
 
-  // base::PowerObserver:
+  // base::PowerSuspendObserver:
   void OnSuspend() override;
   void OnResume() override;
 
diff --git a/base/test/power_monitor_test_base.cc b/base/test/power_monitor_test_base.cc
index f66c599..0c54322 100644
--- a/base/test/power_monitor_test_base.cc
+++ b/base/test/power_monitor_test_base.cc
@@ -18,7 +18,7 @@
 
 PowerMonitorTestSource::~PowerMonitorTestSource() = default;
 
-PowerObserver::DeviceThermalState
+PowerThermalObserver::DeviceThermalState
 PowerMonitorTestSource::GetCurrentThermalState() {
   return current_thermal_state_;
 }
@@ -44,7 +44,7 @@
 }
 
 void PowerMonitorTestSource::GenerateThermalThrottlingEvent(
-    PowerObserver::DeviceThermalState new_thermal_state) {
+    PowerThermalObserver::DeviceThermalState new_thermal_state) {
   ProcessThermalEvent(new_thermal_state);
   current_thermal_state_ = new_thermal_state;
   RunLoop().RunUntilIdle();
@@ -59,7 +59,6 @@
 
 PowerMonitorTestObserver::~PowerMonitorTestObserver() = default;
 
-// PowerObserver callbacks.
 void PowerMonitorTestObserver::OnPowerStateChange(bool on_battery_power) {
   last_power_state_ = on_battery_power;
   power_state_changes_++;
@@ -74,7 +73,7 @@
 }
 
 void PowerMonitorTestObserver::OnThermalStateChange(
-    PowerObserver::DeviceThermalState new_state) {
+    PowerThermalObserver::DeviceThermalState new_state) {
   last_thermal_state_ = new_state;
 }
 
diff --git a/base/test/power_monitor_test_base.h b/base/test/power_monitor_test_base.h
index ac104ff..b5dd983 100644
--- a/base/test/power_monitor_test_base.h
+++ b/base/test/power_monitor_test_base.h
@@ -14,40 +14,44 @@
  public:
   PowerMonitorTestSource();
   ~PowerMonitorTestSource() override;
-  PowerObserver::DeviceThermalState GetCurrentThermalState() override;
+  PowerThermalObserver::DeviceThermalState GetCurrentThermalState() override;
 
   void GeneratePowerStateEvent(bool on_battery_power);
   void GenerateSuspendEvent();
   void GenerateResumeEvent();
   void GenerateThermalThrottlingEvent(
-      PowerObserver::DeviceThermalState new_thermal_state);
+      PowerThermalObserver::DeviceThermalState new_thermal_state);
 
  protected:
   bool IsOnBatteryPowerImpl() override;
 
   bool test_on_battery_power_ = false;
-  PowerObserver::DeviceThermalState current_thermal_state_ =
-      PowerObserver::DeviceThermalState::kUnknown;
+  PowerThermalObserver::DeviceThermalState current_thermal_state_ =
+      PowerThermalObserver::DeviceThermalState::kUnknown;
 };
 
-class PowerMonitorTestObserver : public PowerObserver {
+class PowerMonitorTestObserver : public PowerSuspendObserver,
+                                 public PowerThermalObserver,
+                                 public PowerStateObserver {
  public:
   PowerMonitorTestObserver();
   ~PowerMonitorTestObserver() override;
 
-  // PowerObserver callbacks.
+  // PowerStateObserver overrides.
   void OnPowerStateChange(bool on_battery_power) override;
+  // PowerSuspendObserver overrides.
   void OnSuspend() override;
   void OnResume() override;
+  // PowerThermalObserver overrides.
   void OnThermalStateChange(
-      PowerObserver::DeviceThermalState new_state) override;
+      PowerThermalObserver::DeviceThermalState new_state) override;
 
   // Test status counts.
   bool last_power_state() const { return last_power_state_; }
   int power_state_changes() const { return power_state_changes_; }
   int suspends() const { return suspends_; }
   int resumes() const { return resumes_; }
-  PowerObserver::DeviceThermalState last_thermal_state() const {
+  PowerThermalObserver::DeviceThermalState last_thermal_state() const {
     return last_thermal_state_;
   }
 
@@ -56,7 +60,7 @@
   int power_state_changes_;  // Count of OnPowerStateChange notifications.
   int suspends_;             // Count of OnSuspend notifications.
   int resumes_;              // Count of OnResume notifications.
-  PowerObserver::DeviceThermalState last_thermal_state_;
+  PowerThermalObserver::DeviceThermalState last_thermal_state_;
 };
 
 }  // namespace base
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
index ce16488c..aa30785 100644
--- a/base/threading/thread_restrictions.h
+++ b/base/threading/thread_restrictions.h
@@ -123,7 +123,7 @@
 class RTCVideoEncoder;
 class SourceStream;
 class VideoFrameResourceProvider;
-class WebRtcVideoFrameAdapter;
+class LegacyWebRtcVideoFrameAdapter;
 class WorkerThread;
 namespace scheduler {
 class WorkerThread;
@@ -537,7 +537,7 @@
   friend class base::StackSamplingProfiler;
   friend class blink::RTCVideoDecoderAdapter;
   friend class blink::RTCVideoEncoder;
-  friend class blink::WebRtcVideoFrameAdapter;
+  friend class blink::LegacyWebRtcVideoFrameAdapter;
   friend class cc::TileTaskManagerImpl;
   friend class content::CategorizedWorkerPool;
   friend class content::DesktopCaptureDevice;
diff --git a/base/timer/hi_res_timer_manager.h b/base/timer/hi_res_timer_manager.h
index bfa316d..974bbf7 100644
--- a/base/timer/hi_res_timer_manager.h
+++ b/base/timer/hi_res_timer_manager.h
@@ -16,13 +16,16 @@
 
 // Ensures that the Windows high resolution timer is only used
 // when not running on battery power.
-class BASE_EXPORT HighResolutionTimerManager : public base::PowerObserver {
+class BASE_EXPORT HighResolutionTimerManager
+    : public base::PowerSuspendObserver,
+      public base::PowerStateObserver {
  public:
   HighResolutionTimerManager();
   ~HighResolutionTimerManager() override;
 
-  // base::PowerObserver methods.
+  // base::PowerStateObserver methods.
   void OnPowerStateChange(bool on_battery_power) override;
+  // base::PowerSuspendObserver methods.
   void OnSuspend() override;
   void OnResume() override;
 
diff --git a/base/timer/hi_res_timer_manager_win.cc b/base/timer/hi_res_timer_manager_win.cc
index 1ac214f4..b6f66f5 100644
--- a/base/timer/hi_res_timer_manager_win.cc
+++ b/base/timer/hi_res_timer_manager_win.cc
@@ -42,7 +42,8 @@
   // hi_res_clock_available_ will remain at its initial value.
   if (HighResolutionTimerAllowed()) {
     DCHECK(PowerMonitor::IsInitialized());
-    PowerMonitor::AddObserver(this);
+    PowerMonitor::AddPowerSuspendObserver(this);
+    PowerMonitor::AddPowerStateObserver(this);
     UseHiResClock(!PowerMonitor::IsOnBatteryPower());
 
     // Start polling the high resolution timer usage.
@@ -54,7 +55,8 @@
 
 HighResolutionTimerManager::~HighResolutionTimerManager() {
   if (HighResolutionTimerAllowed()) {
-    PowerMonitor::RemoveObserver(this);
+    PowerMonitor::RemovePowerSuspendObserver(this);
+    PowerMonitor::RemovePowerStateObserver(this);
     UseHiResClock(false);
   }
 }
diff --git a/base/util/timer/wall_clock_timer.cc b/base/util/timer/wall_clock_timer.cc
index 1407775..f53b38f6 100644
--- a/base/util/timer/wall_clock_timer.cc
+++ b/base/util/timer/wall_clock_timer.cc
@@ -53,14 +53,14 @@
 
 void WallClockTimer::AddObserver() {
   if (!observer_added_) {
-    base::PowerMonitor::AddObserver(this);
+    base::PowerMonitor::AddPowerSuspendObserver(this);
     observer_added_ = true;
   }
 }
 
 void WallClockTimer::RemoveObserver() {
   if (observer_added_) {
-    base::PowerMonitor::RemoveObserver(this);
+    base::PowerMonitor::RemovePowerSuspendObserver(this);
     observer_added_ = false;
   }
 }
diff --git a/base/util/timer/wall_clock_timer.h b/base/util/timer/wall_clock_timer.h
index 752a7b1c..a36a467d6 100644
--- a/base/util/timer/wall_clock_timer.h
+++ b/base/util/timer/wall_clock_timer.h
@@ -36,7 +36,7 @@
 // destructor.
 // - The destructor may be called from any sequence when the timer is not
 // running and there is no scheduled task active.
-class WallClockTimer : public base::PowerObserver {
+class WallClockTimer : public base::PowerSuspendObserver {
  public:
   // Constructs a timer. Start() must be called later to start the timer.
   // If |clock| is provided, it's used instead of
@@ -74,7 +74,7 @@
   // Returns true if the timer is running.
   bool IsRunning() const;
 
-  // base::PowerObserver:
+  // base::PowerSuspendObserver:
   void OnResume() override;
 
   base::Time desired_run_time() const { return desired_run_time_; }
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index 4bedf1ef..0ef73ab 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -232,7 +232,7 @@
 } else if (target_os == "fuchsia") {
   _default_toolchain = "//build/toolchain/fuchsia:$target_cpu"
 } else if (target_os == "ios") {
-  _default_toolchain = "//build/toolchain/mac:ios_clang_$target_cpu"
+  _default_toolchain = "//build/toolchain/ios:ios_clang_$target_cpu"
 } else if (target_os == "mac") {
   assert(host_os == "mac" || host_os == "linux",
          "Mac cross-compiles are unsupported.")
diff --git a/build/config/android/BUILD.gn b/build/config/android/BUILD.gn
index 78c7983a7..8cfe7a0 100644
--- a/build/config/android/BUILD.gn
+++ b/build/config/android/BUILD.gn
@@ -51,6 +51,14 @@
     "-Wl,--exclude-libs=libvpx_assembly_arm.a",
   ]
 
+  # TODO(crbug.com/1184398): Move to compiler-rt when we are ready.
+  ldflags += [ "--rtlib=libgcc" ]
+  if (current_cpu == "arm64") {
+    # For outline atomics on AArch64 (can't pass this unconditionally
+    # due to unused flag warning on other targets).
+    cflags += [ "--rtlib=libgcc" ]
+  }
+
   # $compile_api_level corresponds to the API level used for the sysroot path
   # calculation in //build/config/android/config.gni
   if (current_cpu == "arm") {
diff --git a/build/config/ios/ios_sdk.gni b/build/config/ios/ios_sdk.gni
index d6017cc3..e2c4d71 100644
--- a/build/config/ios/ios_sdk.gni
+++ b/build/config/ios/ios_sdk.gni
@@ -101,7 +101,7 @@
     assert(_additional_target_cpu != target_cpu,
            "target_cpu must not be listed in additional_target_cpus")
 
-    _toolchain = "//build/toolchain/mac:ios_clang_${_additional_target_cpu}_fat"
+    _toolchain = "//build/toolchain/ios:ios_clang_${_additional_target_cpu}_fat"
     foreach(_additional_toolchain, additional_toolchains) {
       assert(_toolchain != _additional_toolchain,
              "additional_target_cpus must not contains duplicate values")
diff --git a/build/config/mac/mac_sdk.gni b/build/config/mac/mac_sdk.gni
index 1ee2ded..6f7c7e5 100644
--- a/build/config/mac/mac_sdk.gni
+++ b/build/config/mac/mac_sdk.gni
@@ -64,7 +64,7 @@
 # The path to the hermetic install of Xcode. Only relevant when
 # use_system_xcode = false.
 if (!use_system_xcode) {
-  _hermetic_xcode_path = "//build/${target_os}_files/xcode_binaries"
+  _hermetic_xcode_path = "//build/mac_files/xcode_binaries"
 }
 
 script_name = "//build/config/apple/sdk_info.py"
diff --git a/build/dotfile_settings.gni b/build/dotfile_settings.gni
index f6a4a00d..3d869b3 100644
--- a/build/dotfile_settings.gni
+++ b/build/dotfile_settings.gni
@@ -17,11 +17,11 @@
     "//build/config/host_byteorder.gni",
     "//build/config/ios/ios_sdk.gni",
     "//build/config/ios/rules.gni",
-    "//build/config/linux/BUILD.gn",
-    "//build/config/linux/pkg_config.gni",
     "//build/config/linux/atk/BUILD.gn",
     "//build/config/linux/atspi2/BUILD.gn",
+    "//build/config/linux/BUILD.gn",
     "//build/config/linux/dri/BUILD.gn",
+    "//build/config/linux/pkg_config.gni",
     "//build/config/mac/mac_sdk.gni",
     "//build/config/mac/rules.gni",
     "//build/config/posix/BUILD.gn",
@@ -30,10 +30,10 @@
     "//build/config/win/BUILD.gn",
     "//build/config/win/visual_studio_version.gni",
     "//build/timestamp.gni",
+    "//build/toolchain/apple/toolchain.gni",
     "//build/toolchain/BUILD.gn",
     "//build/toolchain/concurrent_links.gni",
     "//build/toolchain/goma.gni",
-    "//build/toolchain/mac/BUILD.gn",
     "//build/toolchain/nacl/BUILD.gn",
     "//build/toolchain/toolchain.gni",
     "//build/toolchain/win/BUILD.gn",
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index cc75a47..0488b00 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-3.20210315.1.1
+3.20210316.1.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index cc75a47..0488b00 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-3.20210315.1.1
+3.20210316.1.1
diff --git a/build/toolchain/apple/BUILD.gn b/build/toolchain/apple/BUILD.gn
new file mode 100644
index 0000000..6f074fd
--- /dev/null
+++ b/build/toolchain/apple/BUILD.gn
@@ -0,0 +1,22 @@
+# Copyright 2021 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("//build/toolchain/concurrent_links.gni")
+
+declare_args() {
+  # Reduce the number of tasks using the copy_bundle_data and compile_xcassets
+  # tools as they can cause lots of I/O contention when invoking ninja with a
+  # large number of parallel jobs (e.g. when using distributed build like goma).
+  bundle_pool_depth = -1
+}
+
+if (current_toolchain == default_toolchain) {
+  pool("bundle_pool") {
+    if (bundle_pool_depth == -1) {
+      depth = concurrent_links
+    } else {
+      depth = bundle_pool_depth
+    }
+  }
+}
diff --git a/build/toolchain/mac/filter_libtool.py b/build/toolchain/apple/filter_libtool.py
similarity index 100%
rename from build/toolchain/mac/filter_libtool.py
rename to build/toolchain/apple/filter_libtool.py
diff --git a/build/toolchain/mac/get_tool_mtime.py b/build/toolchain/apple/get_tool_mtime.py
similarity index 100%
rename from build/toolchain/mac/get_tool_mtime.py
rename to build/toolchain/apple/get_tool_mtime.py
diff --git a/build/toolchain/apple/toolchain.gni b/build/toolchain/apple/toolchain.gni
new file mode 100644
index 0000000..51b4e6f
--- /dev/null
+++ b/build/toolchain/apple/toolchain.gni
@@ -0,0 +1,533 @@
+# Copyright (c) 2013 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.
+
+# TODO(brettw) Use "gcc_toolchain.gni" like the Linux toolchains. This requires
+# some enhancements since the commands on Mac are slightly different than on
+# Linux.
+
+import("//build/config/apple/symbols.gni")
+import("//build/config/clang/clang.gni")
+import("//build/config/compiler/compiler.gni")
+import("//build/config/coverage/coverage.gni")
+import("//build/config/mac/mac_sdk.gni")
+import("//build/toolchain/cc_wrapper.gni")
+import("//build/toolchain/goma.gni")
+import("//build/toolchain/toolchain.gni")
+
+if (is_ios) {
+  import("//build/config/ios/ios_sdk.gni")
+}
+
+assert((is_ios && host_os == "mac") || host_os != "win")
+
+declare_args() {
+  # This makes the linker set timestamps in Mach-O files to 0. This isn't
+  # enabled by default because this breaks Xcode's lldb. This has been fixed in
+  # https://reviews.llvm.org/rL368199 but that has not yet made it into a public
+  # lldb release.
+  mac_deterministic_build = false
+
+  # This controls whether whole module optimization is enabled when building
+  # Swift modules. If enabled, the compiler will compile the module as one
+  # unit, generating just one single object file. Otherwise, it will generate
+  # one object file per .swift file. If unspecified, will default to "true"
+  # for official builds, and "false" for all other builds.
+  swift_whole_module_optimization = -1
+}
+
+if (swift_whole_module_optimization == -1) {
+  swift_whole_module_optimization = is_official_build
+}
+
+# When implementing tools using Python scripts, a TOOL_VERSION=N env
+# variable is placed in front of the command. The N should be incremented
+# whenever the script is changed, so that the build system rebuilds all
+# edges that utilize the script. Ideally this should be changed to use
+# proper input-dirty checking, but that could be expensive. Instead, use a
+# script to get the tool scripts' modification time to use as the version.
+# This won't cause a re-generation of GN files when the tool script changes
+# but it will cause edges to be marked as dirty if the ninja files are
+# regenerated. See https://crbug.com/619083 for details. A proper fix
+# would be to have inputs to tools (https://crbug.com/621119).
+tool_versions =
+    exec_script("get_tool_mtime.py",
+                rebase_path([
+                              "//build/toolchain/apple/filter_libtool.py",
+                              "//build/toolchain/apple/linker_driver.py",
+                              "//build/toolchain/ios/compile_xcassets.py",
+                              "//build/toolchain/ios/swiftc.py",
+                            ],
+                            root_build_dir),
+                "trim scope")
+
+# Shared toolchain definition. Invocations should set current_os to set the
+# build args in this definition.
+template("apple_toolchain") {
+  toolchain(target_name) {
+    # When invoking this toolchain not as the default one, these args will be
+    # passed to the build. They are ignored when this is the default toolchain.
+    assert(defined(invoker.toolchain_args),
+           "Toolchains must declare toolchain_args")
+    toolchain_args = {
+      # Populate toolchain args from the invoker.
+      forward_variables_from(invoker.toolchain_args, "*")
+
+      # The host toolchain value computed by the default toolchain's setup
+      # needs to be passed through unchanged to all secondary toolchains to
+      # ensure that it's always the same, regardless of the values that may be
+      # set on those toolchains.
+      host_toolchain = host_toolchain
+    }
+
+    # Supports building with the version of clang shipped with Xcode when
+    # targeting iOS by not respecting clang_base_path.
+    if (toolchain_args.current_os == "ios" && use_xcode_clang) {
+      prefix = ""
+    } else {
+      prefix = rebase_path("$clang_base_path/bin/", root_build_dir)
+    }
+
+    _cc = "${prefix}clang"
+    _cxx = "${prefix}clang++"
+
+    swiftmodule_switch = "-Wl,-add_ast_path,"
+
+    # When the invoker has explicitly overridden use_goma or cc_wrapper in the
+    # toolchain args, use those values, otherwise default to the global one.
+    # This works because the only reasonable override that toolchains might
+    # supply for these values are to force-disable them.
+    if (defined(toolchain_args.use_goma)) {
+      toolchain_uses_goma = toolchain_args.use_goma
+    } else {
+      toolchain_uses_goma = use_goma
+    }
+    if (defined(toolchain_args.cc_wrapper)) {
+      toolchain_cc_wrapper = toolchain_args.cc_wrapper
+    } else {
+      toolchain_cc_wrapper = cc_wrapper
+    }
+
+    # Compute the compiler prefix.
+    if (toolchain_uses_goma) {
+      assert(toolchain_cc_wrapper == "",
+             "Goma and cc_wrapper can't be used together.")
+      compiler_prefix = "$goma_dir/gomacc "
+    } else if (toolchain_cc_wrapper != "") {
+      compiler_prefix = toolchain_cc_wrapper + " "
+    } else {
+      compiler_prefix = ""
+    }
+
+    cc = compiler_prefix + _cc
+    cxx = compiler_prefix + _cxx
+    ld = _cxx
+
+    # Set the explicit search path for clang++ so it uses the right linker
+    # binary.
+    ld += " -B " + mac_bin_path
+
+    if (defined(toolchain_args.coverage_instrumentation_input_file)) {
+      toolchain_coverage_instrumentation_input_file =
+          toolchain_args.coverage_instrumentation_input_file
+    } else {
+      toolchain_coverage_instrumentation_input_file =
+          coverage_instrumentation_input_file
+    }
+    _use_clang_coverage_wrapper =
+        toolchain_coverage_instrumentation_input_file != ""
+    if (_use_clang_coverage_wrapper) {
+      _coverage_wrapper =
+          rebase_path("//build/toolchain/clang_code_coverage_wrapper.py",
+                      root_build_dir) + " --files-to-instrument=" +
+          rebase_path(toolchain_coverage_instrumentation_input_file,
+                      root_build_dir) + " --target-os=" + target_os
+      cc = "$python_path $_coverage_wrapper ${cc}"
+      cxx = "$python_path $_coverage_wrapper ${cxx}"
+    }
+
+    linker_driver =
+        "TOOL_VERSION=${tool_versions.linker_driver} " +
+        rebase_path("//build/toolchain/apple/linker_driver.py", root_build_dir)
+
+    # Specify an explicit path for the strip binary.
+    _strippath = mac_bin_path + "strip"
+    linker_driver += " -Wcrl,strippath," + _strippath
+
+    if (mac_deterministic_build) {
+      linker_driver += " --deterministic"
+    }
+
+    # On iOS, the final applications are assembled using lipo (to support fat
+    # builds). The correct flags are passed to the linker_driver.py script
+    # directly during the lipo call. The test is against the target_os because
+    # there is no need to create .dSYMs for targets compiled for the host.
+    if (target_os != "ios") {
+      _enable_dsyms = enable_dsyms
+      _save_unstripped_output = save_unstripped_output
+    } else {
+      _enable_dsyms = false
+      _save_unstripped_output = false
+    }
+
+    # Make these apply to all tools below.
+    lib_switch = "-l"
+    lib_dir_switch = "-L"
+
+    # Object files go in this directory. Use label_name instead of
+    # target_output_name since labels will generally have no spaces and will be
+    # unique in the directory.
+    object_subdir = "{{target_out_dir}}/{{label_name}}"
+
+    # If dSYMs are enabled, this flag will be added to the link tools.
+    if (_enable_dsyms) {
+      dsym_switch = " -Wcrl,dsym,{{root_out_dir}} "
+      dsym_switch += "-Wcrl,dsymutilpath," +
+                     rebase_path("//tools/clang/dsymutil/bin/dsymutil",
+                                 root_build_dir) + " "
+
+      dsym_output_dir =
+          "{{root_out_dir}}/{{target_output_name}}{{output_extension}}.dSYM"
+      dsym_output = [
+        "$dsym_output_dir/Contents/Info.plist",
+        "$dsym_output_dir/Contents/Resources/DWARF/" +
+            "{{target_output_name}}{{output_extension}}",
+      ]
+    } else {
+      dsym_switch = ""
+    }
+
+    if (_save_unstripped_output) {
+      _unstripped_output = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}.unstripped"
+    }
+
+    tool("cc") {
+      depfile = "{{output}}.d"
+      precompiled_header_type = "gcc"
+      command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
+      depsformat = "gcc"
+      description = "CC {{output}}"
+      outputs = [ "$object_subdir/{{source_name_part}}.o" ]
+    }
+
+    tool("cxx") {
+      depfile = "{{output}}.d"
+      precompiled_header_type = "gcc"
+      command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}"
+      depsformat = "gcc"
+      description = "CXX {{output}}"
+      outputs = [ "$object_subdir/{{source_name_part}}.o" ]
+    }
+
+    tool("asm") {
+      # For GCC we can just use the C compiler to compile assembly.
+      depfile = "{{output}}.d"
+      command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}"
+      depsformat = "gcc"
+      description = "ASM {{output}}"
+      outputs = [ "$object_subdir/{{source_name_part}}.o" ]
+    }
+
+    tool("objc") {
+      depfile = "{{output}}.d"
+      precompiled_header_type = "gcc"
+      command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{framework_dirs}} {{cflags}} {{cflags_objc}} -c {{source}} -o {{output}}"
+      depsformat = "gcc"
+      description = "OBJC {{output}}"
+      outputs = [ "$object_subdir/{{source_name_part}}.o" ]
+    }
+
+    tool("objcxx") {
+      depfile = "{{output}}.d"
+      precompiled_header_type = "gcc"
+      command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{framework_dirs}} {{cflags}} {{cflags_objcc}} -c {{source}} -o {{output}}"
+      depsformat = "gcc"
+      description = "OBJCXX {{output}}"
+      outputs = [ "$object_subdir/{{source_name_part}}.o" ]
+    }
+
+    tool("alink") {
+      rspfile = "{{output}}.rsp"
+
+      if (!use_lld) {
+        # Note about -filelist: Apple's linker reads the file list file and
+        # interprets each newline-separated chunk of text as a file name. It
+        # doesn't do the things one would expect from the shell like unescaping
+        # or handling quotes. In contrast, when Ninja finds a file name with
+        # spaces, it single-quotes them in $inputs_newline as it would normally
+        # do for command-line arguments. Thus any source names with spaces, or
+        # label names with spaces (which GN bases the output paths on) will be
+        # corrupted by this process. Don't use spaces for source files or
+        # labels.
+        rspfile_content = "{{inputs_newline}}"
+
+        script = rebase_path("//build/toolchain/apple/filter_libtool.py",
+                             root_build_dir)
+
+        # Specify explicit path for libtool.
+        libtool = mac_bin_path + "libtool"
+        command = "rm -f {{output}} && TOOL_VERSION=${tool_versions.filter_libtool} $python_path $script $libtool -static -D {{arflags}} -o {{output}} -filelist $rspfile"
+        description = "LIBTOOL-STATIC {{output}}"
+      } else {
+        rspfile_content = "{{inputs}}"
+        ar = "${prefix}llvm-ar"
+        command = "\"$ar\" {{arflags}} -r -c -s -D {{output}} \"@$rspfile\""
+
+        # Remove the output file first so that ar doesn't try to modify the
+        # existing file.
+        command = "rm -f {{output}} && $command"
+        description = "AR {{output}}"
+      }
+      outputs = [ "{{output_dir}}/{{target_output_name}}{{output_extension}}" ]
+      default_output_dir = "{{target_out_dir}}"
+      default_output_extension = ".a"
+      output_prefix = "lib"
+    }
+
+    tool("solink") {
+      # E.g. "./libfoo.dylib":
+      dylib = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
+      rspfile = dylib + ".rsp"
+      pool = "//build/toolchain:link_pool($default_toolchain)"
+
+      # These variables are not built into GN but are helpers that implement
+      # (1) linking to produce a .dylib, (2) extracting the symbols from that
+      # file to a temporary file, (3) if the temporary file has differences from
+      # the existing .TOC file, overwrite it, otherwise, don't change it.
+      #
+      # As a special case, if the library reexports symbols from other dynamic
+      # libraries, we always update the .TOC and skip the temporary file and
+      # diffing steps, since that library always needs to be re-linked.
+      tocname = dylib + ".TOC"
+      temporary_tocname = dylib + ".tmp"
+
+      # Use explicit paths to binaries. The binaries present on the default
+      # search path in /usr/bin are thin wrappers around xcrun, which requires a
+      # full CommandLineTools or Xcode install, and still may not choose the
+      # appropriate binary if there are multiple installs.
+      otool = mac_bin_path + "otool"
+      nm = mac_bin_path + "nm"
+
+      does_reexport_command = "[ ! -e \"$dylib\" -o ! -e \"$tocname\" ] || $otool -l \"$dylib\" | grep -q LC_REEXPORT_DYLIB"
+
+      link_command = "$linker_driver $ld -shared "
+      if (is_component_build) {
+        link_command += " -Wl,-install_name,@rpath/\"{{target_output_name}}{{output_extension}}\" "
+      }
+      link_command += dsym_switch
+      link_command += "{{ldflags}} -o \"$dylib\" -Wl,-filelist,\"$rspfile\" {{frameworks}} {{swiftmodules}} {{solibs}} {{libs}}"
+
+      replace_command = "if ! cmp -s \"$temporary_tocname\" \"$tocname\"; then mv \"$temporary_tocname\" \"$tocname\""
+      extract_toc_command = "{ $otool -l \"$dylib\" | grep LC_ID_DYLIB -A 5; $nm -gPp \"$dylib\" | cut -f1-2 -d' ' | grep -v U\$\$; true; }"
+
+      command = "if $does_reexport_command ; then $link_command && $extract_toc_command > \"$tocname\"; else $link_command && $extract_toc_command > \"$temporary_tocname\" && $replace_command ; fi; fi"
+
+      rspfile_content = "{{inputs_newline}}"
+
+      description = "SOLINK {{output}}"
+
+      # Use this for {{output_extension}} expansions unless a target manually
+      # overrides it (in which case {{output_extension}} will be what the target
+      # specifies).
+      default_output_dir = "{{root_out_dir}}"
+      default_output_extension = ".dylib"
+
+      output_prefix = "lib"
+
+      # Since the above commands only updates the .TOC file when it changes, ask
+      # Ninja to check if the timestamp actually changed to know if downstream
+      # dependencies should be recompiled.
+      restat = true
+
+      # Tell GN about the output files. It will link to the dylib but use the
+      # tocname for dependency management.
+      outputs = [
+        dylib,
+        tocname,
+      ]
+      link_output = dylib
+      depend_output = tocname
+
+      if (_enable_dsyms) {
+        outputs += dsym_output
+      }
+      if (_save_unstripped_output) {
+        outputs += [ _unstripped_output ]
+      }
+    }
+
+    tool("solink_module") {
+      # E.g. "./libfoo.so":
+      sofile = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
+      rspfile = sofile + ".rsp"
+      pool = "//build/toolchain:link_pool($default_toolchain)"
+
+      link_command = "$linker_driver $ld -bundle {{ldflags}} -o \"$sofile\" -Wl,-filelist,\"$rspfile\""
+      if (is_component_build) {
+        link_command += " -Wl,-install_name,@rpath/{{target_output_name}}{{output_extension}}"
+      }
+      link_command += dsym_switch
+      link_command += " {{frameworks}} {{swiftmodules}} {{solibs}} {{libs}}"
+      command = link_command
+
+      rspfile_content = "{{inputs_newline}}"
+
+      description = "SOLINK_MODULE {{output}}"
+
+      # Use this for {{output_extension}} expansions unless a target manually
+      # overrides it (in which case {{output_extension}} will be what the target
+      # specifies).
+      default_output_dir = "{{root_out_dir}}"
+      default_output_extension = ".so"
+
+      outputs = [ sofile ]
+
+      if (_enable_dsyms) {
+        outputs += dsym_output
+      }
+      if (_save_unstripped_output) {
+        outputs += [ _unstripped_output ]
+      }
+    }
+
+    tool("link") {
+      outfile = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
+      rspfile = "$outfile.rsp"
+      pool = "//build/toolchain:link_pool($default_toolchain)"
+
+      # Note about -filelist: Apple's linker reads the file list file and
+      # interprets each newline-separated chunk of text as a file name. It
+      # doesn't do the things one would expect from the shell like unescaping
+      # or handling quotes. In contrast, when Ninja finds a file name with
+      # spaces, it single-quotes them in $inputs_newline as it would normally
+      # do for command-line arguments. Thus any source names with spaces, or
+      # label names with spaces (which GN bases the output paths on) will be
+      # corrupted by this process. Don't use spaces for source files or labels.
+      command = "$linker_driver $ld $dsym_switch {{ldflags}} -o \"$outfile\" -Wl,-filelist,\"$rspfile\" {{frameworks}} {{swiftmodules}} {{solibs}} {{libs}}"
+      description = "LINK $outfile"
+      rspfile_content = "{{inputs_newline}}"
+      outputs = [ outfile ]
+
+      if (_enable_dsyms) {
+        outputs += dsym_output
+      }
+      if (_save_unstripped_output) {
+        outputs += [ _unstripped_output ]
+      }
+
+      default_output_dir = "{{root_out_dir}}"
+    }
+
+    # These two are really entirely generic, but have to be repeated in
+    # each toolchain because GN doesn't allow a template to be used here.
+    # See //build/toolchain/toolchain.gni for details.
+    tool("stamp") {
+      command = stamp_command
+      description = stamp_description
+    }
+    tool("copy") {
+      command = copy_command
+      description = copy_description
+    }
+
+    tool("copy_bundle_data") {
+      # copy_command use hardlink if possible but this does not work with
+      # directories. Also when running EG2 tests from Xcode, Xcode tries to
+      # copy some files into the application bundle which fails if source
+      # and destination are hardlinked together.
+      #
+      # Instead use clonefile to copy the files which is as efficient as
+      # hardlink but ensure the file have distinct metadata (thus avoid the
+      # error with ditto, see https://crbug.com/1042182).
+      if (host_os == "mac") {
+        command = "rm -rf {{output}} && cp -Rc {{source}} {{output}}"
+      } else {
+        command = "rm -rf {{output}} && cp -Rl {{source}} {{output}}"
+      }
+      description = "COPY_BUNDLE_DATA {{source}} {{output}}"
+      pool = "//build/toolchain/apple:bundle_pool($default_toolchain)"
+    }
+
+    # Swift is only used on iOS, not macOS. We want to minimize the number
+    # of Xcode-based tools used by the macOS toolchain, so we intentionally
+    # disallow future uses of Swift on macOS. https://crbug.com/965663.
+    if (toolchain_args.current_os == "ios") {
+      tool("swift") {
+        _tool = rebase_path("//build/toolchain/ios/swiftc.py", root_build_dir)
+
+        depfile = "{{target_out_dir}}/{{module_name}}.d"
+        depsformat = "gcc"
+
+        outputs = [
+          # The module needs to be the first output listed. The blank line after
+          # the module is required to prevent `gn format` from changing the file
+          # order.
+          "{{target_gen_dir}}/{{module_name}}.swiftmodule",
+
+          "{{target_gen_dir}}/{{module_name}}.h",
+          "{{target_gen_dir}}/{{module_name}}.swiftdoc",
+          "{{target_gen_dir}}/{{module_name}}.swiftsourceinfo",
+        ]
+
+        if (swift_whole_module_optimization) {
+          _extra_flags = "-whole-module-optimization"
+          _objects_dir = "{{target_out_dir}}"
+
+          outputs += [ "$_objects_dir/{{module_name}}.o" ]
+        } else {
+          _extra_flags = ""
+          _objects_dir = "{{target_out_dir}}/{{label_name}}"
+
+          partial_outputs = [ "$_objects_dir/{{source_name_part}}.o" ]
+        }
+
+        _env_vars = "TOOL_VERSION=${tool_versions.swiftc}"
+        if (is_ios && ios_sdk_developer_dir != "") {
+          _env_vars += " DEVELOPER_DIR=$ios_sdk_developer_dir"
+        }
+
+        command =
+            "$_env_vars $_tool -module-name {{module_name}} " +
+            "-object-dir $_objects_dir " +
+            "-module-path {{target_gen_dir}}/{{module_name}}.swiftmodule " +
+            "-header-path {{target_gen_dir}}/{{module_name}}.h " +
+            "-depfile {{target_out_dir}}/{{module_name}}.d " +
+            "-depfile-filter {{target_gen_dir}}/{{module_name}}.swiftmodule " +
+            "-bridge-header {{bridge_header}} $_extra_flags " +
+            "{{swiftflags}} {{include_dirs}} {{module_dirs}} {{inputs}}"
+      }
+    }
+
+    # xcassets are only used on iOS, not macOS. We want to minimize the number
+    # of Xcode-based tools used by the macOS toolchain, so we intentionally
+    # disallow future uses of xcassets on macOS. https://crbug.com/965663.
+    if (toolchain_args.current_os == "ios") {
+      tool("compile_xcassets") {
+        _tool = rebase_path("//build/toolchain/ios/compile_xcassets.py",
+                            root_build_dir)
+        if (is_ios) {
+          _sdk_name = ios_sdk_name
+          _min_deployment_target = ios_deployment_target
+          _compress_pngs = ""
+        } else {
+          _sdk_name = mac_sdk_name
+          _min_deployment_target = mac_deployment_target
+          _compress_pngs = " -c "
+        }
+        command =
+            "rm -f \"{{output}}\" && " +
+            "TOOL_VERSION=${tool_versions.compile_xcassets} " +
+            "$python_path $_tool$_compress_pngs -p \"$_sdk_name\" " +
+            "-t \"$_min_deployment_target\" -T \"{{bundle_product_type}}\" " +
+            "-P \"{{bundle_partial_info_plist}}\" -o {{output}} {{inputs}}"
+
+        description = "COMPILE_XCASSETS {{output}}"
+        pool = "//build/toolchain/apple:bundle_pool($default_toolchain)"
+      }
+    }
+
+    tool("action") {
+      pool = "//build/toolchain:action_pool($default_toolchain)"
+    }
+  }
+}
diff --git a/build/toolchain/ios/BUILD.gn b/build/toolchain/ios/BUILD.gn
new file mode 100644
index 0000000..581e9e65
--- /dev/null
+++ b/build/toolchain/ios/BUILD.gn
@@ -0,0 +1,67 @@
+# Copyright 2021 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("//build/toolchain/apple/toolchain.gni")
+
+apple_toolchain("ios_clang_arm64") {
+  toolchain_args = {
+    current_cpu = "arm64"
+    current_os = "ios"
+  }
+}
+
+apple_toolchain("ios_clang_arm64_14_0") {
+  toolchain_args = {
+    current_cpu = "arm64"
+    current_os = "ios"
+    ios_deployment_target = "14.0"
+  }
+}
+
+apple_toolchain("ios_clang_arm") {
+  toolchain_args = {
+    current_cpu = "arm"
+    current_os = "ios"
+  }
+}
+
+apple_toolchain("ios_clang_arm_fat") {
+  toolchain_args = {
+    current_cpu = "arm"
+    current_os = "ios"
+    is_fat_secondary_toolchain = true
+    primary_fat_toolchain_name = "//build/toolchain/ios:ios_clang_arm64"
+  }
+}
+
+apple_toolchain("ios_clang_x64") {
+  toolchain_args = {
+    current_cpu = "x64"
+    current_os = "ios"
+  }
+}
+
+apple_toolchain("ios_clang_x64_14_0") {
+  toolchain_args = {
+    current_cpu = "x64"
+    current_os = "ios"
+    ios_deployment_target = "14.0"
+  }
+}
+
+apple_toolchain("ios_clang_x86") {
+  toolchain_args = {
+    current_cpu = "x86"
+    current_os = "ios"
+  }
+}
+
+apple_toolchain("ios_clang_x86_fat") {
+  toolchain_args = {
+    current_cpu = "x86"
+    current_os = "ios"
+    is_fat_secondary_toolchain = true
+    primary_fat_toolchain_name = "//build/toolchain/ios:ios_clang_x64"
+  }
+}
diff --git a/build/toolchain/ios/OWNERS b/build/toolchain/ios/OWNERS
new file mode 100644
index 0000000..6f3324f
--- /dev/null
+++ b/build/toolchain/ios/OWNERS
@@ -0,0 +1 @@
+file://build/apple/OWNERS
diff --git a/build/config/ios/compile_xcassets.py b/build/toolchain/ios/compile_xcassets.py
similarity index 77%
rename from build/config/ios/compile_xcassets.py
rename to build/toolchain/ios/compile_xcassets.py
index 5ed43e8b..e160665 100644
--- a/build/config/ios/compile_xcassets.py
+++ b/build/toolchain/ios/compile_xcassets.py
@@ -8,7 +8,6 @@
 import subprocess
 import sys
 import tempfile
-
 """Wrapper around actool to compile assets catalog.
 
 The script compile_xcassets.py is a wrapper around actool to compile
@@ -40,16 +39,17 @@
 
         # crbug.com/770634, likely a bug in Xcode 9.2 beta, remove once build
         # requires a version of Xcode with a fix.
-        r'\[\]\[ipad\]\[76x76\]\[\]\[\]\[1x\]\[\]\[\]: notice: 76x76@1x app icons'
-        ' only apply to iPad apps targeting releases of iOS prior to 10.0.',
+        r'\[\]\[ipad\]\[76x76\]\[\]\[\]\[1x\]\[\]\[\]: notice: 76x76@1x app'
+        ' icons only apply to iPad apps targeting releases of iOS prior to'
+        ' 10.0.',
     ]
 ]
 
 # Map special type of asset catalog to the corresponding command-line
 # parameter that need to be passed to actool.
 ACTOOL_FLAG_FOR_ASSET_TYPE = {
-  '.appiconset': '--app-icon',
-  '.launchimage': '--launch-image',
+    '.appiconset': '--app-icon',
+    '.launchimage': '--launch-image',
 }
 
 
@@ -115,7 +115,7 @@
 
 
 def CompileAssetCatalog(output, platform, product_type, min_deployment_target,
-    inputs, compress_pngs, partial_info_plist):
+                        inputs, compress_pngs, partial_info_plist):
   """Compile the .xcassets bundles to an asset catalog using actool.
 
   Args:
@@ -128,9 +128,16 @@
     partial_info_plist: path to partial Info.plist to generate
   """
   command = [
-      'xcrun', 'actool', '--output-format=human-readable-text',
-      '--notices', '--warnings', '--errors', '--platform', platform,
-      '--minimum-deployment-target', min_deployment_target,
+      'xcrun',
+      'actool',
+      '--output-format=human-readable-text',
+      '--notices',
+      '--warnings',
+      '--errors',
+      '--platform',
+      platform,
+      '--minimum-deployment-target',
+      min_deployment_target,
   ]
 
   if compress_pngs:
@@ -190,8 +197,9 @@
   try:
     # Run actool and redirect stdout and stderr to the same pipe (as actool
     # is confused about what should go to stderr/stdout).
-    process = subprocess.Popen(
-        command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+    process = subprocess.Popen(command,
+                               stdout=subprocess.PIPE,
+                               stderr=subprocess.STDOUT)
     stdout, _ = process.communicate()
 
     # Filter the output to remove all garbarge and to fix the paths.
@@ -209,44 +217,44 @@
 def Main():
   parser = argparse.ArgumentParser(
       description='compile assets catalog for a bundle')
+  parser.add_argument('--platform',
+                      '-p',
+                      required=True,
+                      choices=('macosx', 'iphoneos', 'iphonesimulator'),
+                      help='target platform for the compiled assets catalog')
   parser.add_argument(
-      '--platform', '-p', required=True,
-      choices=('macosx', 'iphoneos', 'iphonesimulator'),
-      help='target platform for the compiled assets catalog')
-  parser.add_argument(
-      '--minimum-deployment-target', '-t', required=True,
+      '--minimum-deployment-target',
+      '-t',
+      required=True,
       help='minimum deployment target for the compiled assets catalog')
-  parser.add_argument(
-      '--output', '-o', required=True,
-      help='path to the compiled assets catalog')
-  parser.add_argument(
-      '--compress-pngs', '-c', action='store_true', default=False,
-      help='recompress PNGs while compiling assets catalog')
-  parser.add_argument(
-      '--product-type', '-T',
-      help='type of the containing bundle')
-  parser.add_argument(
-      '--partial-info-plist', '-P',
-      help='path to partial info plist to create')
-  parser.add_argument(
-      'inputs', nargs='+',
-      help='path to input assets catalog sources')
+  parser.add_argument('--output',
+                      '-o',
+                      required=True,
+                      help='path to the compiled assets catalog')
+  parser.add_argument('--compress-pngs',
+                      '-c',
+                      action='store_true',
+                      default=False,
+                      help='recompress PNGs while compiling assets catalog')
+  parser.add_argument('--product-type',
+                      '-T',
+                      help='type of the containing bundle')
+  parser.add_argument('--partial-info-plist',
+                      '-P',
+                      help='path to partial info plist to create')
+  parser.add_argument('inputs',
+                      nargs='+',
+                      help='path to input assets catalog sources')
   args = parser.parse_args()
 
   if os.path.basename(args.output) != 'Assets.car':
-    sys.stderr.write(
-        'output should be path to compiled asset catalog, not '
-        'to the containing bundle: %s\n' % (args.output,))
+    sys.stderr.write('output should be path to compiled asset catalog, not '
+                     'to the containing bundle: %s\n' % (args.output, ))
     sys.exit(1)
 
-  CompileAssetCatalog(
-      args.output,
-      args.platform,
-      args.product_type,
-      args.minimum_deployment_target,
-      args.inputs,
-      args.compress_pngs,
-      args.partial_info_plist)
+  CompileAssetCatalog(args.output, args.platform, args.product_type,
+                      args.minimum_deployment_target, args.inputs,
+                      args.compress_pngs, args.partial_info_plist)
 
 
 if __name__ == '__main__':
diff --git a/build/apple/swiftc.py b/build/toolchain/ios/swiftc.py
similarity index 100%
rename from build/apple/swiftc.py
rename to build/toolchain/ios/swiftc.py
diff --git a/build/toolchain/mac/BUILD.gn b/build/toolchain/mac/BUILD.gn
index 60e9de6..c228b00 100644
--- a/build/toolchain/mac/BUILD.gn
+++ b/build/toolchain/mac/BUILD.gn
@@ -1,563 +1,24 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Copyright 2021 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.
 
-# TODO(brettw) Use "gcc_toolchain.gni" like the Linux toolchains. This requires
-# some enhancements since the commands on Mac are slightly different than on
-# Linux.
+import("//build/toolchain/apple/toolchain.gni")
 
-import("//build/config/clang/clang.gni")
-import("//build/config/coverage/coverage.gni")
-import("../goma.gni")
-if (is_ios) {
-  import("//build/config/ios/ios_sdk.gni")
-}
-import("//build/config/apple/symbols.gni")
-import("//build/config/mac/mac_sdk.gni")
-
-assert((is_ios && host_os == "mac") || host_os != "win")
-
-import("//build/toolchain/cc_wrapper.gni")
-import("//build/toolchain/concurrent_links.gni")
-import("//build/toolchain/goma.gni")
-import("//build/toolchain/toolchain.gni")
-
-declare_args() {
-  # Reduce the number of tasks using the copy_bundle_data and compile_xcassets
-  # tools as they can cause lots of I/O contention when invoking ninja with a
-  # large number of parallel jobs (e.g. when using distributed build like goma).
-  bundle_pool_depth = -1
-
-  # This makes the linker set timestamps in Mach-O files to 0. This isn't
-  # enabled by default because this breaks Xcode's lldb. This has been fixed in
-  # https://reviews.llvm.org/rL368199 but that has not yet made it into a public
-  # lldb release.
-  mac_deterministic_build = false
-
-  # This controls whether whole module optimization is enabled when building
-  # Swift modules. If enabled, the compiler will compile the module as one
-  # unit, generating just one single object file. Otherwise, it will generate
-  # one object file per .swift file. If unspecified, will default to "true"
-  # for official builds, and "false" for all other builds.
-  swift_whole_module_optimization = -1
-}
-
-if (swift_whole_module_optimization == -1) {
-  swift_whole_module_optimization = is_official_build
-}
-
-if (current_toolchain == default_toolchain) {
-  pool("bundle_pool") {
-    if (bundle_pool_depth == -1) {
-      depth = concurrent_links
-    } else {
-      depth = bundle_pool_depth
-    }
-  }
-}
-
-# When implementing tools using Python scripts, a TOOL_VERSION=N env
-# variable is placed in front of the command. The N should be incremented
-# whenever the script is changed, so that the build system rebuilds all
-# edges that utilize the script. Ideally this should be changed to use
-# proper input-dirty checking, but that could be expensive. Instead, use a
-# script to get the tool scripts' modification time to use as the version.
-# This won't cause a re-generation of GN files when the tool script changes
-# but it will cause edges to be marked as dirty if the ninja files are
-# regenerated. See https://crbug.com/619083 for details. A proper fix
-# would be to have inputs to tools (https://crbug.com/621119).
-tool_versions =
-    exec_script("get_tool_mtime.py",
-                rebase_path([
-                              "//build/apple/swiftc.py",
-                              "//build/config/ios/compile_xcassets.py",
-                              "//build/toolchain/mac/filter_libtool.py",
-                              "//build/toolchain/apple/linker_driver.py",
-                            ],
-                            root_build_dir),
-                "trim scope")
-
-# Shared toolchain definition. Invocations should set current_os to set the
-# build args in this definition.
-template("mac_toolchain") {
-  toolchain(target_name) {
-    # When invoking this toolchain not as the default one, these args will be
-    # passed to the build. They are ignored when this is the default toolchain.
-    assert(defined(invoker.toolchain_args),
-           "Toolchains must declare toolchain_args")
-    toolchain_args = {
-      # Populate toolchain args from the invoker.
-      forward_variables_from(invoker.toolchain_args, "*")
-
-      # The host toolchain value computed by the default toolchain's setup
-      # needs to be passed through unchanged to all secondary toolchains to
-      # ensure that it's always the same, regardless of the values that may be
-      # set on those toolchains.
-      host_toolchain = host_toolchain
-    }
-
-    # Supports building with the version of clang shipped with Xcode when
-    # targeting iOS by not respecting clang_base_path.
-    if (toolchain_args.current_os == "ios" && use_xcode_clang) {
-      prefix = ""
-    } else {
-      prefix = rebase_path("$clang_base_path/bin/", root_build_dir)
-    }
-
-    _cc = "${prefix}clang"
-    _cxx = "${prefix}clang++"
-
-    swiftmodule_switch = "-Wl,-add_ast_path,"
-
-    # When the invoker has explicitly overridden use_goma or cc_wrapper in the
-    # toolchain args, use those values, otherwise default to the global one.
-    # This works because the only reasonable override that toolchains might
-    # supply for these values are to force-disable them.
-    if (defined(toolchain_args.use_goma)) {
-      toolchain_uses_goma = toolchain_args.use_goma
-    } else {
-      toolchain_uses_goma = use_goma
-    }
-    if (defined(toolchain_args.cc_wrapper)) {
-      toolchain_cc_wrapper = toolchain_args.cc_wrapper
-    } else {
-      toolchain_cc_wrapper = cc_wrapper
-    }
-
-    # Compute the compiler prefix.
-    if (toolchain_uses_goma) {
-      assert(toolchain_cc_wrapper == "",
-             "Goma and cc_wrapper can't be used together.")
-      compiler_prefix = "$goma_dir/gomacc "
-    } else if (toolchain_cc_wrapper != "") {
-      compiler_prefix = toolchain_cc_wrapper + " "
-    } else {
-      compiler_prefix = ""
-    }
-
-    cc = compiler_prefix + _cc
-    cxx = compiler_prefix + _cxx
-    ld = _cxx
-
-    # Set the explicit search path for clang++ so it uses the right linker
-    # binary.
-    ld += " -B " + mac_bin_path
-
-    if (defined(toolchain_args.coverage_instrumentation_input_file)) {
-      toolchain_coverage_instrumentation_input_file =
-          toolchain_args.coverage_instrumentation_input_file
-    } else {
-      toolchain_coverage_instrumentation_input_file =
-          coverage_instrumentation_input_file
-    }
-    _use_clang_coverage_wrapper =
-        toolchain_coverage_instrumentation_input_file != ""
-    if (_use_clang_coverage_wrapper) {
-      _coverage_wrapper =
-          rebase_path("//build/toolchain/clang_code_coverage_wrapper.py",
-                      root_build_dir) + " --files-to-instrument=" +
-          rebase_path(toolchain_coverage_instrumentation_input_file,
-                      root_build_dir) + " --target-os=" + target_os
-      cc = "$python_path $_coverage_wrapper ${cc}"
-      cxx = "$python_path $_coverage_wrapper ${cxx}"
-    }
-
-    linker_driver =
-        "TOOL_VERSION=${tool_versions.linker_driver} " +
-        rebase_path("//build/toolchain/apple/linker_driver.py", root_build_dir)
-
-    # Specify an explicit path for the strip binary.
-    _strippath = mac_bin_path + "strip"
-    linker_driver += " -Wcrl,strippath," + _strippath
-
-    if (mac_deterministic_build) {
-      linker_driver += " --deterministic"
-    }
-
-    # On iOS, the final applications are assembled using lipo (to support fat
-    # builds). The correct flags are passed to the linker_driver.py script
-    # directly during the lipo call. The test is against the target_os because
-    # there is no need to create .dSYMs for targets compiled for the host.
-    if (target_os != "ios") {
-      _enable_dsyms = enable_dsyms
-      _save_unstripped_output = save_unstripped_output
-    } else {
-      _enable_dsyms = false
-      _save_unstripped_output = false
-    }
-
-    # Make these apply to all tools below.
-    lib_switch = "-l"
-    lib_dir_switch = "-L"
-
-    # Object files go in this directory. Use label_name instead of
-    # target_output_name since labels will generally have no spaces and will be
-    # unique in the directory.
-    object_subdir = "{{target_out_dir}}/{{label_name}}"
-
-    # If dSYMs are enabled, this flag will be added to the link tools.
-    if (_enable_dsyms) {
-      dsym_switch = " -Wcrl,dsym,{{root_out_dir}} "
-      dsym_switch += "-Wcrl,dsymutilpath," +
-                     rebase_path("//tools/clang/dsymutil/bin/dsymutil",
-                                 root_build_dir) + " "
-
-      dsym_output_dir =
-          "{{root_out_dir}}/{{target_output_name}}{{output_extension}}.dSYM"
-      dsym_output = [
-        "$dsym_output_dir/Contents/Info.plist",
-        "$dsym_output_dir/Contents/Resources/DWARF/" +
-            "{{target_output_name}}{{output_extension}}",
-      ]
-    } else {
-      dsym_switch = ""
-    }
-
-    if (_save_unstripped_output) {
-      _unstripped_output = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}.unstripped"
-    }
-
-    tool("cc") {
-      depfile = "{{output}}.d"
-      precompiled_header_type = "gcc"
-      command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
-      depsformat = "gcc"
-      description = "CC {{output}}"
-      outputs = [ "$object_subdir/{{source_name_part}}.o" ]
-    }
-
-    tool("cxx") {
-      depfile = "{{output}}.d"
-      precompiled_header_type = "gcc"
-      command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}"
-      depsformat = "gcc"
-      description = "CXX {{output}}"
-      outputs = [ "$object_subdir/{{source_name_part}}.o" ]
-    }
-
-    tool("asm") {
-      # For GCC we can just use the C compiler to compile assembly.
-      depfile = "{{output}}.d"
-      command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}"
-      depsformat = "gcc"
-      description = "ASM {{output}}"
-      outputs = [ "$object_subdir/{{source_name_part}}.o" ]
-    }
-
-    tool("objc") {
-      depfile = "{{output}}.d"
-      precompiled_header_type = "gcc"
-      command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{framework_dirs}} {{cflags}} {{cflags_objc}} -c {{source}} -o {{output}}"
-      depsformat = "gcc"
-      description = "OBJC {{output}}"
-      outputs = [ "$object_subdir/{{source_name_part}}.o" ]
-    }
-
-    tool("objcxx") {
-      depfile = "{{output}}.d"
-      precompiled_header_type = "gcc"
-      command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{framework_dirs}} {{cflags}} {{cflags_objcc}} -c {{source}} -o {{output}}"
-      depsformat = "gcc"
-      description = "OBJCXX {{output}}"
-      outputs = [ "$object_subdir/{{source_name_part}}.o" ]
-    }
-
-    tool("alink") {
-      rspfile = "{{output}}.rsp"
-
-      if (!use_lld) {
-        # Note about -filelist: Apple's linker reads the file list file and
-        # interprets each newline-separated chunk of text as a file name. It
-        # doesn't do the things one would expect from the shell like unescaping
-        # or handling quotes. In contrast, when Ninja finds a file name with
-        # spaces, it single-quotes them in $inputs_newline as it would normally
-        # do for command-line arguments. Thus any source names with spaces, or
-        # label names with spaces (which GN bases the output paths on) will be
-        # corrupted by this process. Don't use spaces for source files or
-        # labels.
-        rspfile_content = "{{inputs_newline}}"
-
-        script = rebase_path("//build/toolchain/mac/filter_libtool.py",
-                             root_build_dir)
-
-        # Specify explicit path for libtool.
-        libtool = mac_bin_path + "libtool"
-        command = "rm -f {{output}} && TOOL_VERSION=${tool_versions.filter_libtool} $python_path $script $libtool -static -D {{arflags}} -o {{output}} -filelist $rspfile"
-        description = "LIBTOOL-STATIC {{output}}"
-      } else {
-        rspfile_content = "{{inputs}}"
-        ar = "${prefix}llvm-ar"
-        command = "\"$ar\" {{arflags}} -r -c -s -D {{output}} \"@$rspfile\""
-
-        # Remove the output file first so that ar doesn't try to modify the
-        # existing file.
-        command = "rm -f {{output}} && $command"
-        description = "AR {{output}}"
-      }
-      outputs = [ "{{output_dir}}/{{target_output_name}}{{output_extension}}" ]
-      default_output_dir = "{{target_out_dir}}"
-      default_output_extension = ".a"
-      output_prefix = "lib"
-    }
-
-    tool("solink") {
-      # E.g. "./libfoo.dylib":
-      dylib = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
-      rspfile = dylib + ".rsp"
-      pool = "//build/toolchain:link_pool($default_toolchain)"
-
-      # These variables are not built into GN but are helpers that implement
-      # (1) linking to produce a .dylib, (2) extracting the symbols from that
-      # file to a temporary file, (3) if the temporary file has differences from
-      # the existing .TOC file, overwrite it, otherwise, don't change it.
-      #
-      # As a special case, if the library reexports symbols from other dynamic
-      # libraries, we always update the .TOC and skip the temporary file and
-      # diffing steps, since that library always needs to be re-linked.
-      tocname = dylib + ".TOC"
-      temporary_tocname = dylib + ".tmp"
-
-      # Use explicit paths to binaries. The binaries present on the default
-      # search path in /usr/bin are thin wrappers around xcrun, which requires a
-      # full CommandLineTools or Xcode install, and still may not choose the
-      # appropriate binary if there are multiple installs.
-      otool = mac_bin_path + "otool"
-      nm = mac_bin_path + "nm"
-
-      does_reexport_command = "[ ! -e \"$dylib\" -o ! -e \"$tocname\" ] || $otool -l \"$dylib\" | grep -q LC_REEXPORT_DYLIB"
-
-      link_command = "$linker_driver $ld -shared "
-      if (is_component_build) {
-        link_command += " -Wl,-install_name,@rpath/\"{{target_output_name}}{{output_extension}}\" "
-      }
-      link_command += dsym_switch
-      link_command += "{{ldflags}} -o \"$dylib\" -Wl,-filelist,\"$rspfile\" {{frameworks}} {{swiftmodules}} {{solibs}} {{libs}}"
-
-      replace_command = "if ! cmp -s \"$temporary_tocname\" \"$tocname\"; then mv \"$temporary_tocname\" \"$tocname\""
-      extract_toc_command = "{ $otool -l \"$dylib\" | grep LC_ID_DYLIB -A 5; $nm -gPp \"$dylib\" | cut -f1-2 -d' ' | grep -v U\$\$; true; }"
-
-      command = "if $does_reexport_command ; then $link_command && $extract_toc_command > \"$tocname\"; else $link_command && $extract_toc_command > \"$temporary_tocname\" && $replace_command ; fi; fi"
-
-      rspfile_content = "{{inputs_newline}}"
-
-      description = "SOLINK {{output}}"
-
-      # Use this for {{output_extension}} expansions unless a target manually
-      # overrides it (in which case {{output_extension}} will be what the target
-      # specifies).
-      default_output_dir = "{{root_out_dir}}"
-      default_output_extension = ".dylib"
-
-      output_prefix = "lib"
-
-      # Since the above commands only updates the .TOC file when it changes, ask
-      # Ninja to check if the timestamp actually changed to know if downstream
-      # dependencies should be recompiled.
-      restat = true
-
-      # Tell GN about the output files. It will link to the dylib but use the
-      # tocname for dependency management.
-      outputs = [
-        dylib,
-        tocname,
-      ]
-      link_output = dylib
-      depend_output = tocname
-
-      if (_enable_dsyms) {
-        outputs += dsym_output
-      }
-      if (_save_unstripped_output) {
-        outputs += [ _unstripped_output ]
-      }
-    }
-
-    tool("solink_module") {
-      # E.g. "./libfoo.so":
-      sofile = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
-      rspfile = sofile + ".rsp"
-      pool = "//build/toolchain:link_pool($default_toolchain)"
-
-      link_command = "$linker_driver $ld -bundle {{ldflags}} -o \"$sofile\" -Wl,-filelist,\"$rspfile\""
-      if (is_component_build) {
-        link_command += " -Wl,-install_name,@rpath/{{target_output_name}}{{output_extension}}"
-      }
-      link_command += dsym_switch
-      link_command += " {{frameworks}} {{swiftmodules}} {{solibs}} {{libs}}"
-      command = link_command
-
-      rspfile_content = "{{inputs_newline}}"
-
-      description = "SOLINK_MODULE {{output}}"
-
-      # Use this for {{output_extension}} expansions unless a target manually
-      # overrides it (in which case {{output_extension}} will be what the target
-      # specifies).
-      default_output_dir = "{{root_out_dir}}"
-      default_output_extension = ".so"
-
-      outputs = [ sofile ]
-
-      if (_enable_dsyms) {
-        outputs += dsym_output
-      }
-      if (_save_unstripped_output) {
-        outputs += [ _unstripped_output ]
-      }
-    }
-
-    tool("link") {
-      outfile = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
-      rspfile = "$outfile.rsp"
-      pool = "//build/toolchain:link_pool($default_toolchain)"
-
-      # Note about -filelist: Apple's linker reads the file list file and
-      # interprets each newline-separated chunk of text as a file name. It
-      # doesn't do the things one would expect from the shell like unescaping
-      # or handling quotes. In contrast, when Ninja finds a file name with
-      # spaces, it single-quotes them in $inputs_newline as it would normally
-      # do for command-line arguments. Thus any source names with spaces, or
-      # label names with spaces (which GN bases the output paths on) will be
-      # corrupted by this process. Don't use spaces for source files or labels.
-      command = "$linker_driver $ld $dsym_switch {{ldflags}} -o \"$outfile\" -Wl,-filelist,\"$rspfile\" {{frameworks}} {{swiftmodules}} {{solibs}} {{libs}}"
-      description = "LINK $outfile"
-      rspfile_content = "{{inputs_newline}}"
-      outputs = [ outfile ]
-
-      if (_enable_dsyms) {
-        outputs += dsym_output
-      }
-      if (_save_unstripped_output) {
-        outputs += [ _unstripped_output ]
-      }
-
-      default_output_dir = "{{root_out_dir}}"
-    }
-
-    # These two are really entirely generic, but have to be repeated in
-    # each toolchain because GN doesn't allow a template to be used here.
-    # See //build/toolchain/toolchain.gni for details.
-    tool("stamp") {
-      command = stamp_command
-      description = stamp_description
-    }
-    tool("copy") {
-      command = copy_command
-      description = copy_description
-    }
-
-    tool("copy_bundle_data") {
-      # copy_command use hardlink if possible but this does not work with
-      # directories. Also when running EG2 tests from Xcode, Xcode tries to
-      # copy some files into the application bundle which fails if source
-      # and destination are hardlinked together.
-      #
-      # Instead use clonefile to copy the files which is as efficient as
-      # hardlink but ensure the file have distinct metadata (thus avoid the
-      # error with ditto, see https://crbug.com/1042182).
-      if (host_os == "mac") {
-        command = "rm -rf {{output}} && cp -Rc {{source}} {{output}}"
-      } else {
-        command = "rm -rf {{output}} && cp -Rl {{source}} {{output}}"
-      }
-      description = "COPY_BUNDLE_DATA {{source}} {{output}}"
-      pool = ":bundle_pool($default_toolchain)"
-    }
-
-    tool("swift") {
-      _tool = rebase_path("//build/apple/swiftc.py", root_build_dir)
-
-      depfile = "{{target_out_dir}}/{{module_name}}.d"
-      depsformat = "gcc"
-
-      outputs = [
-        # The module needs to be the first output listed. The blank line after
-        # the module is required to prevent `gn format` from changing the file
-        # order.
-        "{{target_gen_dir}}/{{module_name}}.swiftmodule",
-
-        "{{target_gen_dir}}/{{module_name}}.h",
-        "{{target_gen_dir}}/{{module_name}}.swiftdoc",
-        "{{target_gen_dir}}/{{module_name}}.swiftsourceinfo",
-      ]
-
-      if (swift_whole_module_optimization) {
-        _extra_flags = "-whole-module-optimization"
-        _objects_dir = "{{target_out_dir}}"
-
-        outputs += [ "$_objects_dir/{{module_name}}.o" ]
-      } else {
-        _extra_flags = ""
-        _objects_dir = "{{target_out_dir}}/{{label_name}}"
-
-        partial_outputs = [ "$_objects_dir/{{source_name_part}}.o" ]
-      }
-
-      _env_vars = "TOOL_VERSION=${tool_versions.swiftc}"
-      if (is_ios && ios_sdk_developer_dir != "") {
-        _env_vars += " DEVELOPER_DIR=$ios_sdk_developer_dir"
-      }
-
-      command =
-          "$_env_vars $_tool -module-name {{module_name}} " +
-          "-object-dir $_objects_dir " +
-          "-module-path {{target_gen_dir}}/{{module_name}}.swiftmodule " +
-          "-header-path {{target_gen_dir}}/{{module_name}}.h " +
-          "-depfile {{target_out_dir}}/{{module_name}}.d " +
-          "-depfile-filter {{target_gen_dir}}/{{module_name}}.swiftmodule " +
-          "-bridge-header {{bridge_header}} $_extra_flags " +
-          "{{swiftflags}} {{include_dirs}} {{module_dirs}} {{inputs}}"
-    }
-
-    # xcassets are only used on iOS, not macOS. We want to minimize the number
-    # of Xcode-based tools used by the macOS toolchain, so we intentionally
-    # disallow future uses of xcassets on macOS. https://crbug.com/965663.
-    if (toolchain_args.current_os == "ios") {
-      tool("compile_xcassets") {
-        _tool = rebase_path("//build/config/ios/compile_xcassets.py",
-                            root_build_dir)
-        if (is_ios) {
-          _sdk_name = ios_sdk_name
-          _min_deployment_target = ios_deployment_target
-          _compress_pngs = ""
-        } else {
-          _sdk_name = mac_sdk_name
-          _min_deployment_target = mac_deployment_target
-          _compress_pngs = " -c "
-        }
-        command =
-            "rm -f \"{{output}}\" && " +
-            "TOOL_VERSION=${tool_versions.compile_xcassets} " +
-            "$python_path $_tool$_compress_pngs -p \"$_sdk_name\" " +
-            "-t \"$_min_deployment_target\" -T \"{{bundle_product_type}}\" " +
-            "-P \"{{bundle_partial_info_plist}}\" -o {{output}} {{inputs}}"
-
-        description = "COMPILE_XCASSETS {{output}}"
-        pool = ":bundle_pool($default_toolchain)"
-      }
-    }
-
-    tool("action") {
-      pool = "//build/toolchain:action_pool($default_toolchain)"
-    }
-  }
-}
-
-mac_toolchain("clang_arm") {
+apple_toolchain("clang_arm") {
   toolchain_args = {
     current_cpu = "arm"
     current_os = "mac"
   }
 }
 
-mac_toolchain("clang_arm64") {
+apple_toolchain("clang_arm64") {
   toolchain_args = {
     current_cpu = "arm64"
     current_os = "mac"
   }
 }
 
-mac_toolchain("clang_x64") {
+apple_toolchain("clang_x64") {
   toolchain_args = {
     current_cpu = "x64"
     current_os = "mac"
@@ -571,14 +32,14 @@
   }
 }
 
-mac_toolchain("clang_x86") {
+apple_toolchain("clang_x86") {
   toolchain_args = {
     current_cpu = "x86"
     current_os = "mac"
   }
 }
 
-mac_toolchain("clang_x86_v8_arm") {
+apple_toolchain("clang_x86_v8_arm") {
   toolchain_args = {
     current_cpu = "x86"
     current_os = "mac"
@@ -589,7 +50,7 @@
   }
 }
 
-mac_toolchain("clang_x86_v8_mipsel") {
+apple_toolchain("clang_x86_v8_mipsel") {
   toolchain_args = {
     current_cpu = "x86"
     current_os = "mac"
@@ -600,7 +61,7 @@
   }
 }
 
-mac_toolchain("clang_x64_v8_arm64") {
+apple_toolchain("clang_x64_v8_arm64") {
   toolchain_args = {
     current_cpu = "x64"
     current_os = "mac"
@@ -611,7 +72,7 @@
   }
 }
 
-mac_toolchain("clang_x64_v8_mips64el") {
+apple_toolchain("clang_x64_v8_mips64el") {
   toolchain_args = {
     current_cpu = "x64"
     current_os = "mac"
@@ -621,67 +82,3 @@
     }
   }
 }
-
-if (is_ios) {
-  mac_toolchain("ios_clang_arm64") {
-    toolchain_args = {
-      current_cpu = "arm64"
-      current_os = "ios"
-    }
-  }
-
-  mac_toolchain("ios_clang_arm64_14_0") {
-    toolchain_args = {
-      current_cpu = "arm64"
-      current_os = "ios"
-      ios_deployment_target = "14.0"
-    }
-  }
-
-  mac_toolchain("ios_clang_arm") {
-    toolchain_args = {
-      current_cpu = "arm"
-      current_os = "ios"
-    }
-  }
-
-  mac_toolchain("ios_clang_arm_fat") {
-    toolchain_args = {
-      current_cpu = "arm"
-      current_os = "ios"
-      is_fat_secondary_toolchain = true
-      primary_fat_toolchain_name = "//build/toolchain/mac:ios_clang_arm64"
-    }
-  }
-
-  mac_toolchain("ios_clang_x64") {
-    toolchain_args = {
-      current_cpu = "x64"
-      current_os = "ios"
-    }
-  }
-
-  mac_toolchain("ios_clang_x64_14_0") {
-    toolchain_args = {
-      current_cpu = "x64"
-      current_os = "ios"
-      ios_deployment_target = "14.0"
-    }
-  }
-
-  mac_toolchain("ios_clang_x86") {
-    toolchain_args = {
-      current_cpu = "x86"
-      current_os = "ios"
-    }
-  }
-
-  mac_toolchain("ios_clang_x86_fat") {
-    toolchain_args = {
-      current_cpu = "x86"
-      current_os = "ios"
-      is_fat_secondary_toolchain = true
-      primary_fat_toolchain_name = "//build/toolchain/mac:ios_clang_x64"
-    }
-  }
-}
diff --git a/build_overrides/build.gni b/build_overrides/build.gni
index d4268477..cc1e39f 100644
--- a/build_overrides/build.gni
+++ b/build_overrides/build.gni
@@ -50,27 +50,37 @@
   # due to 4GiB file size limit, see https://crbug.com/648948.
   # Set this flag to true to skip the assertion.
   ignore_elf32_limitations = false
-
-  # Use the system install of Xcode for tools like ibtool, libtool, etc.
-  # This does not affect the compiler. When this variable is false, targets will
-  # instead use a hermetic install of Xcode. [The hermetic install can be
-  # obtained with gclient sync after setting the environment variable
-  # FORCE_MAC_TOOLCHAIN for target_os mac only].
-  use_system_xcode = ""
 }
 
-if (is_apple && use_system_xcode == "") {
-  _result = exec_script("//build/mac/should_use_hermetic_xcode.py",
-                        [ target_os ],
-                        "value")
+if (host_os == "mac" || is_apple) {
+  # Needed for is_apple when targeting macOS or iOS, independent of host.
+  # Needed for host_os=="mac" for running host tool such as gperf in blink
+  # even when targeting e.g. Windows.
+  # TODO(thakis): See TODO in scripts.gni -- this should really only be needed
+  # if is_apple, independent of host_os.
+  declare_args() {
+    # Use the system install of Xcode for tools like ibtool, libtool, etc.
+    # This does not affect the compiler. When this variable is false, targets
+    # will instead use a hermetic install of Xcode. [The hermetic install can
+    # be obtained with gclient sync after setting the environment variable
+    # FORCE_MAC_TOOLCHAIN for target_os mac only].
+    use_system_xcode = ""
+  }
 
-  assert(_result != 2,
-         "Do not allow building targets with the default" +
-             "hermetic toolchain if the minimum OS version is not met.")
-  assert(_result != 3,
-         "iOS does not support building with a hermetic toolchain. " +
-             "Please install Xcode.")
+  if (use_system_xcode == "") {
+    _result = exec_script("//build/mac/should_use_hermetic_xcode.py",
+                          [ target_os ],
+                          "value")
 
-  use_system_xcode = _result != 1
+    assert(_result != 2,
+           "Do not allow building targets with the default" +
+               "hermetic toolchain if the minimum OS version is not met.")
+    assert(_result != 3,
+           "iOS does not support building with a hermetic toolchain. " +
+               "Please install Xcode.")
+
+    use_system_xcode = _result != 1
+  }
+  assert(host_os != "ios" || use_system_xcode)
   assert(host_os == "mac" || !use_system_xcode)
 }
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 6c513ce..ae5d38a2 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -98,8 +98,6 @@
     !is_java_debug && !enable_chrome_android_internal &&
     android_channel == "stable"
 
-_enable_flags_verification = target_cpu == "arm" && is_official_build
-
 jinja_template("chrome_public_android_manifest") {
   input = "java/AndroidManifest.xml"
   output = chrome_public_android_manifest
@@ -154,8 +152,8 @@
 
 # Resources which are needed in the base module manifest's application tag
 # should be added here. These are split out from chrome_app_java_resources
-# because //chrome resources may be included in a DFM instead of the base module
-# if the enable_chrome_module gn arg is true.
+# because //chrome resources may be included in a DFM instead of the base
+# module.
 android_resources("chrome_base_module_resources") {
   sources = [
     "java/res_base/anim/no_anim.xml",
@@ -178,6 +176,7 @@
 android_resources("chrome_app_java_resources") {
   sources = chrome_java_resources
   sources += [
+    "//chrome/android/java/res_app/layout/main.xml",
     "//chrome/android/java/res_chromium/drawable-hdpi/fre_product_logo.png",
     "//chrome/android/java/res_chromium/drawable-hdpi/product_logo_name.png",
     "//chrome/android/java/res_chromium/drawable-mdpi/fre_product_logo.png",
@@ -318,6 +317,7 @@
     "//chrome/browser/download/android:java",
     "//chrome/browser/download/android:java_resources",
     "//chrome/browser/enterprise/util:java",
+    "//chrome/browser/feature_engagement:java",
     "//chrome/browser/feed/android:java",
     "//chrome/browser/feedback/android:java",
     "//chrome/browser/flags:java",
@@ -702,6 +702,7 @@
     "//chrome/browser/contextmenu:jni_headers",
     "//chrome/browser/download/android:jni_headers",
     "//chrome/browser/enterprise/util:jni_headers",
+    "//chrome/browser/feature_engagement:jni_headers",
     "//chrome/browser/flags:jni_headers",
     "//chrome/browser/image_descriptions:jni_headers",
     "//chrome/browser/image_fetcher:jni_headers",
@@ -851,6 +852,7 @@
     "//chrome/browser/download/internal/android:junit",
     "//chrome/browser/endpoint_fetcher:java",
     "//chrome/browser/enterprise/util:java",
+    "//chrome/browser/feature_engagement:java",
     "//chrome/browser/feed/android:java",
     "//chrome/browser/feedback/android:java",
     "//chrome/browser/flags:flags_junit_tests",
@@ -1112,6 +1114,7 @@
     "//chrome/browser/download/internal/android:javatests",
     "//chrome/browser/endpoint_fetcher:java",
     "//chrome/browser/enterprise/util:java",
+    "//chrome/browser/feature_engagement:java",
     "//chrome/browser/feed/android:javatests",
     "//chrome/browser/feedback/android:java",
     "//chrome/browser/flags:java",
@@ -2215,8 +2218,8 @@
   }
 }
 
-# Target for classes which should be in the base module, even when
-# enable_chrome_module is true and //chrome code is in a DFM.
+# Target for classes which should be in the base module, even when //chrome code
+# is in a DFM.
 android_library("base_module_java") {
   sources = [
     "java/src/com/google/ipc/invalidation/ticl/android2/channel/GcmRegistrationTaskService.java",
@@ -2350,13 +2353,12 @@
       "$target_gen_dir/manifest/${target_name}/AndroidManifest_split.xml"
   _is_trichrome =
       defined(invoker.use_trichrome_library) && invoker.use_trichrome_library
-  _enable_chrome_module =
-      enable_chrome_module && invoker.target_type == "android_app_bundle_module"
+  _is_bundle = invoker.target_type == "android_app_bundle_module"
 
   # Generate the manifest here in the template, to avoid a growing collection
   # of manually-instantiated manifests.
   split_manifest_template("${target_name}__android_manifest") {
-    definitions_in_split = _enable_chrome_module
+    definitions_in_split = _is_bundle
     includes = [ "java/AndroidManifest.xml" ]
     split_input = "java/AndroidManifest_split.xml"
     split_output = _split_android_manifest
@@ -2440,7 +2442,7 @@
     }
 
     deps = []
-    if (_enable_chrome_module) {
+    if (_is_bundle) {
       deps += [ "//chrome/android:chrome_base_module_resources" ]
     } else {
       deps += [
@@ -2454,7 +2456,7 @@
         "//android_webview/nonembedded:icon_resources",
         "//android_webview/nonembedded:monochrome_devui_launcher_icon_resources",
       ]
-      if (!_enable_chrome_module) {
+      if (!_is_bundle) {
         deps += [ ":monochrome_java" ]
       }
       if (webview_includes_weblayer) {
@@ -3096,14 +3098,12 @@
     min_sdk_version = _min_sdk_version
     module_descs = _module_descs
     version_code = _version_code
-    if (enable_chrome_module) {
-      chrome_deps = [
-        "//chrome/android:app_hooks_java",
-        "//components/externalauth/android:google_delegate_public_impl_java",
-      ]
-      if (!_is_trichrome) {
-        chrome_deps += [ "//chrome/android:monochrome_java" ]
-      }
+    chrome_deps = [
+      "//chrome/android:app_hooks_java",
+      "//components/externalauth/android:google_delegate_public_impl_java",
+    ]
+    if (!_is_trichrome) {
+      chrome_deps += [ "//chrome/android:monochrome_java" ]
     }
 
     if (!is_java_debug) {
@@ -3386,7 +3386,6 @@
     "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategory.java",
     "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryTile.java",
     "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSite.java",
-    "java/src/org/chromium/chrome/browser/feature_engagement/TrackerFactory.java",
     "java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java",
     "java/src/org/chromium/chrome/browser/feedback/ScreenshotTask.java",
     "java/src/org/chromium/chrome/browser/firstrun/FirstRunUtils.java",
@@ -3546,8 +3545,7 @@
 }
 
 # Used by android-binary-size trybot to validate expectations.
-if (_enable_libs_and_assets_verification || _enable_manifest_verification ||
-    _enable_flags_verification) {
+if (_enable_libs_and_assets_verification || _enable_manifest_verification) {
   group("validate_expectations") {
     deps = []
     if (_enable_libs_and_assets_verification) {
@@ -3568,8 +3566,5 @@
         "//android_webview:trichrome_webview_base_bundle_module_validate_android_manifest",
       ]
     }
-    if (_enable_flags_verification) {
-      deps += [ "//chrome/android/expectations:native_flags_expectations" ]
-    }
   }
 }
diff --git a/chrome/android/chrome_java_resources.gni b/chrome/android/chrome_java_resources.gni
index e001557..0830596 100644
--- a/chrome/android/chrome_java_resources.gni
+++ b/chrome/android/chrome_java_resources.gni
@@ -784,7 +784,6 @@
   "java/res/layout/location_status_icon.xml",
   "java/res/layout/location_status_incognito_badge.xml",
   "java/res/layout/long_screenshots_area_selection_dialog.xml",
-  "java/res/layout/main.xml",
   "java/res/layout/manage_space_activity.xml",
   "java/res/layout/managed_by_menu_item.xml",
   "java/res/layout/material_tooltip.xml",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index be1ea34..2d0ead4 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -577,10 +577,6 @@
   "java/src/org/chromium/chrome/browser/explore_sites/StableScrollLayoutManager.java",
   "java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java",
   "java/src/org/chromium/chrome/browser/externalnav/IntentWithRequestMetadataHandler.java",
-  "java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotMonitor.java",
-  "java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotMonitorDelegate.java",
-  "java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotTabObserver.java",
-  "java/src/org/chromium/chrome/browser/feature_engagement/TrackerFactory.java",
   "java/src/org/chromium/chrome/browser/feedback/ChromeFeedbackCollector.java",
   "java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java",
   "java/src/org/chromium/chrome/browser/feedback/ConnectivityFeedbackSource.java",
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index 581eff9..9153f5f 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -73,8 +73,6 @@
   _is_64_bit_browser =
       defined(invoker.is_64_bit_browser) && invoker.is_64_bit_browser
   _is_bundle = invoker.target_type == "android_app_bundle_module"
-  _enable_chrome_module =
-      _is_bundle && enable_chrome_module && (_is_monochrome || _is_trichrome)
   not_needed([ "_is_64_bit_browser" ])
   assert(!(_is_monochrome && _is_trichrome),
          "Cannot be both trichrome and monochrome!")
@@ -265,10 +263,6 @@
         "//base/android/proguard/chromium_apk.flags",
         "//base/android/proguard/chromium_code.flags",
       ]
-      if (_enable_chrome_module) {
-        proguard_configs +=
-            [ "//chrome/android/proguard/isolated_splits.flags" ]
-      }
     }
 
     if (use_chromium_linker) {
@@ -303,7 +297,7 @@
       deps += [ ":$_unwind_asset_target" ]
     }
 
-    if (!_enable_chrome_module) {
+    if (!_is_bundle || !(_is_monochrome || _is_trichrome)) {
       deps += [ "//chrome/android:chrome_all_java" ]
     }
 
@@ -388,18 +382,11 @@
       }
 
       if (_is_bundle_module && invoker.is_base_module && enable_arcore) {
-        # AR DFM is disabled - bring in the ar_java target along with ARCore SDK
-        # and set the loadable_modules / secondary_abi_loadable_modules to what
-        # would be brought in by the module.
-        # This needs to happen for monochrome & trichrome builds of base module if ARCore is enabled.
-
-        if (!enable_chrome_module) {
-          deps += [
-            "//components/webxr/android:ar_java",
-            "//third_party/arcore-android-sdk-client:com_google_ar_core_java",
-          ]
-        }
-
+        # AR DFM is disabled - set the loadable_modules /
+        # secondary_abi_loadable_modules to what would be brought in by the
+        # module. The AR Java will be brought in by the chrome_bundle target.
+        # This needs to happen for monochrome & trichrome builds of base module
+        # if ARCore is enabled.
         _libarcore_dir = get_label_info(
                              "//third_party/arcore-android-sdk-client:com_google_ar_core_java($default_toolchain)",
                              "target_out_dir") + "/com_google_ar_core_java/jni"
@@ -418,15 +405,13 @@
         }
       }
 
-      if (_is_bundle_module && enable_isolated_splits) {
+      if (_is_bundle_module) {
         # Sets ISOLATED_SPLITS_ENABLED in BuildConfig.java.
         isolated_splits_enabled = true
         deps += [ ":${target_name}__all_dfm_resources" ]
       }
 
-      _enable_chrome_module =
-          _is_bundle_module && invoker.is_base_module && enable_chrome_module
-      if (_enable_chrome_module) {
+      if (_is_bundle_module && invoker.is_base_module) {
         # If the manifest is being verified, add the chrome module's manifest.
         if (defined(invoker.expected_android_manifest)) {
           _bundle_target_gen_dir =
@@ -496,7 +481,7 @@
           "//android_webview/glue:glue_java",
           "//android_webview/nonembedded:nonembedded_java",
         ]
-        if (!enable_chrome_module || !_is_bundle_module) {
+        if (!_is_bundle_module) {
           deps += [ "//chrome/android:monochrome_java" ]
         }
 
diff --git a/chrome/android/expectations/BUILD.gn b/chrome/android/expectations/BUILD.gn
deleted file mode 100644
index d0512f5..0000000
--- a/chrome/android/expectations/BUILD.gn
+++ /dev/null
@@ -1,66 +0,0 @@
-# Use of this source code is governed by a BSD-style license that can be
-# Copyright 2021 The Chromium Authors. All rights reserved.
-# found in the LICENSE file.
-
-import("//build/config/android/config.gni")
-import("//build/config/python.gni")
-
-_flagcapture_out_dir =
-    get_label_info("foo(//build/android/native_flags:flagcapture)",
-                   "root_out_dir")
-action_with_pydeps("native_cc_flags_expectations") {
-  script = "//build/android/gyp/check_flag_expectations.py"
-  _actual_flags = "$_flagcapture_out_dir/default_ccflags.txt"
-  _expected_flags = "//chrome/android/expectations/ccflags.expected"
-  _failure_file =
-      "$expectations_failure_dir/native_cc_flags_expectations.failed"
-  inputs = [
-    _actual_flags,
-    _expected_flags,
-  ]
-  outputs = [ _failure_file ]
-  args = [
-    "--current-flags",
-    rebase_path(_actual_flags, root_build_dir),
-    "--expected-file",
-    rebase_path(_expected_flags, root_build_dir),
-    "--failure-file",
-    rebase_path(_failure_file, root_build_dir),
-  ]
-  if (fail_on_android_expectations) {
-    args += [ "--fail-on-expectations" ]
-  }
-  deps = [ "//build/android/native_flags:default_ccflags(//build/android/native_flags:flagcapture)" ]
-}
-
-action_with_pydeps("native_ld_flags_expectations") {
-  script = "//build/android/gyp/check_flag_expectations.py"
-  _actual_flags = "$_flagcapture_out_dir/default_ldflags.txt"
-  _expected_flags = "//chrome/android/expectations/ldflags.expected"
-  _failure_file =
-      "$expectations_failure_dir/native_ld_flags_expectations.failed"
-  inputs = [
-    _actual_flags,
-    _expected_flags,
-  ]
-  outputs = [ _failure_file ]
-  args = [
-    "--current-flags",
-    rebase_path(_actual_flags, root_build_dir),
-    "--expected-file",
-    rebase_path(_expected_flags, root_build_dir),
-    "--failure-file",
-    rebase_path(_failure_file, root_build_dir),
-  ]
-  if (fail_on_android_expectations) {
-    args += [ "--fail-on-expectations" ]
-  }
-  deps = [ "//build/android/native_flags:default_ldflags(//build/android/native_flags:flagcapture)" ]
-}
-
-group("native_flags_expectations") {
-  deps = [
-    ":native_cc_flags_expectations",
-    ":native_ld_flags_expectations",
-  ]
-}
diff --git a/chrome/android/expectations/README.md b/chrome/android/expectations/README.md
index 5de4f15..7d093844 100644
--- a/chrome/android/expectations/README.md
+++ b/chrome/android/expectations/README.md
@@ -79,20 +79,6 @@
 When we change build gn files, the native libraries and assets can sometimes
 be changed in an unexpected way.
 
-## Native Flags
-The compile and link flags that are used to build chrome.
-
-### What are `*flags.expected` files?
-`*flags.expected` files store in a text format the list of flags passed to
-the compiler and linker when building chrome's native libraries.
-
-### Why do we care about compile/link flag discrepancies?
-Some of chrome's native code is compiled outside of the repo. The
-`*flags.expected` files inform the build team that these flags changed (most
-importantly if any relate to security). When you update a `*flags.expected`
-file the build team is informed (via a WATCHLIST entry) and can then choose
-to add these flags for out-of-repo native library builds.
-
 ## Build failures caused by `*.expected` files
 
 ### What is the build error telling me?
diff --git a/chrome/android/expectations/ldflags.expected b/chrome/android/expectations/ldflags.expected
index 232554e..6fbbf4b1 100644
--- a/chrome/android/expectations/ldflags.expected
+++ b/chrome/android/expectations/ldflags.expected
@@ -1,3 +1,4 @@
+--rtlib=libgcc
 --target=arm-linux-androideabi21
 -Werror
 -Wl,--as-needed
diff --git a/chrome/android/expectations/monochrome_public_bundle.proguard_flags.expected b/chrome/android/expectations/monochrome_public_bundle.proguard_flags.expected
index e0b10da..edbcf98f 100644
--- a/chrome/android/expectations/monochrome_public_bundle.proguard_flags.expected
+++ b/chrome/android/expectations/monochrome_public_bundle.proguard_flags.expected
@@ -257,17 +257,6 @@
   @org.chromium.base.annotations.RemovableInRelease *;
 }
 
-# File: ../../chrome/android/proguard/isolated_splits.flags
-# 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.
-
-# Isolated splits currently use DexSplitter for splitting out some DFMs.
-# DexSplitter has some issues with certain R8 optimizations, so we need to keep
-# ModuleInterface classes to make sure they aren't inlined.
--keep @interface org.chromium.components.module_installer.builder.ModuleInterface
--keep @org.chromium.components.module_installer.builder.ModuleInterface class ** {}
-
 # File: ../../chrome/android/proguard/main.flags
 # Copyright 2016 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
diff --git a/chrome/android/features/keyboard_accessory/BUILD.gn b/chrome/android/features/keyboard_accessory/BUILD.gn
index df06707..48c5719 100644
--- a/chrome/android/features/keyboard_accessory/BUILD.gn
+++ b/chrome/android/features/keyboard_accessory/BUILD.gn
@@ -63,6 +63,7 @@
     "//chrome/android:chrome_java",
     "//chrome/android:chrome_test_java",
     "//chrome/android:chrome_test_util_java",
+    "//chrome/browser/feature_engagement:java",
     "//chrome/browser/flags:java",
     "//chrome/browser/profiles/android:java",
     "//chrome/browser/tab:java",
diff --git a/chrome/android/features/keyboard_accessory/internal/BUILD.gn b/chrome/android/features/keyboard_accessory/internal/BUILD.gn
index 9e6de89..a262c43 100644
--- a/chrome/android/features/keyboard_accessory/internal/BUILD.gn
+++ b/chrome/android/features/keyboard_accessory/internal/BUILD.gn
@@ -17,6 +17,7 @@
     # TODO(crbug/951695): Cyclic dependency. Depend on public only when ready.
     "//chrome/android:chrome_java",
     "//chrome/android/features/keyboard_accessory/public:public_java",
+    "//chrome/browser/feature_engagement:java",
     "//chrome/browser/flags:java",
     "//chrome/browser/fullscreen/android:java",
     "//chrome/browser/password_manager/android:java",
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java
index e8c3d71..8dcc584 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java
@@ -27,10 +27,13 @@
 import static org.hamcrest.Matchers.instanceOf;
 import static org.hamcrest.Matchers.notNullValue;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import static org.chromium.chrome.browser.tabmodel.TestTabModelDirectory.M26_GOOGLE_COM;
 import static org.chromium.chrome.test.util.ViewUtils.onViewWaiting;
+import static org.chromium.chrome.test.util.ViewUtils.waitForView;
 
+import android.app.Activity;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.graphics.Bitmap;
@@ -44,6 +47,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
+import android.widget.TextView;
 
 import androidx.annotation.Nullable;
 import androidx.recyclerview.widget.LinearLayoutManager;
@@ -69,6 +73,7 @@
 import org.chromium.base.BuildConfig;
 import org.chromium.base.Callback;
 import org.chromium.base.CommandLine;
+import org.chromium.base.ContextUtils;
 import org.chromium.base.NativeLibraryLoadedStatus;
 import org.chromium.base.StreamUtil;
 import org.chromium.base.SysUtils;
@@ -85,6 +90,7 @@
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
+import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.compositor.layouts.Layout;
 import org.chromium.chrome.browser.compositor.layouts.LayoutManagerChromePhone;
 import org.chromium.chrome.browser.compositor.layouts.LayoutManagerChromeTablet;
@@ -117,6 +123,7 @@
 import org.chromium.chrome.browser.tasks.pseudotab.TabAttributeCache;
 import org.chromium.chrome.browser.tasks.tab_management.TabUiFeatureUtilities;
 import org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper;
+import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
 import org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarCoordinator;
 import org.chromium.chrome.browser.toolbar.top.TopToolbarCoordinator;
 import org.chromium.chrome.browser.util.ChromeAccessibilityUtil;
@@ -133,6 +140,7 @@
 import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
 import org.chromium.chrome.test.util.browser.suggestions.SuggestionsDependenciesRule;
 import org.chromium.chrome.test.util.browser.suggestions.mostvisited.FakeMostVisitedSites;
+import org.chromium.components.embedder_support.util.UrlConstants;
 import org.chromium.components.user_prefs.UserPrefs;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.content_public.browser.test.util.TestTouchUtils;
@@ -165,6 +173,7 @@
     private static final String IMMEDIATE_RETURN_PARAMS = "force-fieldtrial-params=Study.Group:"
             + ReturnToChromeExperimentsUtil.TAB_SWITCHER_ON_RETURN_MS_PARAM + "/0";
     private static final int ARTICLE_SECTION_HEADER_POSITION = 0;
+    private static final long MAX_TIMEOUT_MS = 30000L;
     private Bitmap mBitmap;
     private int mThumbnailFetchCount;
 
@@ -218,6 +227,14 @@
         mActivityTestRule.launchActivity(intent);
     }
 
+    private void startNewTabFromLauncherIcon() {
+        Intent intent = IntentHandler.createTrustedOpenNewTabIntent(
+                ContextUtils.getApplicationContext(), false);
+        intent.putExtra(IntentHandler.EXTRA_INVOKED_FROM_SHORTCUT, true);
+        mActivityTestRule.prepareUrlIntent(intent, null);
+        mActivityTestRule.launchActivity(intent);
+    }
+
     public static Bitmap createThumbnailBitmapAndWriteToFile(int tabId) {
         final Bitmap thumbnailBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
 
@@ -1015,13 +1032,11 @@
                 mActivityTestRule.getActivity().findViewById(R.id.placeholders_layout), 0, 0, 0,
                 toY, 1);
 
-        // The start surface toolbar should be scrolled up and not be displayed.
-        onView(withId(org.chromium.chrome.start_surface.R.id.tab_switcher_toolbar))
-                .check(matches(not(isDisplayed())));
+        // Toolbar layout view should show.
+        onViewWaiting(withId(R.id.toolbar));
 
-        // Toolbar container view should show.
-        onView(withId(org.chromium.chrome.start_surface.R.id.toolbar_container))
-                .check(matches(isDisplayed()));
+        // The start surface toolbar should be scrolled up and not be displayed.
+        onView(withId(R.id.tab_switcher_toolbar)).check(matches(not(isDisplayed())));
 
         View surface = mActivityTestRule.getActivity().findViewById(R.id.toolbar);
         ChromeRenderTestRule.sanitize(surface);
@@ -1371,6 +1386,50 @@
         Assert.assertEquals(1, PseudoTab.getAllPseudoTabsFromStateFile().size());
     }
 
+    @Test
+    @MediumTest
+    @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE})
+    // clang-format off
+    @EnableFeatures({ChromeFeatureList.TAB_SWITCHER_ON_RETURN + "<Study,",
+        ChromeFeatureList.START_SURFACE_ANDROID + "<Study"})
+    @CommandLineFlags.Add({"force-fieldtrials=Study/Group", IMMEDIATE_RETURN_PARAMS +
+        "/start_surface_variation/single/omnibox_focused_on_new_tab/true"})
+    public void testNewTabFromLauncher() throws IOException {
+        // clang-format on
+        createTabStateFile(new int[] {0});
+        createThumbnailBitmapAndWriteToFile(0);
+        TabAttributeCache.setTitleForTesting(0, "Google");
+
+        startNewTabFromLauncherIcon();
+        waitForTabModel();
+        TabUiTestHelper.verifyTabModelTabCount(mActivityTestRule.getActivity(), 2, 0);
+
+        waitForView(withId(org.chromium.chrome.start_surface.R.id.search_box_text));
+        TextView urlBar = mActivityTestRule.getActivity().findViewById(
+                org.chromium.chrome.start_surface.R.id.url_bar);
+        CriteriaHelper.pollUiThread(()
+                                            -> isKeyboardShown() && urlBar.isFocused(),
+                MAX_TIMEOUT_MS, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
+        waitForView(withId(org.chromium.chrome.start_surface.R.id.voice_search_button));
+        Assert.assertTrue(TextUtils.isEmpty(urlBar.getText()));
+        assertEquals(mActivityTestRule.getActivity()
+                             .findViewById(org.chromium.chrome.start_surface.R.id.toolbar_buttons)
+                             .getVisibility(),
+                View.INVISIBLE);
+        ToolbarDataProvider toolbarDataProvider =
+                mActivityTestRule.getActivity().getToolbarManager().getLocationBarModelForTesting();
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            assertTrue(TextUtils.equals(toolbarDataProvider.getCurrentUrl(), UrlConstants.NTP_URL));
+        });
+    }
+
+    private boolean isKeyboardShown() {
+        Activity activity = mActivityTestRule.getActivity();
+        if (activity.getCurrentFocus() == null) return false;
+        return mActivityTestRule.getKeyboardDelegate().isKeyboardShowing(
+                activity, activity.getCurrentFocus());
+    }
+
     /**
      * Toggles the header and checks whether the header has the right status.
      *
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
index 3eac0f3..04f9503 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
@@ -1516,10 +1516,11 @@
                         -> Assert.assertTrue(StartSurfaceUserData.getKeepTab(
                                 cta.getTabModelSelector().getCurrentTab())));
 
+        OverviewModeBehaviorWatcher overviewModeWatcher = new OverviewModeBehaviorWatcher(
+                mActivityTestRule.getActivity().getLayoutManager(), true, false);
         pressBack();
         // Verifies the new Tab isn't deleted, and Start surface is shown.
-        CriteriaHelper.pollUiThread(() -> cta.getLayoutManager().overviewVisible());
-        waitForView(withId(R.id.primary_tasks_surface_view));
+        overviewModeWatcher.waitForBehavior();
         TabUiTestHelper.verifyTabModelTabCount(cta, 2, 0);
 
         // Verifies Chrome is closed.
@@ -1527,11 +1528,15 @@
             pressBack();
         } catch (Exception e) {
         } finally {
-            TestThreadUtils.runOnUiThreadBlocking(() -> {
-                Assert.assertEquals(Stage.STOPPED,
-                        ActivityLifecycleMonitorRegistry.getInstance().getLifecycleStageOf(
-                                mActivityTestRule.getActivity()));
-            });
+            CriteriaHelper.pollUiThread(
+                    ()
+                            -> {
+                        return ActivityLifecycleMonitorRegistry.getInstance().getLifecycleStageOf(
+                                       mActivityTestRule.getActivity())
+                                == Stage.STOPPED;
+                    },
+                    "Tapping back button should close Chrome.", MAX_TIMEOUT_MS,
+                    CriteriaHelper.DEFAULT_POLLING_INTERVAL);
         }
     }
 
@@ -2001,10 +2006,11 @@
                                 .getResources()
                                 .getDimensionPixelOffset(R.dimen.toolbar_height_no_shadow)));
 
-        onView(withId(R.id.tab_switcher_toolbar)).check(matches(not(isDisplayed())));
+        // Toolbar layout view should show.
+        onViewWaiting(withId(R.id.toolbar));
 
-        // Toolbar container view should show.
-        onView(withId(R.id.toolbar_container)).check(matches(isDisplayed()));
+        // The start surface toolbar should be scrolled up and not be displayed.
+        onView(withId(R.id.tab_switcher_toolbar)).check(matches(not(isDisplayed())));
 
         // Check the toolbar's background color.
         ToolbarPhone toolbar =
diff --git a/chrome/android/features/tab_ui/BUILD.gn b/chrome/android/features/tab_ui/BUILD.gn
index 926c8ce..40275e1 100644
--- a/chrome/android/features/tab_ui/BUILD.gn
+++ b/chrome/android/features/tab_ui/BUILD.gn
@@ -200,6 +200,7 @@
     "//chrome/browser/android/lifecycle:java",
     "//chrome/browser/browser_controls/android:java",
     "//chrome/browser/endpoint_fetcher:java",
+    "//chrome/browser/feature_engagement:java",
     "//chrome/browser/feedback/android:java",
     "//chrome/browser/flags:java",
     "//chrome/browser/profiles/android:java",
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
index 979a7fb..0c73af5 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
@@ -341,8 +341,7 @@
         mMediator = new FeedSurfaceMediator(
                 this, snapScrollHelper, mPageNavigationDelegate, mSectionHeaderModel);
 
-        mUserEducationHelper =
-                new UserEducationHelper(mActivity, mHandler, TrackerFactory::getTrackerForProfile);
+        mUserEducationHelper = new UserEducationHelper(mActivity, mHandler);
     }
 
     @Override
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index 866a957..19323693b 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -14,8 +14,7 @@
     xmlns:tools="http://schemas.android.com/tools"
     package="{{ manifest_package }}"
     {% set definitions_in_split = definitions_in_split|default(0) == 'true' %}
-    {% set enable_isolated_splits = enable_isolated_splits|default(0) == 'true' %}
-    {% if enable_isolated_splits %}
+    {% if definitions_in_split %}
     android:isolatedSplits="true"
     {% endif %}
     tools:ignore="MissingVersion">
@@ -150,13 +149,7 @@
 
     <!-- Set android:largeHeap to "true" to allow more than the default
          Java heap limit (32Mb on Nexus S, 48Mb on Xoom). -->
-      <application android:name="{% block application_name %}
-          {%- if enable_isolated_splits -%}
-          org.chromium.chrome.browser.base.SplitChromeApplication
-          {%- else -%}
-          org.chromium.chrome.browser.ChromeApplication
-          {%- endif -%}
-          {% endblock %}"
+      <application android:name="{% block application_name %}org.chromium.chrome.browser.base.SplitChromeApplication{% endblock %}"
         android:icon="@drawable/ic_launcher"
         android:roundIcon="@drawable/ic_launcher_round"
         android:label="{% block application_label %}@string/app_name{% endblock %}"
@@ -174,9 +167,7 @@
         {% endif %}
         android:networkSecurityConfig="@xml/network_security_config"
         android:allowAudioPlaybackCapture="false"
-        {% if enable_isolated_splits %}
         android:appComponentFactory="org.chromium.chrome.browser.base.SplitCompatAppComponentFactory"
-        {% endif %}
         {% block extra_application_attributes %}{% endblock %}>
 
       {% macro application_definitions() %}
diff --git a/chrome/android/java/AndroidManifest_monochrome.xml b/chrome/android/java/AndroidManifest_monochrome.xml
index 03f5f41..7684979 100644
--- a/chrome/android/java/AndroidManifest_monochrome.xml
+++ b/chrome/android/java/AndroidManifest_monochrome.xml
@@ -8,13 +8,7 @@
 ## Note: This is a jinja2 template, processed at build time into the final manifest.
 ##
 
-{% block application_name %}
-{%- if enable_isolated_splits -%}
-org.chromium.chrome.browser.base.SplitMonochromeApplication
-{%- else -%}
-org.chromium.chrome.browser.MonochromeApplication
-{%- endif -%}
-{% endblock %}
+{% block application_name %}org.chromium.chrome.browser.base.SplitMonochromeApplication{% endblock %}
 
 ##
 ## The below is same as internal version, it seems that jinja doesn't have
diff --git a/chrome/android/java/res/OWNERS b/chrome/android/java/res/OWNERS
index 5937579..f8a91cd 100644
--- a/chrome/android/java/res/OWNERS
+++ b/chrome/android/java/res/OWNERS
@@ -1,10 +1 @@
-# This restriction is in place to avoid accidential addition to our top level
-# layout files, such as add duplicated assets, or introducing new colors when
-# we don't want them.
-set noparent
-
 file://ui/android/java/res/LAYOUT_OWNERS
-
-# New Tab Page changes only:
-mvanouwerkerk@chromium.org
-peconn@chromium.org
diff --git a/chrome/android/java/res_app/DIR_METADATA b/chrome/android/java/res_app/DIR_METADATA
new file mode 100644
index 0000000..8fc7647
--- /dev/null
+++ b/chrome/android/java/res_app/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>Mobile"
+}
+os: ANDROID
diff --git a/chrome/android/java/res_app/OWNERS b/chrome/android/java/res_app/OWNERS
new file mode 100644
index 0000000..87ab79d
--- /dev/null
+++ b/chrome/android/java/res_app/OWNERS
@@ -0,0 +1,5 @@
+# This restriction is in place to avoid accidential addition to our top level
+# layout files.
+set noparent
+
+file://ui/android/java/res/LAYOUT_OWNERS
diff --git a/chrome/android/java/res/layout/main.xml b/chrome/android/java/res_app/layout/main.xml
similarity index 100%
rename from chrome/android/java/res/layout/main.xml
rename to chrome/android/java/res_app/layout/main.xml
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 22d6be9..3af5ba67 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -1050,8 +1050,19 @@
 
     private boolean shouldShowTabSwitcherOnStart() {
         String intentUrl = IntentHandler.getUrlFromIntent(getIntent());
-        if (ReturnToChromeExperimentsUtil.shouldShowStartSurfaceAsTheHomePage()
-                && ReturnToChromeExperimentsUtil.isCanonicalizedNTPUrl(intentUrl)) {
+        // If Chrome is launched by tapping the New Tab Item from the launch icon and
+        // {@link OMNIBOX_FOCUSED_ON_NEW_TAB} is enabled, a new Tab with omnibox focused will be
+        // shown on Startup.
+        boolean isCanonicalizedNTPUrl =
+                ReturnToChromeExperimentsUtil.isCanonicalizedNTPUrl(intentUrl);
+        if (isCanonicalizedNTPUrl && IntentHandler.isTabOpenAsNewTabFromLauncher(getIntent())
+                && StartSurfaceConfiguration.OMNIBOX_FOCUSED_ON_NEW_TAB.getValue()
+                && IntentHandler.wasIntentSenderChrome(getIntent())) {
+            return false;
+        }
+
+        if (isCanonicalizedNTPUrl
+                && ReturnToChromeExperimentsUtil.shouldShowStartSurfaceAsTheHomePage()) {
             // Handle NTP intent.
             return true;
         } else if (ReturnToChromeExperimentsUtil.shouldShowStartSurfaceAsTheHomePageNoTabs()
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/DEPS b/chrome/android/java/src/org/chromium/chrome/browser/DEPS
index fcb464e..9cf912f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/DEPS
+++ b/chrome/android/java/src/org/chromium/chrome/browser/DEPS
@@ -211,9 +211,6 @@
   "AndroidPaymentApp\.java": [
     "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
   ],
-  "AndroidPaymentAppFinder\.java": [
-    "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
-  ],
   "AutofillPaymentInstrument\.java": [
     "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
   ],
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
index e7a4d6a2..a3fc67d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
@@ -1135,6 +1135,15 @@
                 != 0;
     }
 
+    /**
+     * Returns whether the Intent specifies to create a new Tab from the launcher shortcut.
+     */
+    static boolean isTabOpenAsNewTabFromLauncher(Intent intent) {
+        return IntentUtils.safeGetBooleanExtra(intent, Browser.EXTRA_CREATE_NEW_TAB, false)
+                && IntentUtils.safeGetBooleanExtra(
+                        intent, IntentHandler.EXTRA_INVOKED_FROM_SHORTCUT, false);
+    }
+
     /*
      * The default behavior here is to open in a new tab.  If this is changed, ensure
      * intents with action NDEF_DISCOVERED (links beamed over NFC) are handled properly.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java
index 29b49f0..ffa906d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java
@@ -165,6 +165,11 @@
                     @Override
                     public void onActivityStateChange(
                             Activity activity, @ActivityState int newState) {
+                        // Some tests pass an activity without a base context.
+                        if (activity.getBaseContext() == null) {
+                            return;
+                        }
+
                         if (newState != ActivityState.CREATED) {
                             return;
                         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
index 1597998c7..f086ddb2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
@@ -21,7 +21,6 @@
 import org.chromium.base.supplier.Supplier;
 import org.chromium.cc.input.BrowserControlsState;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
-import org.chromium.chrome.browser.ShortcutHelper;
 import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.app.tab_activity_glue.ActivityTabWebContentsDelegateAndroid;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
@@ -56,9 +55,6 @@
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.document.TabDelegate;
 import org.chromium.chrome.browser.ui.native_page.NativePage;
-import org.chromium.chrome.browser.webapps.WebappActivity;
-import org.chromium.chrome.browser.webapps.WebappIntentUtils;
-import org.chromium.chrome.browser.webapps.WebappLauncherActivity;
 import org.chromium.components.browser_ui.util.BrowserControlsVisibilityDelegate;
 import org.chromium.components.browser_ui.util.ComposedBrowserControlsVisibilityDelegate;
 import org.chromium.components.embedder_support.delegate.WebContentsDelegateAndroid;
@@ -239,48 +235,10 @@
 
         @Override
         protected void bringActivityToForeground() {
-            // TODO: Unify WebAPK and CCT behavior.
-            if (isWebappOrWebApk(mActivityType)) {
-                bringActivityToForegroundWebapp();
-            } else {
-                bringActivityToForegroundCustomTab();
-            }
-        }
-
-        private void bringActivityToForegroundCustomTab() {
             ((ActivityManager) mActivity.getSystemService(Context.ACTIVITY_SERVICE))
                     .moveTaskToFront(mActivity.getTaskId(), 0);
         }
 
-        private void bringActivityToForegroundWebapp() {
-            WebappActivity webappActivity = (WebappActivity) mActivity;
-            BrowserServicesIntentDataProvider intentDataProvider =
-                    webappActivity.getIntentDataProvider();
-
-            // Create an Intent that will be fired toward the WebappLauncherActivity, which in turn
-            // will fire an Intent to launch the correct WebappActivity. On L+ this could probably
-            // be changed to call AppTask.moveToFront(), but for backwards compatibility we relaunch
-            // it the hard way.
-            String startUrl = intentDataProvider.getUrlToLoad();
-
-            if (intentDataProvider.isWebApkActivity()) {
-                Intent activateIntent = null;
-                activateIntent = new Intent(ACTION_ACTIVATE_WEBAPK);
-                activateIntent.setPackage(ContextUtils.getApplicationContext().getPackageName());
-                IntentUtils.safeStartActivity(mActivity, activateIntent);
-                return;
-            }
-
-            Intent intent = new Intent();
-            intent.setAction(WebappLauncherActivity.ACTION_START_WEBAPP);
-            intent.setPackage(mActivity.getPackageName());
-            WebappIntentUtils.copyWebappLaunchIntentExtras(mActivity.getIntent(), intent);
-
-            intent.putExtra(ShortcutHelper.EXTRA_MAC, ShortcutHelper.getEncodedMac(startUrl));
-            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            IntentUtils.safeStartActivity(ContextUtils.getApplicationContext(), intent);
-        }
-
         @Override
         protected boolean shouldEnableEmbeddedMediaExperience() {
             return mShouldEnableEmbeddedMediaExperience;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
index 3b223e6..25f37616 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
@@ -186,13 +186,6 @@
     public static final String EXTRA_HIDE_VISITS_FROM_CCT =
             "androidx.browser.customtabs.extra.HIDE_VISITS_FROM_CCT";
 
-    /**
-     * Extra used to provide a PendingIntent that we can launch to focus the client.
-     * TODO(peconn): Move to AndroidX.
-     */
-    private static final String EXTRA_FOCUS_INTENT =
-            "androidx.browser.customtabs.extra.FOCUS_INTENT";
-
     private static final String EXTRA_TWA_DISCLOSURE_UI =
             "androidx.browser.trusted.extra.DISCLOSURE_VERSION";
 
@@ -241,7 +234,6 @@
     private PendingIntent mRemoteViewsPendingIntent;
     // OnFinished listener for PendingIntents. Used for testing only.
     private PendingIntent.OnFinished mOnFinished;
-    private PendingIntent mFocusIntent;
 
     /** Whether this CustomTabActivity was explicitly started by another Chrome Activity. */
     private final boolean mIsOpenedByChrome;
@@ -365,7 +357,6 @@
                 IntentUtils.safeGetBooleanExtra(intent, EXTRA_DISABLE_DOWNLOAD_BUTTON, false);
 
         mTranslateLanguage = IntentUtils.safeGetStringExtra(intent, EXTRA_TRANSLATE_LANGUAGE);
-        mFocusIntent = IntentUtils.safeGetParcelableExtra(intent, EXTRA_FOCUS_INTENT);
         // Import the {@link ScreenOrientation}.
         mDefaultOrientation = convertOrientationType(IntentUtils.safeGetIntExtra(intent,
                 TrustedWebActivityIntentBuilder.EXTRA_SCREEN_ORIENTATION,
@@ -831,12 +822,6 @@
         }
     }
 
-    @Override
-    @Nullable
-    public PendingIntent getFocusIntent() {
-        return mFocusIntent;
-    }
-
     @TwaDisclosureUi
     @Override
     public int getTwaDisclosureUi() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
index 09580122..cab3bf56 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
@@ -118,7 +118,7 @@
     /** Generic interface for notifying external UI components about downloads and their states. */
     public interface DownloadObserver extends DownloadSharedPreferenceHelper.Observer {
         /** Called in response to {@link DownloadManagerService#getAllDownloads(OTRProfileID)}. */
-        void onAllDownloadsRetrieved(final List<DownloadItem> list, boolean isOffTheRecord);
+        void onAllDownloadsRetrieved(final List<DownloadItem> list, ProfileKey profileKey);
 
         /** Called when a download is created. */
         void onDownloadItemCreated(DownloadItem item);
@@ -127,7 +127,7 @@
         void onDownloadItemUpdated(DownloadItem item);
 
         /** Called when a download has been removed. */
-        void onDownloadItemRemoved(String guid, boolean isOffTheRecord);
+        void onDownloadItemRemoved(String guid);
 
         /** Only for testing */
         default void broadcastDownloadSuccessfulForTesting(DownloadInfo downloadInfo) {}
@@ -1459,11 +1459,8 @@
     // Deprecated after new download backend.
     @CalledByNative
     private void onAllDownloadsRetrieved(final List<DownloadItem> list, ProfileKey profileKey) {
-        // TODO(https://crbug.com/1099577): Pass the profileKey/profile to adapter instead of the
-        // boolean.
-        boolean isOffTheRecord = profileKey.isOffTheRecord();
         for (DownloadObserver adapter : mDownloadObservers) {
-            adapter.onAllDownloadsRetrieved(list, isOffTheRecord);
+            adapter.onAllDownloadsRetrieved(list, profileKey);
         }
         maybeShowMissingSdCardError(list);
     }
@@ -1567,8 +1564,7 @@
         }
 
         for (DownloadObserver adapter : mDownloadObservers) {
-            // TODO(crbug.com/1099577): Pass OTRProfileID to support non-primary OTR profiles.
-            adapter.onDownloadItemRemoved(guid, OTRProfileID.isOffTheRecord(otrProfileID));
+            adapter.onDownloadItemRemoved(guid);
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/LegacyDownloadProviderImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/LegacyDownloadProviderImpl.java
index c8e35d6c..f4a4bbe 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/LegacyDownloadProviderImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/LegacyDownloadProviderImpl.java
@@ -16,7 +16,11 @@
 import org.chromium.chrome.browser.download.DownloadMetrics;
 import org.chromium.chrome.browser.download.DownloadOpenSource;
 import org.chromium.chrome.browser.download.DownloadUtils;
+import org.chromium.chrome.browser.incognito.IncognitoUtils;
 import org.chromium.chrome.browser.profiles.OTRProfileID;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.profiles.ProfileKey;
+import org.chromium.chrome.browser.profiles.ProfileManager;
 import org.chromium.components.offline_items_collection.ContentId;
 import org.chromium.components.offline_items_collection.LegacyHelpers;
 import org.chromium.components.offline_items_collection.OfflineContentProvider;
@@ -30,6 +34,7 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 
 /**
@@ -38,10 +43,10 @@
  * that need to happen in Java before hitting the service and (2) converting from
  * {@link DownloadItem}s to {@link OfflineItem}s.
  */
-class LegacyDownloadProviderImpl implements DownloadObserver, LegacyDownloadProvider {
-    private final ArrayList<Callback<ArrayList<OfflineItem>>> mRequests = new ArrayList<>();
-    private final ArrayList<Callback<ArrayList<OfflineItem>>> mOffTheRecordRequests =
-            new ArrayList<>();
+class LegacyDownloadProviderImpl
+        implements DownloadObserver, LegacyDownloadProvider, ProfileManager.Observer {
+    private HashMap<ProfileKey, ArrayList<Callback<ArrayList<OfflineItem>>>> mRequestsMap =
+            new HashMap<>();
 
     private final ObserverList<OfflineContentProvider.Observer> mObservers = new ObserverList<>();
 
@@ -77,16 +82,15 @@
 
     /** @see OfflineContentProvider.Observer#onItemRemoved(ContentId) */
     @Override
-    public void onDownloadItemRemoved(String guid, boolean isOffTheRecord) {
+    public void onDownloadItemRemoved(String guid) {
         for (OfflineContentProvider.Observer observer : mObservers) {
             observer.onItemRemoved(LegacyHelpers.buildLegacyContentId(false, guid));
         }
     }
 
     @Override
-    public void onAllDownloadsRetrieved(List<DownloadItem> items, boolean offTheRecord) {
-        List<Callback<ArrayList<OfflineItem>>> list =
-                offTheRecord ? mOffTheRecordRequests : mRequests;
+    public void onAllDownloadsRetrieved(List<DownloadItem> items, ProfileKey profileKey) {
+        List<Callback<ArrayList<OfflineItem>>> list = mRequestsMap.get(profileKey);
         if (list.isEmpty()) return;
 
         ArrayList<OfflineItem> offlineItems = new ArrayList<>();
@@ -98,6 +102,7 @@
         // Copy the list and clear the original in case the callbacks are reentrant.
         List<Callback<ArrayList<OfflineItem>>> listCopy = new ArrayList<>(list);
         list.clear();
+        mRequestsMap.remove(profileKey);
 
         for (Callback<ArrayList<OfflineItem>> callback : listCopy) callback.onResult(offlineItems);
     }
@@ -176,12 +181,11 @@
 
     @Override
     public void getAllItems(Callback<ArrayList<OfflineItem>> callback, OTRProfileID otrProfileID) {
-        // TODO(crbug.com/1145502): Create a map to hold OTRProfileID as key and list of callbacks
-        // as value.
-        List<Callback<ArrayList<OfflineItem>>> list =
-                otrProfileID != null ? mOffTheRecordRequests : mRequests;
+        ProfileKey profileKey = IncognitoUtils.getProfileKeyFromOTRProfileID(otrProfileID);
+        ArrayList<Callback<ArrayList<OfflineItem>>> list = getRequestList(profileKey);
 
         list.add(callback);
+        mRequestsMap.put(profileKey, list);
         if (list.size() > 1) return;
         DownloadManagerService.getDownloadManagerService().getAllDownloads(otrProfileID);
     }
@@ -222,4 +226,17 @@
         if (TextUtils.isEmpty(item.getDownloadInfo().getFileName())) return false;
         return true;
     }
+
+    private ArrayList getRequestList(ProfileKey profileKey) {
+        return mRequestsMap.get(profileKey) == null ? new ArrayList<>()
+                                                    : mRequestsMap.get(profileKey);
+    }
+
+    @Override
+    public void onProfileAdded(Profile profile) {}
+
+    @Override
+    public void onProfileDestroyed(Profile profile) {
+        mRequestsMap.remove(profile.getProfileKey());
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
index ab21412..5de900d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
@@ -36,7 +36,6 @@
 import org.chromium.chrome.browser.DeferredStartupHandler;
 import org.chromium.chrome.browser.DevToolsServer;
 import org.chromium.chrome.browser.app.video_tutorials.VideoTutorialShareHelper;
-import org.chromium.chrome.browser.banners.AppBannerInProductHelpControllerProvider;
 import org.chromium.chrome.browser.bookmarkswidget.BookmarkWidgetProvider;
 import org.chromium.chrome.browser.contacts_picker.ChromePickerAdapter;
 import org.chromium.chrome.browser.content_capture.ContentCaptureHistoryDeletionObserver;
@@ -46,7 +45,6 @@
 import org.chromium.chrome.browser.download.DownloadController;
 import org.chromium.chrome.browser.download.DownloadManagerService;
 import org.chromium.chrome.browser.download.OfflineContentAvailabilityStatusProvider;
-import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.firstrun.ForcedSigninProcessor;
 import org.chromium.chrome.browser.firstrun.TosDialogBehaviorSharedPrefInvalidator;
 import org.chromium.chrome.browser.flags.CachedFeatureFlags;
@@ -211,8 +209,6 @@
         ChromeActivitySessionTracker.getInstance().initializeWithNative();
         ProfileManagerUtils.removeSessionCookiesForAllProfiles();
         AppBannerManager.setAppDetailsDelegate(AppHooks.get().createAppDetailsDelegate());
-        AppBannerInProductHelpControllerProvider.setTrackerFromProfileFactory(
-                TrackerFactory::getTrackerForProfile);
         ChromeLifetimeController.initialize();
         Clipboard.getInstance().setImageFileProvider(new ClipboardImageFileProvider());
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/instantapps/InstantAppsHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/instantapps/InstantAppsHandler.java
index 0ccde209b..3e8bfd5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/instantapps/InstantAppsHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/instantapps/InstantAppsHandler.java
@@ -65,15 +65,6 @@
             "com.google.android.instantapps.START", "com.google.android.instantapps.nmr1.INSTALL",
             "com.google.android.instantapps.nmr1.VIEW"};
 
-    /** Finch experiment name. */
-    private static final String INSTANT_APPS_EXPERIMENT_NAME = "InstantApps";
-
-    /** Finch experiment group which is enabled for instant apps. */
-    private static final String INSTANT_APPS_ENABLED_ARM = "InstantAppsEnabled";
-
-    /** Finch experiment group which is disabled for instant apps. */
-    private static final String INSTANT_APPS_DISABLED_ARM = "InstantAppsDisabled";
-
     // Only two possible call sources for fallback intents, set boundary at n+1.
     private static final int SOURCE_BOUNDARY = 3;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
index 24cf07b..a055408 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
@@ -35,7 +35,6 @@
 import org.chromium.chrome.browser.cryptids.ProbabilisticCryptidRenderer;
 import org.chromium.chrome.browser.explore_sites.ExperimentalExploreSitesSection;
 import org.chromium.chrome.browser.explore_sites.ExploreSitesBridge;
-import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.lens.LensEntryPoint;
 import org.chromium.chrome.browser.lens.LensFeature;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
@@ -970,8 +969,7 @@
 
     private void maybeShowVideoTutorialTryNowIPH() {
         VideoTutorialTryNowTracker tryNowTracker = VideoTutorialServiceFactory.getTryNowTracker();
-        UserEducationHelper userEducationHelper = new UserEducationHelper(
-                mActivity, new Handler(), TrackerFactory::getTrackerForProfile);
+        UserEducationHelper userEducationHelper = new UserEducationHelper(mActivity, new Handler());
         // TODO(shaktisahu): Pass correct y-inset.
         // TODO(shaktisahu): Determine if there is conflict with another IPH.
         if (tryNowTracker.didClickTryNowButton(FeatureType.SEARCH)) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorInProductHelpController.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorInProductHelpController.java
index 936285b..a4d2bc7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorInProductHelpController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorInProductHelpController.java
@@ -9,7 +9,6 @@
 
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.download.OfflineContentAvailabilityStatusProvider;
-import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.status_indicator.StatusIndicatorCoordinator;
 import org.chromium.chrome.browser.toolbar.ToolbarManager;
 import org.chromium.chrome.browser.ui.appmenu.AppMenuHandler;
@@ -36,8 +35,7 @@
         mActivity = activity;
         mToolbarManager = toolbarManager;
         mAppMenuHandler = appMenuHandler;
-        mUserEducationHelper =
-                new UserEducationHelper(mActivity, mHandler, TrackerFactory::getTrackerForProfile);
+        mUserEducationHelper = new UserEducationHelper(mActivity, mHandler);
 
         assert coordinator != null;
         mCoordinator = coordinator;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteController.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteController.java
index 4099b13..904580c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteController.java
@@ -54,6 +54,7 @@
     private boolean mUseCachedZeroSuggestResults;
     private boolean mEnableNativeVoiceSuggestProvider;
     private boolean mWaitingForSuggestionsToCache;
+    private Profile mProfile;
 
     /**
      * Listener for receiving OmniboxSuggestions.
@@ -78,7 +79,8 @@
     }
 
     /**
-     * Resets the underlying autocomplete controller based on the specified profile.
+     * Resets the underlying autocomplete controller based on the specified profile. This function
+     * returns early if there are no profile changes.
      *
      * <p>This will implicitly stop the autocomplete suggestions, so
      * {@link #start(Profile, String, String, boolean)} must be called again to start them flowing
@@ -89,6 +91,13 @@
      */
     public void setProfile(Profile profile) {
         assert mListener != null : "Ensure a listener is set prior to calling.";
+        if (mProfile == profile) {
+            mNativeAutocompleteControllerAndroid =
+                    AutocompleteControllerJni.get().init(AutocompleteController.this, profile);
+            return;
+        }
+
+        mProfile = profile;
         stop(true);
         if (profile == null) {
             mNativeAutocompleteControllerAndroid = 0;
@@ -134,8 +143,8 @@
                 TextUtils.isEmpty(url));
         if (profile == null || TextUtils.isEmpty(url)) return;
 
-        mNativeAutocompleteControllerAndroid =
-                AutocompleteControllerJni.get().init(AutocompleteController.this, profile);
+        setProfile(profile);
+
         // Initializing the native counterpart might still fail.
         if (mNativeAutocompleteControllerAndroid != 0) {
             AutocompleteControllerJni.get().start(mNativeAutocompleteControllerAndroid,
@@ -204,8 +213,8 @@
                             ChromeFeatureList.OMNIBOX_SPARE_RENDERER,
                             "omnibox_spare_renderer_delay_ms", OMNIBOX_SPARE_RENDERER_DELAY_MS));
         }
-        mNativeAutocompleteControllerAndroid =
-                AutocompleteControllerJni.get().init(AutocompleteController.this, profile);
+        setProfile(profile);
+
         if (mNativeAutocompleteControllerAndroid != 0) {
             if (mUseCachedZeroSuggestResults) mWaitingForSuggestionsToCache = true;
             AutocompleteControllerJni.get().onOmniboxFocused(mNativeAutocompleteControllerAndroid,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/page_info/PageInfoIPHController.java b/chrome/android/java/src/org/chromium/chrome/browser/page_info/PageInfoIPHController.java
index 75cd1f8..cfc8682b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/page_info/PageInfoIPHController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/page_info/PageInfoIPHController.java
@@ -31,9 +31,8 @@
      * @param statusView The status view in the omnibox. Used as anchor for IPH bubble.
      */
     public PageInfoIPHController(Activity activity, View statusView) {
-        mUserEducationHelper = new UserEducationHelper(activity,
-                new Handler(Looper.getMainLooper()), TrackerFactory::getTrackerForProfile);
-
+        mUserEducationHelper =
+                new UserEducationHelper(activity, new Handler(Looper.getMainLooper()));
         mStatusView = statusView;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinder.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinder.java
index b58ea25..0fb0dd4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinder.java
@@ -14,8 +14,9 @@
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.Log;
-import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.payments.PaymentManifestVerifier.ManifestVerifyCallback;
+import org.chromium.chrome.browser.tabmodel.TabModelSelector;
+import org.chromium.chrome.browser.tabmodel.TabModelSelectorSupplier;
 import org.chromium.components.payments.AndroidPaymentApp;
 import org.chromium.components.payments.ErrorStrings;
 import org.chromium.components.payments.MethodStrings;
@@ -187,9 +188,12 @@
         mPackageManagerDelegate = packageManagerDelegate;
         mTwaPackageManagerDelegate = twaPackageManagerDelegate;
         mFactory = factory;
-        ChromeActivity activity =
-                ChromeActivity.fromWebContents(mFactoryDelegate.getParams().getWebContents());
-        mIsIncognito = activity != null && activity.getCurrentTabModel().isIncognito();
+        TabModelSelector tabModelSelector = TabModelSelectorSupplier
+                                                    .from(mFactoryDelegate.getParams()
+                                                                    .getWebContents()
+                                                                    .getTopLevelNativeWindow())
+                                                    .get();
+        mIsIncognito = tabModelSelector != null && tabModelSelector.isIncognitoSelected();
     }
 
     private void findAppStoreBillingApp(List<ResolveInfo> allInstalledPaymentApps) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/read_later/ReadLaterIPHController.java b/chrome/android/java/src/org/chromium/chrome/browser/read_later/ReadLaterIPHController.java
index c0df10e2..ea3c7eb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/read_later/ReadLaterIPHController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/read_later/ReadLaterIPHController.java
@@ -10,7 +10,6 @@
 import android.view.View;
 
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.ui.appmenu.AppMenuHandler;
 import org.chromium.chrome.browser.user_education.IPHCommandBuilder;
@@ -35,8 +34,8 @@
             Activity activity, View toolbarMenuButton, AppMenuHandler appMenuHandler) {
         mToolbarMenuButton = toolbarMenuButton;
         mAppMenuHandler = appMenuHandler;
-        mUserEducationHelper = new UserEducationHelper(activity,
-                new Handler(Looper.getMainLooper()), TrackerFactory::getTrackerForProfile);
+        mUserEducationHelper =
+                new UserEducationHelper(activity, new Handler(Looper.getMainLooper()));
     }
 
     /**
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 2b69416a..f5ccb52 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
@@ -32,7 +32,6 @@
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchManager;
 import org.chromium.chrome.browser.continuous_search.ContinuousSearchContainerCoordinator;
 import org.chromium.chrome.browser.datareduction.DataReductionPromoScreen;
-import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.feed.shared.FeedFeatures;
 import org.chromium.chrome.browser.feed.webfeed.WebFeedFollowIntroController;
 import org.chromium.chrome.browser.firstrun.FirstRunStatus;
@@ -412,7 +411,7 @@
                         mActivity, mAppMenuCoordinator.getAppMenuHandler(),
                         ()
                                 -> mActivity.getToolbarManager().getMenuButtonView(),
-                        R.id.add_to_homescreen_id, TrackerFactory::getTrackerForProfile);
+                        R.id.add_to_homescreen_id);
         AppBannerInProductHelpControllerFactory.attach(
                 mActivity.getWindowAndroid(), mAppBannerInProductHelpController);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonInProductHelpController.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonInProductHelpController.java
index 653a1b60..63be0dd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonInProductHelpController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonInProductHelpController.java
@@ -92,8 +92,7 @@
         mMenuButtonAnchorView = menuButtonAnchorView;
         mSecurityIconAnchorView = securityIconAnchorView;
         mIsInOverviewModeSupplier = isInOverviewModeSupplier;
-        mUserEducationHelper =
-                new UserEducationHelper(mActivity, mHandler, TrackerFactory::getTrackerForProfile);
+        mUserEducationHelper = new UserEducationHelper(mActivity, mHandler);
         mScreenshotMonitor = new ScreenshotMonitor(this);
         mLifecycleDispatcher = lifecycleDispatcher;
         mLifecycleDispatcher.register(this);
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 f8f5c739..70e532a0 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
@@ -808,15 +808,7 @@
             @Override
             public void onSceneChange(Layout layout) {
                 mToolbar.setContentAttached(layout.shouldDisplayContentOverlay());
-
-                if (StartSurfaceConfiguration.consumeFocusOnOmnibox(
-                            mActivityTabProvider.get(), layout)) {
-                    setUrlBarFocus(true, OmniboxFocusReason.FOCUS_ON_NEW_TAB);
-                    if (shouldShowCursorInLocationBar()) {
-                        mLocationBar.showUrlBarCursorWithoutFocusAnimations();
-                    }
-                    updateButtonStatus();
-                }
+                maybeFocusOmnibox(layout, mActivityTabProvider.get());
             }
         };
 
@@ -861,6 +853,23 @@
         TraceEvent.end("ToolbarManager.ToolbarManager");
     }
 
+    /**
+     * May set Omnibox focused if the Tab has the flag to require focusing the Omnibox.
+     */
+    private void maybeFocusOmnibox(Layout layout, Tab tab) {
+        if (StartSurfaceConfiguration.consumeFocusOnOmnibox(tab, layout)) {
+            if (mLocationBar.getFakeboxDelegate() == null
+                    || mLocationBar.getFakeboxDelegate().isUrlBarFocused()) {
+                return;
+            }
+            setUrlBarFocus(true, OmniboxFocusReason.FOCUS_ON_NEW_TAB);
+            if (shouldShowCursorInLocationBar()) {
+                mLocationBar.showUrlBarCursorWithoutFocusAnimations();
+            }
+            updateButtonStatus();
+        }
+    }
+
     private TopToolbarCoordinator createTopToolbarCoordinator(
             ToolbarControlContainer controlContainer, ToolbarLayout toolbarLayout,
             List<ButtonDataProvider> buttonDataProviders,
@@ -872,7 +881,7 @@
         // clang-format off
         TopToolbarCoordinator toolbar = new TopToolbarCoordinator(controlContainer, toolbarLayout,
                 mLocationBarModel, mToolbarTabController,
-                new UserEducationHelper(mActivity, mHandler, TrackerFactory::getTrackerForProfile),
+                new UserEducationHelper(mActivity, mHandler),
                 buttonDataProviders, mLayoutStateProviderSupplier, browsingModeThemeColorProvider,
                 mAppThemeColorProvider, mMenuButtonCoordinator, startSurfaceMenuButtonCoordinator,
                 mMenuButtonCoordinator.getMenuButtonHelperSupplier(), mTabModelSelectorSupplier,
@@ -1158,10 +1167,10 @@
                 && !TextUtils.isEmpty(currentTab.getUrlString())) {
             mControlContainer.setReadyForBitmapCapture(true);
         }
+        maybeFocusOmnibox(mLayoutManager.getActiveLayout(), currentTab);
 
         if (ChromeFeatureList.isEnabled(ChromeFeatureList.TOOLBAR_IPH_ANDROID)) {
-            UserEducationHelper userEducationHelper = new UserEducationHelper(
-                    mActivity, mHandler, TrackerFactory::getTrackerForProfile);
+            UserEducationHelper userEducationHelper = new UserEducationHelper(mActivity, mHandler);
             Tracker tracker =
                     TrackerFactory.getTrackerForProfile(Profile.getLastUsedRegularProfile());
             View homeButton = mControlContainer.findViewById(R.id.home_button);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestRule.java
index 0b898a4..56b858d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestRule.java
@@ -18,6 +18,7 @@
 import org.chromium.base.Log;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.chrome.browser.download.items.OfflineContentAggregatorFactory;
+import org.chromium.chrome.browser.profiles.ProfileKey;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.components.offline_items_collection.ContentId;
 import org.chromium.components.offline_items_collection.OfflineContentProvider;
@@ -194,7 +195,7 @@
     private class TestDownloadManagerServiceObserver
             implements DownloadManagerService.DownloadObserver {
         @Override
-        public void onAllDownloadsRetrieved(final List<DownloadItem> list, boolean isOffTheRecord) {
+        public void onAllDownloadsRetrieved(final List<DownloadItem> list, ProfileKey profileKey) {
             mAllDownloads = list;
         }
 
@@ -202,7 +203,7 @@
         public void onDownloadItemCreated(DownloadItem item) {}
 
         @Override
-        public void onDownloadItemRemoved(String guid, boolean isOffTheRecord) {}
+        public void onDownloadItemRemoved(String guid) {}
 
         @Override
         public void onAddOrReplaceDownloadSharedPreferenceEntry(ContentId id) {}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/history/HistoryActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/history/HistoryActivityTest.java
index 491ec85..4fa0ede 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/history/HistoryActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/history/HistoryActivityTest.java
@@ -58,7 +58,6 @@
 import org.chromium.components.browser_ui.widget.selectable_list.SelectableItemView;
 import org.chromium.components.browser_ui.widget.selectable_list.SelectableItemViewHolder;
 import org.chromium.components.signin.base.CoreAccountInfo;
-import org.chromium.components.signin.metrics.SigninAccessPoint;
 import org.chromium.components.signin.metrics.SignoutReason;
 import org.chromium.components.user_prefs.UserPrefs;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
@@ -555,21 +554,15 @@
             mPrefChangeRegistrar = new PrefChangeRegistrar();
             mPrefChangeRegistrar.addObserver(Pref.ALLOW_DELETING_BROWSER_HISTORY, mTestObserver);
             mPrefChangeRegistrar.addObserver(Pref.INCOGNITO_MODE_AVAILABILITY, mTestObserver);
+            IdentityServicesProvider.get()
+                    .getSigninManager(Profile.getLastUsedRegularProfile())
+                    .addSignInStateObserver(mTestObserver);
         });
 
         // Sign in to account. Note that if supervised user is set before sign in, the supervised
         // user setting will be reset.
         final CoreAccountInfo coreAccountInfo =
-                mAccountManagerTestRule.addAccount(AccountManagerTestRule.TEST_ACCOUNT_EMAIL);
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            Profile profile = Profile.getLastUsedRegularProfile();
-            IdentityServicesProvider.get().getSigninManager(profile).onFirstRunCheckDone();
-            IdentityServicesProvider.get().getSigninManager(profile).addSignInStateObserver(
-                    mTestObserver);
-            IdentityServicesProvider.get().getSigninManager(profile).signinAndEnableSync(
-                    SigninAccessPoint.UNKNOWN, coreAccountInfo, null);
-        });
-
+                mAccountManagerTestRule.addTestAccountThenSigninAndEnableSync();
         mTestObserver.onSigninStateChangedCallback.waitForCallback(
                 0, 1, SyncTestUtil.TIMEOUT_MS, TimeUnit.MILLISECONDS);
         Assert.assertEquals(coreAccountInfo, mAccountManagerTestRule.getCurrentSignedInAccount());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoDownloadLeakageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoDownloadLeakageTest.java
index 84e0a211..e61fb74a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoDownloadLeakageTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoDownloadLeakageTest.java
@@ -34,6 +34,7 @@
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.profiles.ProfileKey;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
@@ -84,8 +85,8 @@
             new DownloadManagerService.DownloadObserver() {
                 @Override
                 public void onAllDownloadsRetrieved(
-                        List<DownloadItem> list, boolean isOffTheRecord) {
-                    if (isOffTheRecord) {
+                        List<DownloadItem> list, ProfileKey profileKey) {
+                    if (profileKey.isOffTheRecord()) {
                         mOffTheRecordDownloadItems = new ArrayList<DownloadItem>(list);
                     } else {
                         mRegularDownloadItems = new ArrayList<DownloadItem>(list);
@@ -100,7 +101,7 @@
                 public void onDownloadItemUpdated(DownloadItem item) {}
 
                 @Override
-                public void onDownloadItemRemoved(String guid, boolean isOffTheRecord) {}
+                public void onDownloadItemRemoved(String guid) {}
 
                 @Override
                 public void onAddOrReplaceDownloadSharedPreferenceEntry(ContentId id) {}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoDiscoverabilityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoDiscoverabilityTest.java
index eac373d..7cf4143d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoDiscoverabilityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoDiscoverabilityTest.java
@@ -88,29 +88,9 @@
         });
     }
 
-    @Test
-    @MediumTest
-    @Feature({"PageInfoDiscoverability"})
-    @EnableFeatures({PageInfoFeatureList.PAGE_INFO_DISCOVERABILITY})
-    public void testPageInfoDiscoverabilityFlagOn() throws Exception {
-        Assert.assertEquals(ContentSettingsType.DEFAULT, mMediator.getLastPermission());
-
-        // Prompt for location and accept it.
-        RuntimePermissionTestUtils.setupGeolocationSystemMock();
-        String[] requestablePermission = new String[] {Manifest.permission.ACCESS_COARSE_LOCATION,
-                Manifest.permission.ACCESS_FINE_LOCATION};
-        RuntimePermissionTestUtils.TestAndroidPermissionDelegate testAndroidPermissionDelegate =
-                new RuntimePermissionTestUtils.TestAndroidPermissionDelegate(requestablePermission,
-                        RuntimePermissionTestUtils.RuntimePromptResponse.GRANT);
-        RuntimePermissionTestUtils.runTest(mPermissionTestRule, testAndroidPermissionDelegate,
-                GEOLOCATION_TEST, true /* expectPermissionAllowed */,
-                true /* permissionPromptAllow */, false /* waitForMissingPermissionPrompt */,
-                true /* waitForUpdater */, null /* javascriptToExecute */,
-                0 /* missingPermissionPromptTextId */);
-
-        Assert.assertEquals(ContentSettingsType.GEOLOCATION, mMediator.getLastPermission());
-    }
-
+    /**
+     * Tests no omnibox permission with flag off.
+     */
     @Test
     @MediumTest
     @Feature({"PageInfoDiscoverability"})
@@ -133,4 +113,56 @@
 
         Assert.assertEquals(ContentSettingsType.DEFAULT, mMediator.getLastPermission());
     }
+
+    /**
+     * Tests omnibox permission when permission is allowed by the user.
+     */
+    @Test
+    @MediumTest
+    @Feature({"PageInfoDiscoverability"})
+    @EnableFeatures({PageInfoFeatureList.PAGE_INFO_DISCOVERABILITY})
+    public void testPageInfoDiscoverabilityAllowPrompt() throws Exception {
+        Assert.assertEquals(ContentSettingsType.DEFAULT, mMediator.getLastPermission());
+
+        // Prompt for location and accept it.
+        RuntimePermissionTestUtils.setupGeolocationSystemMock();
+        String[] requestablePermission = new String[] {Manifest.permission.ACCESS_COARSE_LOCATION,
+                Manifest.permission.ACCESS_FINE_LOCATION};
+        RuntimePermissionTestUtils.TestAndroidPermissionDelegate testAndroidPermissionDelegate =
+                new RuntimePermissionTestUtils.TestAndroidPermissionDelegate(requestablePermission,
+                        RuntimePermissionTestUtils.RuntimePromptResponse.GRANT);
+        RuntimePermissionTestUtils.runTest(mPermissionTestRule, testAndroidPermissionDelegate,
+                GEOLOCATION_TEST, true /* expectPermissionAllowed */,
+                true /* permissionPromptAllow */, false /* waitForMissingPermissionPrompt */,
+                true /* waitForUpdater */, null /* javascriptToExecute */,
+                0 /* missingPermissionPromptTextId */);
+
+        Assert.assertEquals(ContentSettingsType.GEOLOCATION, mMediator.getLastPermission());
+    }
+
+    /**
+     * Tests omnibox permission when permission is blocked by the user.
+     */
+    @Test
+    @MediumTest
+    @Feature({"PageInfoDiscoverability"})
+    @EnableFeatures({PageInfoFeatureList.PAGE_INFO_DISCOVERABILITY})
+    public void testPageInfoDiscoverabilityBlockPrompt() throws Exception {
+        Assert.assertEquals(ContentSettingsType.DEFAULT, mMediator.getLastPermission());
+
+        // Prompt for location and deny it.
+        RuntimePermissionTestUtils.setupGeolocationSystemMock();
+        String[] requestablePermission = new String[] {Manifest.permission.ACCESS_COARSE_LOCATION,
+                Manifest.permission.ACCESS_FINE_LOCATION};
+        RuntimePermissionTestUtils.TestAndroidPermissionDelegate testAndroidPermissionDelegate =
+                new RuntimePermissionTestUtils.TestAndroidPermissionDelegate(requestablePermission,
+                        RuntimePermissionTestUtils.RuntimePromptResponse.DENY);
+        RuntimePermissionTestUtils.runTest(mPermissionTestRule, testAndroidPermissionDelegate,
+                GEOLOCATION_TEST, false /* expectPermissionAllowed */,
+                false /* permissionPromptAllow */, false /* waitForMissingPermissionPrompt */,
+                true /* waitForUpdater */, null /* javascriptToExecute */,
+                0 /* missingPermissionPromptTextId */);
+
+        Assert.assertEquals(ContentSettingsType.GEOLOCATION, mMediator.getLastPermission());
+    }
 }
\ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
index 90eba36..fc9e45d1 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
@@ -17,6 +17,7 @@
 
 import static org.hamcrest.CoreMatchers.allOf;
 import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.Matchers.not;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 
@@ -533,6 +534,22 @@
     }
 
     /**
+     * Tests PageInfo on a website with permissions and no particular row highlight.
+     */
+    @Test
+    @MediumTest
+    @Features.EnableFeatures(
+            {PageInfoFeatureList.PAGE_INFO_V2, PageInfoFeatureList.PAGE_INFO_DISCOVERABILITY})
+    public void
+    testShowWithPermissionsAndWithoutHighlight() throws IOException {
+        addSomePermissions(mTestServerRule.getServer().getURL("/"));
+        loadUrlAndOpenPageInfoWithPermission(mTestServerRule.getServer().getURL(sSimpleHtml),
+                PageInfoController.NO_HIGHLIGHTED_PERMISSION);
+        onView(withId(R.id.page_info_permissions_row))
+                .check(matches(not(hasBackgroundColor(R.color.iph_highlight_blue))));
+    }
+
+    /**
      * Tests PageInfo on a website with permissions and a particular permission row highlight.
      * Geolocation is blocked system wide in this test.
      */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderUnitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderUnitTest.java
index 42af63a..67f8ebd 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderUnitTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderUnitTest.java
@@ -15,6 +15,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -28,6 +29,8 @@
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.UiThreadTest;
 import org.chromium.base.test.util.Batch;
+import org.chromium.chrome.browser.tabmodel.TabModelSelector;
+import org.chromium.chrome.browser.tabmodel.TabModelSelectorSupplier;
 import org.chromium.chrome.test.ChromeBrowserTestRule;
 import org.chromium.components.payments.PackageManagerDelegate;
 import org.chromium.components.payments.PaymentApp;
@@ -38,8 +41,12 @@
 import org.chromium.components.payments.WebAppManifestSection;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.test.NativeLibraryTestUtils;
+import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.payments.mojom.PaymentDetailsModifier;
 import org.chromium.payments.mojom.PaymentMethodData;
+import org.chromium.ui.base.ActivityWindowAndroid;
+import org.chromium.ui.base.WindowAndroid;
+import org.chromium.ui.test.util.DummyUiActivityTestCase;
 import org.chromium.url.GURL;
 import org.chromium.url.Origin;
 
@@ -51,7 +58,7 @@
 /** Tests for the native Android payment app finder. */
 @RunWith(BaseJUnit4ClassRunner.class)
 @Batch(AndroidPaymentAppFinderUnitTest.PAYMENTS_BROWSER_UNIT_TESTS)
-public class AndroidPaymentAppFinderUnitTest {
+public class AndroidPaymentAppFinderUnitTest extends DummyUiActivityTestCase {
     // Collection of payments unit tests that require the browser process to be initialized.
     static final String PAYMENTS_BROWSER_UNIT_TESTS = "PaymentsBrowserUnitTests";
     private static final IntentArgumentMatcher sPayIntentArgumentMatcher =
@@ -69,13 +76,23 @@
     @Mock
     private PackageManagerDelegate mPackageManagerDelegate;
 
+    private WindowAndroid mWindowAndroid;
+
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
+        mWindowAndroid = TestThreadUtils.runOnUiThreadBlockingNoException(
+                () -> { return new ActivityWindowAndroid(getActivity()); });
+
         NativeLibraryTestUtils.loadNativeLibraryAndInitBrowserProcess();
     }
 
+    @After
+    public void tearDown() throws Exception {
+        TestThreadUtils.runOnUiThreadBlocking(() -> { mWindowAndroid.destroy(); });
+    }
+
     /**
      * Argument matcher that matches Intents using |filterEquals| method.
      */
@@ -108,7 +125,12 @@
             methodData.put(methodName, data);
         }
         PaymentAppFactoryParams params = Mockito.mock(PaymentAppFactoryParams.class);
-        Mockito.when(params.getWebContents()).thenReturn(Mockito.mock(WebContents.class));
+        WebContents webContents = Mockito.mock(WebContents.class);
+        TabModelSelector tabModelSelector = Mockito.mock(TabModelSelector.class);
+        TabModelSelectorSupplier.setInstanceForTesting(tabModelSelector);
+        Mockito.when(tabModelSelector.isIncognitoSelected()).thenReturn(false);
+        Mockito.when(webContents.getTopLevelNativeWindow()).thenReturn(mWindowAndroid);
+        Mockito.when(params.getWebContents()).thenReturn(webContents);
         Mockito.when(params.getId()).thenReturn("id");
         Mockito.when(params.getMethodData()).thenReturn(methodData);
         Mockito.when(params.getTopLevelOrigin()).thenReturn("https://chromium.org");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/RuntimePermissionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/RuntimePermissionTest.java
index 873890d..6f77ffd 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/RuntimePermissionTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/RuntimePermissionTest.java
@@ -23,6 +23,7 @@
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.permissions.RuntimePermissionTestUtils.RuntimePromptResponse;
 import org.chromium.chrome.browser.permissions.RuntimePermissionTestUtils.TestAndroidPermissionDelegate;
+import org.chromium.chrome.browser.profiles.ProfileKey;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.components.offline_items_collection.ContentId;
 import org.chromium.components.permissions.R;
@@ -153,11 +154,11 @@
         DownloadObserver observer = new DownloadObserver() {
             @Override
             public void onAllDownloadsRetrieved(
-                    final List<DownloadItem> list, boolean isOffTheRecord) {}
+                    final List<DownloadItem> list, ProfileKey profileKey) {}
             @Override
             public void onDownloadItemUpdated(DownloadItem item) {}
             @Override
-            public void onDownloadItemRemoved(String guid, boolean isOffTheRecord) {}
+            public void onDownloadItemRemoved(String guid) {}
             @Override
             public void onAddOrReplaceDownloadSharedPreferenceEntry(ContentId id) {}
 
diff --git a/chrome/android/modules/buildflags.gni b/chrome/android/modules/buildflags.gni
index fc75cbfe..5cb4983 100644
--- a/chrome/android/modules/buildflags.gni
+++ b/chrome/android/modules/buildflags.gni
@@ -7,23 +7,6 @@
 import("//build/config/compiler/compiler.gni")
 import("//device/vr/buildflags/buildflags.gni")
 
-declare_args() {
-  # Whether //chrome code and resources are in a DFM for Monochrome and
-  # Trichrome bundles. This module will also include code and resources from all
-  # other DFMs.
-  enable_chrome_module = true
-
-  # Whether to enable DFMs which depend on the chrome DFM. These will be split
-  # out of the chrome DFM using DexSplitter.
-  enable_chrome_child_modules = true
-}
-
-declare_args() {
-  # Whether isolated splits are enabled. This can be enabled/disabled separately
-  # from enable_chrome_module to test performance in various configurations.
-  enable_isolated_splits = enable_chrome_module
-}
-
 # If true, lld is used to partition feature code into separate libraries, which
 # in turn are included in Dynamic Feature Modules.
 use_native_partitions = is_android && is_clang && use_lld && !is_component_build
diff --git a/chrome/android/modules/chrome_bundle_tmpl.gni b/chrome/android/modules/chrome_bundle_tmpl.gni
index 031b806..4dccca4 100644
--- a/chrome/android/modules/chrome_bundle_tmpl.gni
+++ b/chrome/android/modules/chrome_bundle_tmpl.gni
@@ -23,8 +23,7 @@
   _package_id = 126  # == 0x7e.
   _extra_modules = []
   _module_descs = invoker.module_descs
-  _enable_chrome_module =
-      enable_chrome_module && invoker.is_monochrome_or_trichrome
+  _enable_chrome_module = invoker.is_monochrome_or_trichrome
 
   # If enable_chrome_module is true, //chrome Java code and resources will be
   # split out into a chrome DFM in Monochrome and Trichrome bundles. This will
@@ -55,9 +54,7 @@
     _module_descs += [ chrome_module_desc ]
   }
 
-  _enable_isolated_splits =
-      enable_isolated_splits && invoker.is_monochrome_or_trichrome
-  if (_enable_isolated_splits) {
+  if (invoker.is_monochrome_or_trichrome) {
     # TODO(crbug.com/1126301): Isolated splits cause various bugs with resource
     # access. For now, move all resources to the base module.
     _base_target_name = get_label_info(invoker.base_module_target, "name")
@@ -82,7 +79,7 @@
     # "Replacing nonempty scope" error is thrown.
     _module_desc = {
     }
-    if (_enable_chrome_module && enable_chrome_child_modules) {
+    if (_enable_chrome_module) {
       _module_desc = _tmp_module_desc
     } else {
       # Remove uses_split if child modules are not enabled.
diff --git a/chrome/android/modules/chrome_feature_modules.gni b/chrome/android/modules/chrome_feature_modules.gni
index cae0d233..f5ee6de 100644
--- a/chrome/android/modules/chrome_feature_modules.gni
+++ b/chrome/android/modules/chrome_feature_modules.gni
@@ -73,6 +73,6 @@
 
 # Add this after we assign trichrome_module_descs, since WebLayer should only be
 # part of Monochrome.
-if (enable_chrome_module && webview_includes_weblayer) {
+if (webview_includes_weblayer) {
   monochrome_module_descs += [ weblayer_module_desc ]
 }
diff --git a/chrome/android/monochrome_android_manifest_jinja_variables.gni b/chrome/android/monochrome_android_manifest_jinja_variables.gni
index 7428fe7..9c2c2e08 100644
--- a/chrome/android/monochrome_android_manifest_jinja_variables.gni
+++ b/chrome/android/monochrome_android_manifest_jinja_variables.gni
@@ -10,5 +10,4 @@
   "min_sdk_version=24",
   "sandboxed_service_exported=true",
   use_32bit_abi_jinja_variable,
-  "enable_isolated_splits=$enable_isolated_splits",
 ]
diff --git a/chrome/android/proguard/isolated_splits.flags b/chrome/android/proguard/isolated_splits.flags
deleted file mode 100644
index 2a9b6c75..0000000
--- a/chrome/android/proguard/isolated_splits.flags
+++ /dev/null
@@ -1,9 +0,0 @@
-# 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.
-
-# Isolated splits currently use DexSplitter for splitting out some DFMs.
-# DexSplitter has some issues with certain R8 optimizations, so we need to keep
-# ModuleInterface classes to make sure they aren't inlined.
--keep @interface org.chromium.components.module_installer.builder.ModuleInterface
--keep @org.chromium.components.module_installer.builder.ModuleInterface class ** {}
diff --git a/chrome/android/trichrome.gni b/chrome/android/trichrome.gni
index 1186df9..27cc637 100644
--- a/chrome/android/trichrome.gni
+++ b/chrome/android/trichrome.gni
@@ -33,7 +33,6 @@
   "trichrome_library=$trichrome_library_package",
   "trichrome_certdigest=$trichrome_certdigest",
   "use32bitAbi=android:use32bitAbi=\"true\"",
-  "enable_isolated_splits=$enable_isolated_splits",
 ]
 
 trichrome_synchronized_proguard =
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index ea39061..4f63d6eb4 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -5222,6 +5222,9 @@
   <message name="IDS_PLUGIN_VM_START_VM_ERROR_TITLE" desc="Title in the notification shown when launching the 'Plugin VM' app failed due to a network or unknown error.">
     Couldn't open <ph name="APP_NAME">$1<ex>Plugin VM</ex></ph>
   </message>
+  <message name="IDS_PLUGIN_VM_START_VM_INSUFFICIENT_DISK_SPACE_ERROR_MESSAGE" desc="Message in the error dialog shown when launching Parallels Desktop fails due to insufficient disk space.">
+    Disk space is critically low. Free up disk space and try again.
+  </message>
   <message name="IDS_PLUGIN_VM_NETWORK_ERROR_MESSAGE" desc="Message in the notification shown when launching the 'Plugin VM' app failed due to a network error.">
     Connect to the internet and try again
   </message>
diff --git a/chrome/app/chromeos_strings_grdp/IDS_PLUGIN_VM_START_VM_INSUFFICIENT_DISK_SPACE_ERROR_MESSAGE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_PLUGIN_VM_START_VM_INSUFFICIENT_DISK_SPACE_ERROR_MESSAGE.png.sha1
new file mode 100644
index 0000000..baf19adf
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_PLUGIN_VM_START_VM_INSUFFICIENT_DISK_SPACE_ERROR_MESSAGE.png.sha1
@@ -0,0 +1 @@
+01393bc928ef20d127064f98237b63d0976a489f
\ No newline at end of file
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index 716c7eff8..b0a9f00 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -302,9 +302,6 @@
       <message name="IDS_ABOUT_TERMS_OF_SERVICE" desc="The terms of service label in the About box." translateable="false">
         Not used in Chromium. Placeholder to keep resource maps in sync.
       </message>
-      <message name="IDS_CPU_X86_SSE2_OBSOLETE_SOON" desc="A message displayed on an at-launch infobar and About (Help) page warning the user that the computer they are using will soon be or is already unsupported.">
-        This computer will soon stop receiving Chromium updates because its hardware is no longer supported.
-      </message>
       <if expr="is_macosx">
         <message name="IDS_MAC_10_10_OBSOLETE_SOON" desc="A message displayed on an at-launch infobar and About (Help) page warning the user that the OS version they are using will soon be or is already unsupported.">
           To get future Chromium updates, you'll need OS X 10.11 or later. This computer is using OS X 10.10.
diff --git a/chrome/app/chromium_strings_grd/IDS_CPU_X86_SSE2_OBSOLETE_SOON.png.sha1 b/chrome/app/chromium_strings_grd/IDS_CPU_X86_SSE2_OBSOLETE_SOON.png.sha1
deleted file mode 100644
index c31f784..0000000
--- a/chrome/app/chromium_strings_grd/IDS_CPU_X86_SSE2_OBSOLETE_SOON.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-a0d88718e2f147504d28f0c417348a4d70db0aef
\ No newline at end of file
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 1afb22d..26a9e7a 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -9820,6 +9820,9 @@
       <message name="IDS_DESKTOP_MEDIA_PICKER_MULTIPLE_SCREEN_NAME" desc="Name for screens in the desktop media picker UI when there are multiple monitors.">
         {SCREEN_INDEX, plural, =1{Screen #} other{Screen #}}
       </message>
+      <message name="IDS_DESKTOP_MEDIA_PRESENTER_TOOLS" desc="Text for the checkbox on window picker dialog, when checked the presenter tools will be shown.">
+        Presenter Tools
+      </message>
       <if expr="toolkit_views">
         <message name="IDS_DESKTOP_MEDIA_PICKER_SOURCE_TYPE_THIS_TAB" desc="Text for one of the dialog-tabs on the media picker dialog. This dialog-tab controls sharing the current tab.">
           This Tab
diff --git a/chrome/app/generated_resources_grd/IDS_DESKTOP_MEDIA_PRESENTER_TOOLS.png.sha1 b/chrome/app/generated_resources_grd/IDS_DESKTOP_MEDIA_PRESENTER_TOOLS.png.sha1
new file mode 100644
index 0000000..f901b3d
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_DESKTOP_MEDIA_PRESENTER_TOOLS.png.sha1
@@ -0,0 +1 @@
+3e57c68c4a76ecccc8037a51cd2a3c4fbc5d0648
\ No newline at end of file
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index 1ae19e8..6e262a25 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -308,9 +308,6 @@
       <message name="IDS_ABOUT_TERMS_OF_SERVICE" desc="The terms of service label in the About box.">
         Terms of Service
       </message>
-      <message name="IDS_CPU_X86_SSE2_OBSOLETE_SOON" desc="A message displayed on an at-launch infobar and About (Help) page warning the user that the computer they are using will soon be or is already unsupported.">
-        This computer will soon stop receiving Google Chrome updates because its hardware is no longer supported.
-      </message>
       <if expr="is_macosx">
         <message name="IDS_MAC_10_10_OBSOLETE_SOON" desc="A message displayed on an at-launch infobar and About (Help) page warning the user that the OS version they are using will soon be or is already unsupported.">
           To get future Google Chrome updates, you'll need OS X 10.11 or later. This computer is using OS X 10.10.
diff --git a/chrome/app/google_chrome_strings_grd/IDS_CPU_X86_SSE2_OBSOLETE_SOON.png.sha1 b/chrome/app/google_chrome_strings_grd/IDS_CPU_X86_SSE2_OBSOLETE_SOON.png.sha1
deleted file mode 100644
index 6f544d5a..0000000
--- a/chrome/app/google_chrome_strings_grd/IDS_CPU_X86_SSE2_OBSOLETE_SOON.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-3223a40ccdf0dc64119f047104c5e47b889d2bc9
\ No newline at end of file
diff --git a/chrome/browser/android/bookmarks/partner_bookmarks_reader.cc b/chrome/browser/android/bookmarks/partner_bookmarks_reader.cc
index 58b43a1..fbf0bc9 100644
--- a/chrome/browser/android/bookmarks/partner_bookmarks_reader.cc
+++ b/chrome/browser/android/bookmarks/partner_bookmarks_reader.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/android/bookmarks/partner_bookmarks_reader.h"
 
+#include <utility>
+
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
 #include "base/bind.h"
@@ -267,9 +269,8 @@
   GetLargeIconService()->GetLargeIconRawBitmapOrFallbackStyleForPageUrl(
       page_url, kPartnerBookmarksMinimumFaviconSizePx, desired_favicon_size_px,
       base::BindOnce(&PartnerBookmarksReader::OnGetFaviconFromCacheFinished,
-                     base::Unretained(this), page_url,
-                     base::Passed(std::move(callback)), fallback_to_server,
-                     from_server, desired_favicon_size_px),
+                     base::Unretained(this), page_url, std::move(callback),
+                     fallback_to_server, from_server, desired_favicon_size_px),
       &favicon_task_tracker_);
 }
 
@@ -326,7 +327,7 @@
           base::BindOnce(
               &PartnerBookmarksReader::OnGetFaviconFromServerFinished,
               base::Unretained(this), page_url, desired_favicon_size_px,
-              base::Passed(std::move(callback))));
+              std::move(callback)));
 }
 
 void PartnerBookmarksReader::OnGetFaviconFromServerFinished(
diff --git a/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/BrowserServicesIntentDataProvider.java b/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/BrowserServicesIntentDataProvider.java
index 12d618c..df7bf30 100644
--- a/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/BrowserServicesIntentDataProvider.java
+++ b/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/BrowserServicesIntentDataProvider.java
@@ -480,11 +480,6 @@
         return getUiType() == CustomTabsUiType.INFO_PAGE;
     }
 
-    @Nullable
-    public PendingIntent getFocusIntent() {
-        return null;
-    }
-
     @TwaDisclosureUi
     public int getTwaDisclosureUi() {
         return TwaDisclosureUi.DEFAULT;
diff --git a/chrome/browser/android/context_menu/context_menu_native_delegate_impl.cc b/chrome/browser/android/context_menu/context_menu_native_delegate_impl.cc
index eed4560..5cddffd 100644
--- a/chrome/browser/android/context_menu/context_menu_native_delegate_impl.cc
+++ b/chrome/browser/android/context_menu/context_menu_native_delegate_impl.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/android/context_menu/context_menu_native_delegate_impl.h"
 
+#include <utility>
+
 #include "base/android/callback_android.h"
 #include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
@@ -169,7 +171,7 @@
       max_width_px * max_height_px, gfx::Size(max_width_px, max_height_px),
       image_format,
       base::BindOnce(
-          std::move(retrieve_callback), base::Passed(&chrome_render_frame),
+          std::move(retrieve_callback), std::move(chrome_render_frame),
           base::android::ScopedJavaGlobalRef<jobject>(env, jcallback)));
 }
 
diff --git a/chrome/browser/android/customtabs/detached_resource_request.cc b/chrome/browser/android/customtabs/detached_resource_request.cc
index 1131220c..f8de4e5 100644
--- a/chrome/browser/android/customtabs/detached_resource_request.cc
+++ b/chrome/browser/android/customtabs/detached_resource_request.cc
@@ -133,7 +133,6 @@
   resource_request->resource_type =
       static_cast<int>(blink::mojom::ResourceType::kSubResource);
   resource_request->do_not_prompt_for_login = true;
-  resource_request->render_frame_id = -1;
   resource_request->enable_load_timing = false;
   resource_request->report_raw_headers = false;
 
diff --git a/chrome/browser/android/feature_engagement/tracker_factory_android.cc b/chrome/browser/android/feature_engagement/tracker_factory_android.cc
index 8b48d02a..e7ddcea 100644
--- a/chrome/browser/android/feature_engagement/tracker_factory_android.cc
+++ b/chrome/browser/android/feature_engagement/tracker_factory_android.cc
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/android/scoped_java_ref.h"
-#include "chrome/android/chrome_jni_headers/TrackerFactory_jni.h"
+#include "chrome/browser/feature_engagement/jni_headers/TrackerFactory_jni.h"
 #include "chrome/browser/feature_engagement/tracker_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_android.h"
diff --git a/chrome/browser/android/vr/autocomplete_controller.cc b/chrome/browser/android/vr/autocomplete_controller.cc
index bb3505d..fd980e9 100644
--- a/chrome/browser/android/vr/autocomplete_controller.cc
+++ b/chrome/browser/android/vr/autocomplete_controller.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/android/vr/autocomplete_controller.h"
 
 #include <string>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/strings/string_util.h"
@@ -97,8 +98,8 @@
   suggestions_timeout_.Cancel();
 
   if (suggestions.size() < kMaxNumberOfSuggestions) {
-    suggestions_timeout_.Reset(base::BindOnce(
-        suggestion_callback_, base::Passed(std::move(suggestions))));
+    suggestions_timeout_.Reset(
+        base::BindOnce(suggestion_callback_, std::move(suggestions)));
     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE, suggestions_timeout_.callback(),
         base::TimeDelta::FromMilliseconds(kSuggestionThrottlingDelayMs));
diff --git a/chrome/browser/android/vr/register_jni_monochrome.cc b/chrome/browser/android/vr/register_jni_monochrome.cc
index 66f7c93..53636c3c 100644
--- a/chrome/browser/android/vr/register_jni_monochrome.cc
+++ b/chrome/browser/android/vr/register_jni_monochrome.cc
@@ -9,10 +9,8 @@
 namespace vr {
 
 bool RegisterJni(JNIEnv* env) {
-  // The GVR Java code is normally in the vr DFM, which will be loaded into the
-  // base class loader. If the enable_chrome_module gn arg is enabled, the GVR
-  // Java code will be in the chrome DFM, which is loaded as an isolated split.
-  // This means the Java code is no longer automatically loaded in the base
+  // The GVR Java code will be in the vr DFM, which is loaded as an isolated
+  // split.  This means the Java code is not automatically loaded in the base
   // class loader. Automatic JNI registration only works for native methods
   // associated with the base class loader (which loaded libmonochrome.so, so
   // will look for symbols there). Most of Chrome's native methods are in
diff --git a/chrome/browser/android/webapk/webapk_install_service.cc b/chrome/browser/android/webapk/webapk_install_service.cc
index db580e4..124cc692 100644
--- a/chrome/browser/android/webapk/webapk_install_service.cc
+++ b/chrome/browser/android/webapk/webapk_install_service.cc
@@ -57,7 +57,7 @@
   WebApkInstaller::InstallAsync(
       browser_context_, shortcut_info, primary_icon, is_primary_icon_maskable,
       base::BindOnce(&WebApkInstallService::OnFinishedInstall,
-                     weak_ptr_factory_.GetWeakPtr(), base::Passed(&observer),
+                     weak_ptr_factory_.GetWeakPtr(), std::move(observer),
                      shortcut_info, primary_icon, is_primary_icon_maskable));
 }
 
diff --git a/chrome/browser/apps/app_service/borealis_apps.cc b/chrome/browser/apps/app_service/borealis_apps.cc
index 228dc88..dbd1197 100644
--- a/chrome/browser/apps/app_service/borealis_apps.cc
+++ b/chrome/browser/apps/app_service/borealis_apps.cc
@@ -198,16 +198,6 @@
     AddCommandItem(ash::UNINSTALL, IDS_APP_LIST_UNINSTALL_ITEM, &menu_items);
   }
 
-  // TODO(b/170677773): Show shutdown in another app.
-  if (app_id == borealis::kBorealisAppId &&
-      borealis::BorealisService::GetForProfile(profile_)
-          ->ContextManager()
-          .IsRunning()) {
-    // TODO(b/174705762): Use borealis-specific strings.
-    AddCommandItem(ash::SHUTDOWN_GUEST_OS, IDS_PLUGIN_VM_SHUT_DOWN_MENU_ITEM,
-                   &menu_items);
-  }
-
   if (ShouldAddCloseItem(app_id, menu_type, profile_)) {
     AddCommandItem(ash::MENU_CLOSE, IDS_SHELF_CONTEXT_MENU_CLOSE, &menu_items);
   }
diff --git a/chrome/browser/ash/account_manager/account_manager_migrator.cc b/chrome/browser/ash/account_manager/account_manager_migrator.cc
index bee59a8..1e3288a8 100644
--- a/chrome/browser/ash/account_manager/account_manager_migrator.cc
+++ b/chrome/browser/ash/account_manager/account_manager_migrator.cc
@@ -22,6 +22,7 @@
 #include "base/sequence_checker.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
+#include "chrome/browser/account_manager_facade_factory.h"
 #include "chrome/browser/ash/account_manager/account_manager_util.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/browser_process.h"
@@ -37,6 +38,7 @@
 #include "chrome/common/pref_names.h"
 #include "components/account_id/account_id.h"
 #include "components/account_manager_core/account.h"
+#include "components/account_manager_core/account_manager_facade.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/core/browser/account_reconcilor.h"
@@ -87,11 +89,14 @@
 // to Account Manager.
 class AccountMigrationBaseStep : public AccountMigrationRunner::Step {
  public:
-  AccountMigrationBaseStep(const std::string& id,
-                           AccountManager* account_manager,
-                           signin::IdentityManager* identity_manager)
+  AccountMigrationBaseStep(
+      const std::string& id,
+      AccountManager* account_manager,
+      account_manager::AccountManagerFacade* account_manager_facade,
+      signin::IdentityManager* identity_manager)
       : AccountMigrationRunner::Step(id),
         account_manager_(account_manager),
+        account_manager_facade_(account_manager_facade),
         identity_manager_(identity_manager) {}
   ~AccountMigrationBaseStep() override = default;
 
@@ -136,7 +141,7 @@
   // must call either of |Step::FinishWithSuccess| or |Step::FinishWithFailure|
   // when done.
   void Run() final {
-    account_manager_->GetAccounts(base::BindOnce(
+    account_manager_facade_->GetAccounts(base::BindOnce(
         &AccountMigrationBaseStep::OnGetAccounts, weak_factory_.GetWeakPtr()));
   }
 
@@ -151,6 +156,8 @@
 
   // A non-owning pointer to Account Manager.
   AccountManager* const account_manager_;
+  // A non-owning pointer.
+  account_manager::AccountManagerFacade* const account_manager_facade_;
 
   // Non-owning pointer.
   signin::IdentityManager* const identity_manager_;
@@ -168,13 +175,16 @@
 class DeviceAccountMigration : public AccountMigrationBaseStep,
                                public WebDataServiceConsumer {
  public:
-  DeviceAccountMigration(const ::account_manager::AccountKey& device_account,
-                         const std::string& device_account_raw_email,
-                         AccountManager* account_manager,
-                         signin::IdentityManager* identity_manager,
-                         scoped_refptr<TokenWebData> token_web_data)
+  DeviceAccountMigration(
+      const ::account_manager::AccountKey& device_account,
+      const std::string& device_account_raw_email,
+      AccountManager* account_manager,
+      account_manager::AccountManagerFacade* account_manager_facade,
+      signin::IdentityManager* identity_manager,
+      scoped_refptr<TokenWebData> token_web_data)
       : AccountMigrationBaseStep(kDeviceAccountMigration,
                                  account_manager,
+                                 account_manager_facade,
                                  identity_manager),
         token_web_data_(token_web_data),
         device_account_(device_account),
@@ -292,10 +302,14 @@
 class ContentAreaAccountsMigration : public AccountMigrationBaseStep,
                                      signin::IdentityManager::Observer {
  public:
-  ContentAreaAccountsMigration(AccountManager* account_manager,
-                               signin::IdentityManager* identity_manager)
+  ContentAreaAccountsMigration(
+      AccountManager* account_manager,
+      account_manager::AccountManagerFacade* account_manager_facade,
+
+      signin::IdentityManager* identity_manager)
       : AccountMigrationBaseStep(kContentAreaAccountsMigration,
                                  account_manager,
+                                 account_manager_facade,
                                  identity_manager),
         identity_manager_(identity_manager) {}
   ~ContentAreaAccountsMigration() override {
@@ -363,12 +377,15 @@
 class ArcAccountsMigration : public AccountMigrationBaseStep,
                              public arc::ArcSessionManagerObserver {
  public:
-  ArcAccountsMigration(AccountManager* account_manager,
-                       signin::IdentityManager* identity_manager,
-                       arc::ArcAuthService* arc_auth_service)
+  ArcAccountsMigration(
+      AccountManager* account_manager,
+      account_manager::AccountManagerFacade* account_manager_facade,
+      signin::IdentityManager* identity_manager,
+      arc::ArcAuthService* arc_auth_service)
       : AccountMigrationBaseStep(
             AccountManagerMigrator::kArcAccountsMigrationId,
             account_manager,
+            account_manager_facade,
             identity_manager),
         arc_auth_service_(arc_auth_service) {}
   ~ArcAccountsMigration() override { Reset(); }
@@ -556,13 +573,15 @@
       factory->GetAccountManager(profile_->GetPath().value());
   signin::IdentityManager* identity_manager =
       IdentityManagerFactory::GetForProfile(profile_);
+  auto* account_manager_facade =
+      ::GetAccountManagerFacade(profile_->GetPath().value());
 
   migration_runner_->AddStep(std::make_unique<DeviceAccountMigration>(
       GetDeviceAccount(profile_),
       ProfileHelper::Get()
           ->GetUserByProfile(profile_)
           ->display_email() /* device_account_raw_email */,
-      account_manager, identity_manager,
+      account_manager, account_manager_facade, identity_manager,
       WebDataServiceFactory::GetTokenWebDataForProfile(
           profile_, ServiceAccessType::EXPLICIT_ACCESS) /* token_web_data */));
 
@@ -572,14 +591,14 @@
 
   if (is_secondary_google_account_signin_allowed) {
     migration_runner_->AddStep(std::make_unique<ContentAreaAccountsMigration>(
-        account_manager, identity_manager));
+        account_manager, account_manager_facade, identity_manager));
 
     if (arc::IsArcProvisioned(profile_)) {
       // Add a migration step for ARC only if ARC has been provisioned. If ARC
       // has not been provisioned yet, there cannot be any accounts that need to
       // be migrated.
       migration_runner_->AddStep(std::make_unique<ArcAccountsMigration>(
-          account_manager, identity_manager,
+          account_manager, account_manager_facade, identity_manager,
           arc::ArcAuthService::GetForBrowserContext(
               profile_) /* arc_auth_service */));
     } else {
diff --git a/chrome/browser/ash/crosapi/browser_util.cc b/chrome/browser/ash/crosapi/browser_util.cc
index 1e70045..6251c44 100644
--- a/chrome/browser/ash/crosapi/browser_util.cc
+++ b/chrome/browser/ash/crosapi/browser_util.cc
@@ -40,7 +40,6 @@
 #include "components/user_manager/user_manager.h"
 #include "components/user_manager/user_type.h"
 #include "components/version_info/channel.h"
-#include "media/capture/mojom/video_capture.mojom.h"
 #include "mojo/public/cpp/platform/platform_channel.h"
 #include "mojo/public/cpp/system/invitation.h"
 
@@ -194,7 +193,7 @@
 
 base::flat_map<base::Token, uint32_t> GetInterfaceVersions() {
   static_assert(
-      crosapi::mojom::Crosapi::Version_ == 18,
+      crosapi::mojom::Crosapi::Version_ == 17,
       "if you add a new crosapi, please add it to the version map here");
   InterfaceVersions versions;
   AddVersion<chromeos::sensors::mojom::SensorHalClient>(&versions);
@@ -217,7 +216,6 @@
   AddVersion<crosapi::mojom::SnapshotCapturer>(&versions);
   AddVersion<crosapi::mojom::TestController>(&versions);
   AddVersion<crosapi::mojom::UrlHandler>(&versions);
-  AddVersion<crosapi::mojom::VideoCaptureDeviceFactory>(&versions);
   AddVersion<device::mojom::HidConnection>(&versions);
   AddVersion<device::mojom::HidManager>(&versions);
   AddVersion<media_session::mojom::MediaControllerManager>(&versions);
diff --git a/chrome/browser/ash/crosapi/crosapi_ash.cc b/chrome/browser/ash/crosapi/crosapi_ash.cc
index e6a3368..0d897ad 100644
--- a/chrome/browser/ash/crosapi/crosapi_ash.cc
+++ b/chrome/browser/ash/crosapi/crosapi_ash.cc
@@ -27,7 +27,6 @@
 #include "chrome/browser/ash/crosapi/select_file_ash.h"
 #include "chrome/browser/ash/crosapi/test_controller_ash.h"
 #include "chrome/browser/ash/crosapi/url_handler_ash.h"
-#include "chrome/browser/ash/crosapi/video_capture_device_factory_ash.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
@@ -66,9 +65,7 @@
       screen_manager_ash_(std::make_unique<ScreenManagerAsh>()),
       select_file_ash_(std::make_unique<SelectFileAsh>()),
       test_controller_ash_(std::make_unique<TestControllerAsh>()),
-      url_handler_ash_(std::make_unique<UrlHandlerAsh>()),
-      video_capture_device_factory_ash_(
-          std::make_unique<VideoCaptureDeviceFactoryAsh>()) {
+      url_handler_ash_(std::make_unique<UrlHandlerAsh>()) {
   receiver_set_.set_disconnect_handler(base::BindRepeating(
       &CrosapiAsh::OnDisconnected, weak_factory_.GetWeakPtr()));
 }
@@ -231,11 +228,6 @@
       ->BindMachineLearningService(std::move(receiver));
 }
 
-void CrosapiAsh::BindVideoCaptureDeviceFactory(
-    mojo::PendingReceiver<mojom::VideoCaptureDeviceFactory> receiver) {
-  video_capture_device_factory_ash_->BindReceiver(std::move(receiver));
-}
-
 void CrosapiAsh::OnBrowserStartup(mojom::BrowserInfoPtr browser_info) {
   BrowserManager::Get()->set_browser_version(browser_info->browser_version);
 }
diff --git a/chrome/browser/ash/crosapi/crosapi_ash.h b/chrome/browser/ash/crosapi/crosapi_ash.h
index 9c11fdf6..ac15958 100644
--- a/chrome/browser/ash/crosapi/crosapi_ash.h
+++ b/chrome/browser/ash/crosapi/crosapi_ash.h
@@ -32,7 +32,6 @@
 class SelectFileAsh;
 class TestControllerAsh;
 class UrlHandlerAsh;
-class VideoCaptureDeviceFactoryAsh;
 
 // Implementation of Crosapi in Ash. It provides a set of APIs that
 // crosapi clients, such as lacros-chrome, can call into.
@@ -96,9 +95,6 @@
       mojo::PendingReceiver<
           chromeos::machine_learning::mojom::MachineLearningService> receiver)
       override;
-  void BindVideoCaptureDeviceFactory(
-      mojo::PendingReceiver<mojom::VideoCaptureDeviceFactory> receiver)
-      override;
 
   BrowserServiceHostAsh* browser_service_host_ash() {
     return browser_service_host_ash_.get();
@@ -123,8 +119,6 @@
   std::unique_ptr<SelectFileAsh> select_file_ash_;
   std::unique_ptr<TestControllerAsh> test_controller_ash_;
   std::unique_ptr<UrlHandlerAsh> url_handler_ash_;
-  std::unique_ptr<VideoCaptureDeviceFactoryAsh>
-      video_capture_device_factory_ash_;
 
   mojo::ReceiverSet<mojom::Crosapi, CrosapiId> receiver_set_;
   std::map<mojo::ReceiverId, base::OnceClosure> disconnect_handler_map_;
diff --git a/chrome/browser/ash/crosapi/test_mojo_connection_manager_unittest.cc b/chrome/browser/ash/crosapi/test_mojo_connection_manager_unittest.cc
index 20196a7..a71d9a06 100644
--- a/chrome/browser/ash/crosapi/test_mojo_connection_manager_unittest.cc
+++ b/chrome/browser/ash/crosapi/test_mojo_connection_manager_unittest.cc
@@ -37,7 +37,6 @@
 #include "chromeos/startup/startup_switches.h"
 #include "components/account_id/account_id.h"
 #include "components/user_manager/fake_user_manager.h"
-#include "content/public/test/browser_task_environment.h"
 #include "mojo/public/cpp/platform/named_platform_channel.h"
 #include "mojo/public/cpp/platform/platform_channel.h"
 #include "mojo/public/cpp/platform/socket_utils_posix.h"
@@ -160,7 +159,7 @@
 
   // Use IO type to support the FileDescriptorWatcher API on POSIX.
   // TestingProfileManager instantiated below requires a TaskRunner.
-  content::BrowserTaskEnvironment task_environment{
+  base::test::TaskEnvironment task_environment{
       base::test::TaskEnvironment::MainThreadType::IO};
 
   chromeos::LoginState::Initialize();
diff --git a/chrome/browser/ash/crosapi/video_capture_device_ash.cc b/chrome/browser/ash/crosapi/video_capture_device_ash.cc
deleted file mode 100644
index 99291d1..0000000
--- a/chrome/browser/ash/crosapi/video_capture_device_ash.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2021 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/ash/crosapi/video_capture_device_ash.h"
-
-#include <memory>
-#include <utility>
-
-#include "chrome/browser/ash/crosapi/video_frame_handler_ash.h"
-
-namespace crosapi {
-
-VideoCaptureDeviceAsh::VideoCaptureDeviceAsh(
-    mojo::PendingReceiver<crosapi::mojom::VideoCaptureDevice> proxy_receiver,
-    mojo::PendingRemote<video_capture::mojom::Device> device_remote,
-    base::OnceClosure cleanup_callback)
-    : device_(std::move(device_remote)) {
-  receiver_.Bind(std::move(proxy_receiver));
-  receiver_.set_disconnect_handler(std::move(cleanup_callback));
-}
-
-VideoCaptureDeviceAsh::~VideoCaptureDeviceAsh() = default;
-
-void VideoCaptureDeviceAsh::Start(
-    const media::VideoCaptureParams& requested_settings,
-    mojo::PendingRemote<crosapi::mojom::VideoFrameHandler> proxy_handler) {
-  mojo::PendingRemote<video_capture::mojom::VideoFrameHandler> handler_remote;
-  handler_ = std::make_unique<VideoFrameHandlerAsh>(
-      handler_remote.InitWithNewPipeAndPassReceiver(),
-      std::move(proxy_handler));
-  device_->Start(std::move(requested_settings), std::move(handler_remote));
-}
-
-void VideoCaptureDeviceAsh::MaybeSuspend() {
-  device_->MaybeSuspend();
-}
-
-void VideoCaptureDeviceAsh::Resume() {
-  device_->Resume();
-}
-
-void VideoCaptureDeviceAsh::GetPhotoState(GetPhotoStateCallback callback) {
-  device_->GetPhotoState(std::move(callback));
-}
-
-void VideoCaptureDeviceAsh::SetPhotoOptions(
-    media::mojom::PhotoSettingsPtr settings,
-    SetPhotoOptionsCallback callback) {
-  device_->SetPhotoOptions(std::move(settings), std::move(callback));
-}
-
-void VideoCaptureDeviceAsh::TakePhoto(TakePhotoCallback callback) {
-  device_->TakePhoto(std::move(callback));
-}
-
-void VideoCaptureDeviceAsh::ProcessFeedback(
-    const media::VideoFrameFeedback& feedback) {
-  device_->ProcessFeedback(std::move(feedback));
-}
-
-}  // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/video_capture_device_ash.h b/chrome/browser/ash/crosapi/video_capture_device_ash.h
deleted file mode 100644
index 06dc3b66..0000000
--- a/chrome/browser/ash/crosapi/video_capture_device_ash.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2021 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_ASH_CROSAPI_VIDEO_CAPTURE_DEVICE_ASH_H_
-#define CHROME_BROWSER_ASH_CROSAPI_VIDEO_CAPTURE_DEVICE_ASH_H_
-
-#include "base/callback_forward.h"
-#include "chromeos/crosapi/mojom/video_capture.mojom.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "services/video_capture/public/mojom/device.mojom.h"
-
-namespace crosapi {
-
-class VideoFrameHandlerAsh;
-
-// It is used as a proxy to communicate between Lacros-Chrome and real
-// video_capture::Device.
-class VideoCaptureDeviceAsh : public crosapi::mojom::VideoCaptureDevice {
- public:
-  VideoCaptureDeviceAsh(
-      mojo::PendingReceiver<crosapi::mojom::VideoCaptureDevice> proxy_receiver,
-      mojo::PendingRemote<video_capture::mojom::Device> device_remote,
-      base::OnceClosure cleanup_callback);
-  VideoCaptureDeviceAsh(const VideoCaptureDeviceAsh&) = delete;
-  VideoCaptureDeviceAsh& operator=(const VideoCaptureDeviceAsh&) = delete;
-  ~VideoCaptureDeviceAsh() override;
-
- private:
-  // crosapi::mojom::Device implementation.
-  void Start(const media::VideoCaptureParams& requested_settings,
-             mojo::PendingRemote<crosapi::mojom::VideoFrameHandler>
-                 proxy_handler) override;
-  void MaybeSuspend() override;
-  void Resume() override;
-  void GetPhotoState(GetPhotoStateCallback callback) override;
-  void SetPhotoOptions(media::mojom::PhotoSettingsPtr settings,
-                       SetPhotoOptionsCallback callback) override;
-  void TakePhoto(TakePhotoCallback callback) override;
-  void ProcessFeedback(const media::VideoFrameFeedback& feedback) override;
-
-  std::unique_ptr<VideoFrameHandlerAsh> handler_;
-
-  mojo::Receiver<crosapi::mojom::VideoCaptureDevice> receiver_{this};
-
-  mojo::Remote<video_capture::mojom::Device> device_;
-};
-
-}  // namespace crosapi
-
-#endif  // CHROME_BROWSER_ASH_CROSAPI_VIDEO_CAPTURE_DEVICE_ASH_H_
diff --git a/chrome/browser/ash/crosapi/video_capture_device_factory_ash.cc b/chrome/browser/ash/crosapi/video_capture_device_factory_ash.cc
deleted file mode 100644
index 7678d55..0000000
--- a/chrome/browser/ash/crosapi/video_capture_device_factory_ash.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2021 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/ash/crosapi/video_capture_device_factory_ash.h"
-
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/notreached.h"
-#include "chrome/browser/ash/crosapi/video_capture_device_ash.h"
-#include "content/public/browser/video_capture_service.h"
-
-namespace crosapi {
-
-VideoCaptureDeviceFactoryAsh::VideoCaptureDeviceFactoryAsh() {
-  content::GetVideoCaptureService().ConnectToDeviceFactory(
-      device_factory_.BindNewPipeAndPassReceiver());
-}
-
-VideoCaptureDeviceFactoryAsh::~VideoCaptureDeviceFactoryAsh() = default;
-
-void VideoCaptureDeviceFactoryAsh::BindReceiver(
-    mojo::PendingReceiver<crosapi::mojom::VideoCaptureDeviceFactory> receiver) {
-  receivers_.Add(this, std::move(receiver));
-}
-
-void VideoCaptureDeviceFactoryAsh::GetDeviceInfos(
-    GetDeviceInfosCallback callback) {
-  device_factory_->GetDeviceInfos(std::move(callback));
-}
-
-void VideoCaptureDeviceFactoryAsh::CreateDevice(
-    const std::string& device_id,
-    mojo::PendingReceiver<crosapi::mojom::VideoCaptureDevice> device_receiver,
-    CreateDeviceCallback callback) {
-  mojo::PendingRemote<video_capture::mojom::Device> proxy_remote;
-  auto proxy_receiver = proxy_remote.InitWithNewPipeAndPassReceiver();
-  auto device_proxy = std::make_unique<VideoCaptureDeviceAsh>(
-      std::move(device_receiver), std::move(proxy_remote),
-      base::BindOnce(
-          &VideoCaptureDeviceFactoryAsh::OnClientConnectionErrorOrClose,
-          base::Unretained(this), device_id));
-
-  auto wrapped_callback = base::BindOnce(
-      [](CreateDeviceCallback callback,
-         video_capture::mojom::DeviceAccessResultCode code) {
-        crosapi::mojom::DeviceAccessResultCode crosapi_result_code;
-        switch (code) {
-          case video_capture::mojom::DeviceAccessResultCode::NOT_INITIALIZED:
-            crosapi_result_code =
-                crosapi::mojom::DeviceAccessResultCode::NOT_INITIALIZED;
-            break;
-          case video_capture::mojom::DeviceAccessResultCode::SUCCESS:
-            crosapi_result_code =
-                crosapi::mojom::DeviceAccessResultCode::SUCCESS;
-            break;
-          case video_capture::mojom::DeviceAccessResultCode::
-              ERROR_DEVICE_NOT_FOUND:
-            crosapi_result_code =
-                crosapi::mojom::DeviceAccessResultCode::ERROR_DEVICE_NOT_FOUND;
-            break;
-          default:
-            NOTREACHED() << "Unexpected device access result code";
-        }
-        std::move(callback).Run(crosapi_result_code);
-      },
-      std::move(callback));
-  devices_.emplace(device_id, std::move(device_proxy));
-  device_factory_->CreateDevice(device_id, std::move(proxy_receiver),
-                                std::move(wrapped_callback));
-}
-
-void VideoCaptureDeviceFactoryAsh::OnClientConnectionErrorOrClose(
-    const std::string& device_id) {
-  devices_.erase(device_id);
-}
-
-}  // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/video_capture_device_factory_ash.h b/chrome/browser/ash/crosapi/video_capture_device_factory_ash.h
deleted file mode 100644
index e3cfc01..0000000
--- a/chrome/browser/ash/crosapi/video_capture_device_factory_ash.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2021 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_ASH_CROSAPI_VIDEO_CAPTURE_DEVICE_FACTORY_ASH_H_
-#define CHROME_BROWSER_ASH_CROSAPI_VIDEO_CAPTURE_DEVICE_FACTORY_ASH_H_
-
-#include <string>
-
-#include "base/containers/flat_map.h"
-#include "chromeos/crosapi/mojom/video_capture.mojom.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/receiver_set.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "services/video_capture/public/mojom/device_factory.mojom.h"
-
-namespace crosapi {
-
-class VideoCaptureDeviceAsh;
-
-// This class is the ash-chrome implementation of the VideoCaptureDeviceFactory
-// interface. This class must only be used from the main thread.
-// It is used as a proxy between Lacros-Chrome and actual
-// video_capture::DeviceFactory in Ash-Chrome and also responsible for
-// translating structures between crosapi and other components.
-// (e.g. gfx, media, video_capture)
-class VideoCaptureDeviceFactoryAsh
-    : public crosapi::mojom::VideoCaptureDeviceFactory {
- public:
-  VideoCaptureDeviceFactoryAsh();
-  VideoCaptureDeviceFactoryAsh(const VideoCaptureDeviceFactoryAsh&) = delete;
-  VideoCaptureDeviceFactoryAsh& operator=(const VideoCaptureDeviceFactoryAsh&) =
-      delete;
-  ~VideoCaptureDeviceFactoryAsh() override;
-
-  void BindReceiver(
-      mojo::PendingReceiver<crosapi::mojom::VideoCaptureDeviceFactory>
-          receiver);
-
-  // crosapi::mojom::VideoCaptureDeviceFactory:
-  void GetDeviceInfos(GetDeviceInfosCallback callback) override;
-  void CreateDevice(
-      const std::string& device_id,
-      mojo::PendingReceiver<crosapi::mojom::VideoCaptureDevice> device_receiver,
-      CreateDeviceCallback callback) override;
-
- private:
-  // It will be triggered once the connection to the client of
-  // video_capture::mojom::Device in Lacros-Chrome is dropped.
-  void OnClientConnectionErrorOrClose(const std::string& device_id);
-
-  mojo::Remote<video_capture::mojom::DeviceFactory> device_factory_;
-
-  // The key is the device id used in blink::MediaStreamDevice.
-  base::flat_map<std::string, std::unique_ptr<VideoCaptureDeviceAsh>> devices_;
-
-  mojo::ReceiverSet<crosapi::mojom::VideoCaptureDeviceFactory> receivers_;
-};
-
-}  // namespace crosapi
-
-#endif  // CHROME_BROWSER_ASH_CROSAPI_VIDEO_CAPTURE_DEVICE_FACTORY_ASH_H_
diff --git a/chrome/browser/ash/crosapi/video_frame_handler_ash.cc b/chrome/browser/ash/crosapi/video_frame_handler_ash.cc
deleted file mode 100644
index f6b1b5f..0000000
--- a/chrome/browser/ash/crosapi/video_frame_handler_ash.cc
+++ /dev/null
@@ -1,177 +0,0 @@
-// Copyright 2021 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/ash/crosapi/video_frame_handler_ash.h"
-
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "base/notreached.h"
-#include "media/base/video_transformation.h"
-#include "mojo/public/cpp/bindings/self_owned_receiver.h"
-#include "mojo/public/cpp/system/buffer.h"
-#include "ui/gfx/gpu_memory_buffer.h"
-
-namespace crosapi {
-
-namespace {
-
-crosapi::mojom::ReadyFrameInBufferPtr ToCrosapiBuffer(
-    video_capture::mojom::ReadyFrameInBufferPtr buffer) {
-  auto crosapi_buffer = crosapi::mojom::ReadyFrameInBuffer::New();
-  crosapi_buffer->buffer_id = buffer->buffer_id;
-  crosapi_buffer->frame_feedback_id = buffer->frame_feedback_id;
-
-  mojo::PendingRemote<crosapi::mojom::ScopedAccessPermission> access_permission;
-  mojo::MakeSelfOwnedReceiver(
-      std::make_unique<VideoFrameHandlerAsh::AccessPermissionProxy>(
-          std::move(buffer->access_permission)),
-      access_permission.InitWithNewPipeAndPassReceiver());
-  crosapi_buffer->access_permission = std::move(access_permission);
-
-  const auto& buffer_info = buffer->frame_info;
-  auto crosapi_buffer_info = crosapi::mojom::VideoFrameInfo::New();
-  crosapi_buffer_info->timestamp = buffer_info->timestamp;
-  crosapi_buffer_info->pixel_format = buffer_info->pixel_format;
-  crosapi_buffer_info->coded_size = buffer_info->coded_size;
-  crosapi_buffer_info->visible_rect = buffer_info->visible_rect;
-
-  auto transformation = buffer_info->metadata.transformation;
-  if (transformation) {
-    crosapi::mojom::VideoRotation crosapi_rotation;
-    switch (transformation->rotation) {
-      case media::VideoRotation::VIDEO_ROTATION_0:
-        crosapi_rotation = crosapi::mojom::VideoRotation::kVideoRotation0;
-        break;
-      case media::VideoRotation::VIDEO_ROTATION_90:
-        crosapi_rotation = crosapi::mojom::VideoRotation::kVideoRotation90;
-        break;
-      case media::VideoRotation::VIDEO_ROTATION_180:
-        crosapi_rotation = crosapi::mojom::VideoRotation::kVideoRotation180;
-        break;
-      case media::VideoRotation::VIDEO_ROTATION_270:
-        crosapi_rotation = crosapi::mojom::VideoRotation::kVideoRotation270;
-        break;
-      default:
-        NOTREACHED() << "Unexpected rotation in video frame metadata";
-    }
-    crosapi_buffer_info->rotation = crosapi_rotation;
-  }
-  if (buffer_info->metadata.reference_time.has_value())
-    crosapi_buffer_info->reference_time = *buffer_info->metadata.reference_time;
-
-  crosapi_buffer->frame_info = std::move(crosapi_buffer_info);
-  return crosapi_buffer;
-}
-
-crosapi::mojom::GpuMemoryBufferHandlePtr ToCrosapiGpuMemoryBufferHandle(
-    gfx::GpuMemoryBufferHandle buffer_handle) {
-  auto crosapi_gpu_handle = crosapi::mojom::GpuMemoryBufferHandle::New();
-  crosapi_gpu_handle->id = buffer_handle.id.id;
-  crosapi_gpu_handle->offset = buffer_handle.offset;
-  crosapi_gpu_handle->stride = buffer_handle.stride;
-
-  if (buffer_handle.type == gfx::GpuMemoryBufferType::SHARED_MEMORY_BUFFER) {
-    auto crosapi_platform_handle =
-        crosapi::mojom::GpuMemoryBufferPlatformHandle::New();
-    crosapi_platform_handle->set_shared_memory_handle(
-        std::move(buffer_handle.region));
-    crosapi_gpu_handle->platform_handle = std::move(crosapi_platform_handle);
-  } else if (buffer_handle.type == gfx::GpuMemoryBufferType::NATIVE_PIXMAP) {
-    auto crosapi_platform_handle =
-        crosapi::mojom::GpuMemoryBufferPlatformHandle::New();
-    auto crosapi_native_pixmap_handle =
-        crosapi::mojom::NativePixmapHandle::New();
-    crosapi_native_pixmap_handle->planes =
-        std::move(buffer_handle.native_pixmap_handle.planes);
-    crosapi_native_pixmap_handle->modifier =
-        buffer_handle.native_pixmap_handle.modifier;
-    crosapi_platform_handle->set_native_pixmap_handle(
-        std::move(crosapi_native_pixmap_handle));
-    crosapi_gpu_handle->platform_handle = std::move(crosapi_platform_handle);
-  }
-  return crosapi_gpu_handle;
-}
-
-}  // namespace
-
-VideoFrameHandlerAsh::VideoFrameHandlerAsh(
-    mojo::PendingReceiver<video_capture::mojom::VideoFrameHandler>
-        handler_receiver,
-    mojo::PendingRemote<crosapi::mojom::VideoFrameHandler> proxy_remote)
-    : proxy_(std::move(proxy_remote)) {
-  receiver_.Bind(std::move(handler_receiver));
-}
-
-VideoFrameHandlerAsh::~VideoFrameHandlerAsh() = default;
-
-VideoFrameHandlerAsh::AccessPermissionProxy::AccessPermissionProxy(
-    mojo::PendingRemote<video_capture::mojom::ScopedAccessPermission> remote)
-    : remote_(std::move(remote)) {}
-
-VideoFrameHandlerAsh::AccessPermissionProxy::~AccessPermissionProxy() = default;
-
-void VideoFrameHandlerAsh::OnNewBuffer(
-    int buffer_id,
-    media::mojom::VideoBufferHandlePtr buffer_handle) {
-  crosapi::mojom::VideoBufferHandlePtr crosapi_handle =
-      crosapi::mojom::VideoBufferHandle::New();
-
-  if (buffer_handle->is_shared_buffer_handle()) {
-    crosapi_handle->set_shared_buffer_handle(
-        buffer_handle->get_shared_buffer_handle()->Clone(
-            mojo::SharedBufferHandle::AccessMode::READ_WRITE));
-  } else if (buffer_handle->is_gpu_memory_buffer_handle()) {
-    crosapi_handle->set_gpu_memory_buffer_handle(ToCrosapiGpuMemoryBufferHandle(
-        std::move(buffer_handle->get_gpu_memory_buffer_handle())));
-  } else {
-    NOTREACHED() << "Unexpected new buffer type";
-  }
-  proxy_->OnNewBuffer(buffer_id, std::move(crosapi_handle));
-}
-
-void VideoFrameHandlerAsh::OnFrameReadyInBuffer(
-    video_capture::mojom::ReadyFrameInBufferPtr buffer,
-    std::vector<video_capture::mojom::ReadyFrameInBufferPtr> scaled_buffers) {
-  crosapi::mojom::ReadyFrameInBufferPtr crosapi_buffer =
-      ToCrosapiBuffer(std::move(buffer));
-  std::vector<crosapi::mojom::ReadyFrameInBufferPtr> crosapi_scaled_buffers;
-  for (auto& b : scaled_buffers)
-    crosapi_scaled_buffers.push_back(ToCrosapiBuffer(std::move(b)));
-
-  proxy_->OnFrameReadyInBuffer(std::move(crosapi_buffer),
-                               std::move(crosapi_scaled_buffers));
-}
-
-void VideoFrameHandlerAsh::OnBufferRetired(int buffer_id) {
-  proxy_->OnBufferRetired(buffer_id);
-}
-
-void VideoFrameHandlerAsh::OnError(media::VideoCaptureError error) {
-  proxy_->OnError(error);
-}
-
-void VideoFrameHandlerAsh::OnFrameDropped(
-    media::VideoCaptureFrameDropReason reason) {
-  proxy_->OnFrameDropped(reason);
-}
-
-void VideoFrameHandlerAsh::OnLog(const std::string& message) {
-  proxy_->OnLog(message);
-}
-
-void VideoFrameHandlerAsh::OnStarted() {
-  proxy_->OnStarted();
-}
-
-void VideoFrameHandlerAsh::OnStartedUsingGpuDecode() {
-  proxy_->OnStartedUsingGpuDecode();
-}
-
-void VideoFrameHandlerAsh::OnStopped() {
-  proxy_->OnStopped();
-}
-
-}  // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/video_frame_handler_ash.h b/chrome/browser/ash/crosapi/video_frame_handler_ash.h
deleted file mode 100644
index 3eff969..0000000
--- a/chrome/browser/ash/crosapi/video_frame_handler_ash.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2021 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_ASH_CROSAPI_VIDEO_FRAME_HANDLER_ASH_H_
-#define CHROME_BROWSER_ASH_CROSAPI_VIDEO_FRAME_HANDLER_ASH_H_
-
-#include <vector>
-
-#include "chromeos/crosapi/mojom/video_capture.mojom.h"
-#include "media/capture/mojom/video_capture_buffer.mojom.h"
-#include "media/capture/mojom/video_capture_types.mojom.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "services/video_capture/public/mojom/scoped_access_permission.mojom.h"
-#include "services/video_capture/public/mojom/video_frame_handler.mojom.h"
-
-namespace crosapi {
-
-// It is used as a proxy to communicate between actual VideoFrameHandler on
-// Lacros-Chrome and the actual video capture device on Ash-Chrome. Since we
-// have simplified some structures in crosapi video capture interface to reduce
-// dependencies to other components, this class should also be responsible for
-// translating those structures between the interfaces.
-class VideoFrameHandlerAsh : public video_capture::mojom::VideoFrameHandler {
- public:
-  VideoFrameHandlerAsh(
-      mojo::PendingReceiver<video_capture::mojom::VideoFrameHandler>
-          handler_receiver,
-      mojo::PendingRemote<crosapi::mojom::VideoFrameHandler> proxy_remote);
-  VideoFrameHandlerAsh(const VideoFrameHandlerAsh&) = delete;
-  VideoFrameHandlerAsh& operator=(const VideoFrameHandlerAsh&) = delete;
-  ~VideoFrameHandlerAsh() override;
-
-  class AccessPermissionProxy : public crosapi::mojom::ScopedAccessPermission {
-   public:
-    AccessPermissionProxy(
-        mojo::PendingRemote<video_capture::mojom::ScopedAccessPermission>
-            remote);
-    AccessPermissionProxy(const AccessPermissionProxy&) = delete;
-    AccessPermissionProxy& operator=(const AccessPermissionProxy&) = delete;
-    ~AccessPermissionProxy() override;
-
-   private:
-    mojo::Remote<video_capture::mojom::ScopedAccessPermission> remote_;
-  };
-
- private:
-  // video_capture::mojom::VideoFrameHandler implementation.
-  void OnNewBuffer(int buffer_id,
-                   media::mojom::VideoBufferHandlePtr buffer_handle) override;
-  void OnFrameReadyInBuffer(
-      video_capture::mojom::ReadyFrameInBufferPtr buffer,
-      std::vector<video_capture::mojom::ReadyFrameInBufferPtr> scaled_buffers)
-      override;
-  void OnBufferRetired(int buffer_id) override;
-  void OnError(media::VideoCaptureError error) override;
-  void OnFrameDropped(media::VideoCaptureFrameDropReason reason) override;
-  void OnLog(const std::string& message) override;
-  void OnStarted() override;
-  void OnStartedUsingGpuDecode() override;
-  void OnStopped() override;
-
-  mojo::Receiver<video_capture::mojom::VideoFrameHandler> receiver_{this};
-
-  mojo::Remote<crosapi::mojom::VideoFrameHandler> proxy_;
-};
-
-}  // namespace crosapi
-
-#endif  // CHROME_BROWSER_ASH_CROSAPI_VIDEO_FRAME_HANDLER_ASH_H_
diff --git a/chrome/browser/ash/login/quick_unlock/pin_storage_cryptohome.cc b/chrome/browser/ash/login/quick_unlock/pin_storage_cryptohome.cc
index 306a023..45e9b171 100644
--- a/chrome/browser/ash/login/quick_unlock/pin_storage_cryptohome.cc
+++ b/chrome/browser/ash/login/quick_unlock/pin_storage_cryptohome.cc
@@ -6,7 +6,8 @@
 
 #include "ash/public/cpp/ash_pref_names.h"
 #include "base/bind.h"
-#include "base/callback_helpers.h"
+#include "base/containers/contains.h"
+#include "base/containers/flat_map.h"
 #include "base/logging.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/ash/login/quick_unlock/pin_backend.h"
@@ -46,28 +47,6 @@
                           return_code == cryptohome::MOUNT_ERROR_NONE);
 }
 
-// Checks to see if there is a KeyDefinition instance with the pin label. If
-// `require_unlocked` is true, the key must not be locked.
-void CheckCryptohomePinKey(PinStorageCryptohome::BoolCallback callback,
-                           bool require_unlocked,
-                           base::Optional<cryptohome::BaseReply> reply) {
-  const cryptohome::MountError return_code =
-      cryptohome::GetKeyDataReplyToMountError(reply);
-  if (return_code == cryptohome::MOUNT_ERROR_NONE) {
-    const std::vector<cryptohome::KeyDefinition>& key_definitions =
-        cryptohome::GetKeyDataReplyToKeyDefinitions(reply);
-    for (const cryptohome::KeyDefinition& definition : key_definitions) {
-      if (definition.label == kCryptohomePinLabel) {
-        DCHECK(definition.policy.low_entropy_credential);
-        std::move(callback).Run(!require_unlocked ||
-                                !definition.policy.auth_locked);
-        return;
-      }
-    }
-  }
-  std::move(callback).Run(false);
-}
-
 // Called after cryptohomed backend is available; used to check if the
 // cryptohome supports low entropy credentials (ie, PIN).
 void OnGetSupportedKeyPolicies(PinStorageCryptohome::BoolCallback callback,
@@ -148,9 +127,8 @@
 }
 
 PinStorageCryptohome::PinStorageCryptohome() {
-  SystemSaltGetter::Get()->GetSystemSalt(base::AdaptCallbackForRepeating(
-      base::BindOnce(&PinStorageCryptohome::OnSystemSaltObtained,
-                     weak_factory_.GetWeakPtr())));
+  SystemSaltGetter::Get()->GetSystemSalt(base::BindOnce(
+      &PinStorageCryptohome::OnSystemSaltObtained, weak_factory_.GetWeakPtr()));
 }
 
 PinStorageCryptohome::~PinStorageCryptohome() = default;
@@ -162,9 +140,9 @@
   chromeos::CryptohomeClient::Get()->GetKeyDataEx(
       cryptohome::CreateAccountIdentifierFromAccountId(account_id),
       cryptohome::AuthorizationRequest(), request,
-      base::AdaptCallbackForRepeating(
-          base::BindOnce(&CheckCryptohomePinKey, std::move(result),
-                         false /*require_unlocked*/)));
+      base::BindOnce(&PinStorageCryptohome::CheckCryptohomePinKey,
+                     weak_factory_.GetWeakPtr(), account_id, std::move(result),
+                     false /*require_unlocked*/));
 }
 
 void PinStorageCryptohome::SetPin(const UserContext& user_context,
@@ -213,9 +191,7 @@
   cryptohome::HomedirMethods::GetInstance()->AddKeyEx(
       cryptohome::Identification(user_context.GetAccountId()),
       cryptohome::CreateAuthorizationRequest(key.GetLabel(), key.GetSecret()),
-      request,
-      base::AdaptCallbackForRepeating(
-          base::BindOnce(&OnCryptohomeCallComplete, std::move(did_set))));
+      request, base::BindOnce(&OnCryptohomeCallComplete, std::move(did_set)));
 }
 
 void PinStorageCryptohome::RemovePin(const UserContext& user_context,
@@ -237,8 +213,9 @@
           user_context.GetKey()->GetLabel(),
           user_context.GetKey()->GetSecret()),
       request,
-      base::AdaptCallbackForRepeating(
-          base::BindOnce(&OnCryptohomeCallComplete, std::move(did_remove))));
+      base::BindOnce(&OnCryptohomeCallComplete, std::move(did_remove)));
+
+  can_authenticate_cache_.erase(user_context.GetAccountId());
 }
 
 void PinStorageCryptohome::OnSystemSaltObtained(
@@ -254,16 +231,49 @@
   DCHECK(system_salt_callbacks_.empty());
 }
 
+// Checks to see if there is a KeyDefinition instance with the pin label. If
+// `require_unlocked` is true, the key must not be locked.
+void PinStorageCryptohome::CheckCryptohomePinKey(
+    const AccountId& account_id,
+    PinStorageCryptohome::BoolCallback callback,
+    bool require_unlocked,
+    base::Optional<cryptohome::BaseReply> reply) {
+  const cryptohome::MountError return_code =
+      cryptohome::GetKeyDataReplyToMountError(reply);
+
+  if (return_code != cryptohome::MOUNT_ERROR_NONE) {
+    can_authenticate_cache_[account_id] = false;
+    std::move(callback).Run(false);
+  }
+
+  const std::vector<cryptohome::KeyDefinition>& key_definitions =
+      cryptohome::GetKeyDataReplyToKeyDefinitions(reply);
+  for (const cryptohome::KeyDefinition& definition : key_definitions) {
+    if (definition.label == kCryptohomePinLabel) {
+      DCHECK(definition.policy.low_entropy_credential);
+      std::move(callback).Run(!require_unlocked ||
+                              !definition.policy.auth_locked);
+      can_authenticate_cache_[account_id] = !definition.policy.auth_locked;
+      return;
+    }
+  }
+}
+
 void PinStorageCryptohome::CanAuthenticate(const AccountId& account_id,
                                            BoolCallback result) const {
+  if (base::Contains(can_authenticate_cache_, account_id)) {
+    std::move(result).Run(can_authenticate_cache_.find(account_id)->second);
+    return;
+  }
+
   cryptohome::GetKeyDataRequest request;
   request.mutable_key()->mutable_data()->set_label(kCryptohomePinLabel);
   chromeos::CryptohomeClient::Get()->GetKeyDataEx(
       cryptohome::CreateAccountIdentifierFromAccountId(account_id),
       cryptohome::AuthorizationRequest(), request,
-      base::AdaptCallbackForRepeating(
-          base::BindOnce(&CheckCryptohomePinKey, std::move(result),
-                         true /*require_unlocked*/)));
+      base::BindOnce(&PinStorageCryptohome::CheckCryptohomePinKey,
+                     weak_factory_.GetWeakPtr(), account_id, std::move(result),
+                     true /*require_unlocked*/));
 }
 
 void PinStorageCryptohome::TryAuthenticate(const AccountId& account_id,
@@ -275,8 +285,7 @@
       cryptohome::Identification(account_id),
       cryptohome::CreateAuthorizationRequest(kCryptohomePinLabel, secret),
       cryptohome::CheckKeyRequest(),
-      base::AdaptCallbackForRepeating(
-          base::BindOnce(&OnCryptohomeCallComplete, std::move(result))));
+      base::BindOnce(&OnCryptohomeCallComplete, std::move(result)));
 }
 
 }  // namespace quick_unlock
diff --git a/chrome/browser/ash/login/quick_unlock/pin_storage_cryptohome.h b/chrome/browser/ash/login/quick_unlock/pin_storage_cryptohome.h
index e4c7e470..4f9a676 100644
--- a/chrome/browser/ash/login/quick_unlock/pin_storage_cryptohome.h
+++ b/chrome/browser/ash/login/quick_unlock/pin_storage_cryptohome.h
@@ -8,8 +8,10 @@
 #include <string>
 
 #include "base/callback.h"
+#include "base/containers/flat_map.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
+#include "chromeos/dbus/cryptohome/rpc.pb.h"
 #include "chromeos/login/auth/user_context.h"
 
 class AccountId;
@@ -52,10 +54,20 @@
  private:
   void OnSystemSaltObtained(const std::string& system_salt);
 
+  void CheckCryptohomePinKey(const AccountId& account_id,
+                             PinStorageCryptohome::BoolCallback callback,
+                             bool require_unlocked,
+                             base::Optional<cryptohome::BaseReply> reply);
+
   bool salt_obtained_ = false;
   std::string system_salt_;
   std::vector<base::OnceClosure> system_salt_callbacks_;
 
+  // Caches results of CanAuthenticate calls.
+  // TODO(rsorokin): Maybe reconsider the cache if `HasStrongAuth` moved to the
+  // cryptohome side.
+  base::flat_map<AccountId, bool> can_authenticate_cache_;
+
   base::WeakPtrFactory<PinStorageCryptohome> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(PinStorageCryptohome);
diff --git a/chrome/browser/ash/login/signin/offline_signin_limiter.cc b/chrome/browser/ash/login/signin/offline_signin_limiter.cc
index b699c67..54566a2 100644
--- a/chrome/browser/ash/login/signin/offline_signin_limiter.cc
+++ b/chrome/browser/ash/login/signin/offline_signin_limiter.cc
@@ -90,7 +90,7 @@
       base::BindRepeating(&OfflineSigninLimiter::UpdateLimit,
                           base::Unretained(this)));
   // Start listening to power state.
-  base::PowerMonitor::AddObserver(this);
+  base::PowerMonitor::AddPowerSuspendObserver(this);
 
   // Start listening to session lock state
   auto* session_manager = session_manager::SessionManager::Get();
@@ -129,7 +129,7 @@
       offline_signin_limit_timer_(std::make_unique<base::OneShotTimer>()) {}
 
 OfflineSigninLimiter::~OfflineSigninLimiter() {
-  base::PowerMonitor::RemoveObserver(this);
+  base::PowerMonitor::RemovePowerSuspendObserver(this);
   auto* session_manager = session_manager::SessionManager::Get();
   if (session_manager) {
     session_manager->RemoveObserver(this);
diff --git a/chrome/browser/ash/login/signin/offline_signin_limiter.h b/chrome/browser/ash/login/signin/offline_signin_limiter.h
index 687074f..e994c3e 100644
--- a/chrome/browser/ash/login/signin/offline_signin_limiter.h
+++ b/chrome/browser/ash/login/signin/offline_signin_limiter.h
@@ -29,7 +29,7 @@
 // cached password before being forced to go through online authentication
 // against GAIA again.
 class OfflineSigninLimiter : public KeyedService,
-                             public base::PowerObserver,
+                             public base::PowerSuspendObserver,
                              public session_manager::SessionManagerObserver {
  public:
   // Called when the user successfully authenticates. `auth_flow` indicates
diff --git a/chrome/browser/ash/login/ui/webui_login_view.cc b/chrome/browser/ash/login/ui/webui_login_view.cc
index e8cc791..cdd6b57 100644
--- a/chrome/browser/ash/login/ui/webui_login_view.cc
+++ b/chrome/browser/ash/login/ui/webui_login_view.cc
@@ -132,7 +132,8 @@
   for (auto& observer : observer_list_)
     observer.OnHostDestroying();
 
-  if (observing_system_tray_focus_)
+  // TODO(crbug.com/1188526) - Improve the observation of the system tray
+  if (observing_system_tray_focus_ && LoginScreenClient::HasInstance())
     LoginScreenClient::Get()->RemoveSystemTrayFocusObserver(this);
   ChromeKeyboardControllerClient::Get()->RemoveObserver(this);
 
diff --git a/chrome/browser/ash/login/users/avatar/user_image_manager_impl.cc b/chrome/browser/ash/login/users/avatar/user_image_manager_impl.cc
index 722c7dff..70c2803 100644
--- a/chrome/browser/ash/login/users/avatar/user_image_manager_impl.cc
+++ b/chrome/browser/ash/login/users/avatar/user_image_manager_impl.cc
@@ -855,7 +855,7 @@
         FROM_HERE, base::BindOnce(base::GetDeleteFileCallback(),
                                   base::FilePath(image_path)));
   }
-  update->RemoveWithoutPathExpansion(user_id(), nullptr);
+  update->RemoveKey(user_id());
 }
 
 void UserImageManagerImpl::OnJobChangedUserImage() {
diff --git a/chrome/browser/ash/login/users/multi_profile_user_controller.cc b/chrome/browser/ash/login/users/multi_profile_user_controller.cc
index 0407da7a6..90bc655 100644
--- a/chrome/browser/ash/login/users/multi_profile_user_controller.cc
+++ b/chrome/browser/ash/login/users/multi_profile_user_controller.cc
@@ -164,7 +164,7 @@
     const std::string& user_email) {
   DictionaryPrefUpdate update(local_state_,
                               prefs::kCachedMultiProfileUserBehavior);
-  update->RemoveWithoutPathExpansion(user_email, NULL);
+  update->RemoveKey(user_email);
 }
 
 std::string MultiProfileUserController::GetCachedValue(
@@ -209,7 +209,7 @@
     // TODO(xiyuan): Remove this after M35.
     DictionaryPrefUpdate update(local_state_,
                                 prefs::kCachedMultiProfileUserBehavior);
-    update->RemoveWithoutPathExpansion(user_email, NULL);
+    update->RemoveKey(user_email);
   } else {
     const std::string behavior =
         prefs->GetString(prefs::kMultiProfileUserBehavior);
diff --git a/chrome/browser/ash/login/users/supervised_user_manager_impl.cc b/chrome/browser/ash/login/users/supervised_user_manager_impl.cc
index bad1ab6d..8959e59 100644
--- a/chrome/browser/ash/login/users/supervised_user_manager_impl.cc
+++ b/chrome/browser/ash/login/users/supervised_user_manager_impl.cc
@@ -250,7 +250,7 @@
                                           const char* key) {
   PrefService* prefs = g_browser_process->local_state();
   DictionaryPrefUpdate dict_update(prefs, key);
-  dict_update->RemoveWithoutPathExpansion(user_id, NULL);
+  dict_update->RemoveKey(user_id);
 }
 
 bool SupervisedUserManagerImpl::CheckForFirstRun(const std::string& user_id) {
diff --git a/chrome/browser/ash/plugin_vm/plugin_vm_manager_impl.cc b/chrome/browser/ash/plugin_vm/plugin_vm_manager_impl.cc
index d862467..0c3f145 100644
--- a/chrome/browser/ash/plugin_vm/plugin_vm_manager_impl.cc
+++ b/chrome/browser/ash/plugin_vm/plugin_vm_manager_impl.cc
@@ -50,6 +50,8 @@
       return PluginVmLaunchResult::kExpiredLicense;
     case PRL_ERR_JLIC_WEB_PORTAL_ACCESS_REQUIRED:
       return PluginVmLaunchResult::kNetworkError;
+    case PRL_ERR_NOT_ENOUGH_DISK_SPACE_TO_START_VM:
+      return PluginVmLaunchResult::kInsufficientDiskSpace;
     default:
       return PluginVmLaunchResult::kError;
   }
@@ -93,6 +95,11 @@
                                          app_name);
       message_id = IDS_PLUGIN_VM_NETWORK_ERROR_MESSAGE;
       break;
+    case PluginVmLaunchResult::kInsufficientDiskSpace:
+      title = l10n_util::GetStringFUTF16(IDS_PLUGIN_VM_START_VM_ERROR_TITLE,
+                                         app_name);
+      message_id = IDS_PLUGIN_VM_START_VM_INSUFFICIENT_DISK_SPACE_ERROR_MESSAGE;
+      break;
   }
 
   chrome::ShowWarningMessageBox(nullptr, std::move(title),
diff --git a/chrome/browser/ash/plugin_vm/plugin_vm_manager_impl.h b/chrome/browser/ash/plugin_vm/plugin_vm_manager_impl.h
index 19820b2..8594410 100644
--- a/chrome/browser/ash/plugin_vm/plugin_vm_manager_impl.h
+++ b/chrome/browser/ash/plugin_vm/plugin_vm_manager_impl.h
@@ -35,6 +35,7 @@
 constexpr int PRL_ERR_JLIC_WRONG_HWID = 0x80057005;
 constexpr int PRL_ERR_JLIC_LICENSE_DISABLED = 0x80057010;
 constexpr int PRL_ERR_JLIC_WEB_PORTAL_ACCESS_REQUIRED = 0x80057012;
+constexpr int PRL_ERR_NOT_ENOUGH_DISK_SPACE_TO_START_VM = 0x80000456;
 
 // The PluginVmManagerImpl is responsible for connecting to the D-Bus services
 // to manage the Plugin Vm.
diff --git a/chrome/browser/ash/plugin_vm/plugin_vm_metrics_util.h b/chrome/browser/ash/plugin_vm/plugin_vm_metrics_util.h
index 1141300..754fdfe3 100644
--- a/chrome/browser/ash/plugin_vm/plugin_vm_metrics_util.h
+++ b/chrome/browser/ash/plugin_vm/plugin_vm_metrics_util.h
@@ -23,7 +23,8 @@
   kVmMissing = 3,
   kExpiredLicense = 4,
   kNetworkError = 5,
-  kMaxValue = kNetworkError,
+  kInsufficientDiskSpace = 6,
+  kMaxValue = kInsufficientDiskSpace,
 };
 
 // These values are persisted to logs. Entries should not be renumbered and
diff --git a/chrome/browser/background/background_mode_manager_unittest.cc b/chrome/browser/background/background_mode_manager_unittest.cc
index b3e0a7a..d03133c6 100644
--- a/chrome/browser/background/background_mode_manager_unittest.cc
+++ b/chrome/browser/background/background_mode_manager_unittest.cc
@@ -51,6 +51,7 @@
 #include "chrome/browser/ash/settings/scoped_cros_settings_test_helper.h"
 #endif
 
+using extensions::mojom::ManifestLocation;
 using testing::_;
 using testing::AtMost;
 using testing::Exactly;
@@ -648,26 +649,26 @@
 TEST_F(BackgroundModeManagerWithExtensionsTest, BackgroundMenuGeneration) {
   scoped_refptr<const extensions::Extension> component_extension =
       extensions::ExtensionBuilder("Component Extension")
-          .SetLocation(extensions::Manifest::COMPONENT)
+          .SetLocation(ManifestLocation::kComponent)
           .AddPermission("background")
           .Build();
 
   scoped_refptr<const extensions::Extension> component_extension_with_options =
       extensions::ExtensionBuilder("Component Extension with Options")
-          .SetLocation(extensions::Manifest::COMPONENT)
+          .SetLocation(ManifestLocation::kComponent)
           .AddPermission("background")
           .SetManifestKey("options_page", "test.html")
           .Build();
 
   scoped_refptr<const extensions::Extension> regular_extension =
       extensions::ExtensionBuilder("Regular Extension")
-          .SetLocation(extensions::Manifest::COMMAND_LINE)
+          .SetLocation(ManifestLocation::kCommandLine)
           .AddPermission("background")
           .Build();
 
   scoped_refptr<const extensions::Extension> regular_extension_with_options =
       extensions::ExtensionBuilder("Regular Extension with Options")
-          .SetLocation(extensions::Manifest::COMMAND_LINE)
+          .SetLocation(ManifestLocation::kCommandLine)
           .AddPermission("background")
           .SetManifestKey("options_page", "test.html")
           .Build();
@@ -712,26 +713,26 @@
        BackgroundMenuGenerationMultipleProfile) {
   scoped_refptr<const extensions::Extension> component_extension =
       extensions::ExtensionBuilder("Component Extension")
-          .SetLocation(extensions::Manifest::COMPONENT)
+          .SetLocation(ManifestLocation::kComponent)
           .AddPermission("background")
           .Build();
 
   scoped_refptr<const extensions::Extension> component_extension_with_options =
       extensions::ExtensionBuilder("Component Extension with Options")
-          .SetLocation(extensions::Manifest::COMPONENT)
+          .SetLocation(ManifestLocation::kComponent)
           .AddPermission("background")
           .SetManifestKey("options_page", "test.html")
           .Build();
 
   scoped_refptr<const extensions::Extension> regular_extension =
       extensions::ExtensionBuilder("Regular Extension")
-          .SetLocation(extensions::Manifest::COMMAND_LINE)
+          .SetLocation(ManifestLocation::kCommandLine)
           .AddPermission("background")
           .Build();
 
   scoped_refptr<const extensions::Extension> regular_extension_with_options =
       extensions::ExtensionBuilder("Regular Extension with Options")
-          .SetLocation(extensions::Manifest::COMMAND_LINE)
+          .SetLocation(ManifestLocation::kCommandLine)
           .AddPermission("background")
           .SetManifestKey("options_page", "test.html")
           .Build();
@@ -856,27 +857,27 @@
   scoped_refptr<const extensions::Extension> bg_ext =
       extensions::ExtensionBuilder("Background Extension")
           .SetVersion("1.0")
-          .SetLocation(extensions::Manifest::COMMAND_LINE)
+          .SetLocation(ManifestLocation::kCommandLine)
           .AddPermission("background")
           .Build();
 
   scoped_refptr<const extensions::Extension> upgraded_bg_ext =
       extensions::ExtensionBuilder("Background Extension")
           .SetVersion("2.0")
-          .SetLocation(extensions::Manifest::COMMAND_LINE)
+          .SetLocation(ManifestLocation::kCommandLine)
           .AddPermission("background")
           .Build();
 
   scoped_refptr<const extensions::Extension> no_bg_ext =
       extensions::ExtensionBuilder("Regular Extension")
           .SetVersion("1.0")
-          .SetLocation(extensions::Manifest::COMMAND_LINE)
+          .SetLocation(ManifestLocation::kCommandLine)
           .Build();
 
   scoped_refptr<const extensions::Extension> upgraded_no_bg_ext_has_bg =
       extensions::ExtensionBuilder("Regular Extension")
           .SetVersion("1.0")
-          .SetLocation(extensions::Manifest::COMMAND_LINE)
+          .SetLocation(ManifestLocation::kCommandLine)
           .AddPermission("background")
           .Build();
 
diff --git a/chrome/browser/banners/android/BUILD.gn b/chrome/browser/banners/android/BUILD.gn
index eb0220c..fb2f7cb 100644
--- a/chrome/browser/banners/android/BUILD.gn
+++ b/chrome/browser/banners/android/BUILD.gn
@@ -16,6 +16,7 @@
     "//base:base_java",
     "//base:jni_java",
     "//chrome/android:chrome_jni_headers",
+    "//chrome/browser/feature_engagement:java",
     "//chrome/browser/profiles/android:java",
     "//chrome/browser/tab:java",
     "//chrome/browser/ui/android/appmenu:java",
@@ -55,6 +56,7 @@
     "//chrome/android:chrome_test_java",
     "//chrome/android:chrome_test_util_java",
     "//chrome/browser/android/browserservices/intents:java",
+    "//chrome/browser/feature_engagement:java",
     "//chrome/browser/flags:java",
     "//chrome/browser/profiles/android:java",
     "//chrome/browser/tab:java",
diff --git a/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerInProductHelpController.java b/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerInProductHelpController.java
index 96ed510..9394de2 100644
--- a/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerInProductHelpController.java
+++ b/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerInProductHelpController.java
@@ -10,15 +10,12 @@
 
 import androidx.annotation.IdRes;
 
-import org.chromium.base.Function;
 import org.chromium.base.UnownedUserData;
 import org.chromium.base.supplier.Supplier;
-import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.ui.appmenu.AppMenuHandler;
 import org.chromium.chrome.browser.user_education.IPHCommandBuilder;
 import org.chromium.chrome.browser.user_education.UserEducationHelper;
 import org.chromium.components.feature_engagement.FeatureConstants;
-import org.chromium.components.feature_engagement.Tracker;
 
 /**
  * This class is responsible for managing the in-product help for the PWA app banners.
@@ -37,17 +34,14 @@
      * @param appMenuHandler The app menu containing the menu entry to highlight.
      * @param menuButtonView The menu button view to anchor the bubble to.
      * @param higlightMenuItemId The id of the menu item to highlight.
-     * @param trackerFromProfileFactory The factory to obtain a tracker from.
      */
     public AppBannerInProductHelpController(Activity activity, AppMenuHandler appMenuHandler,
-            Supplier<View> menuButtonView, @IdRes int higlightMenuItemId,
-            Function<Profile, Tracker> trackerFromProfileFactory) {
+            Supplier<View> menuButtonView, @IdRes int higlightMenuItemId) {
         mActivity = activity;
         mAppMenuHandler = appMenuHandler;
         mMenuButtonView = menuButtonView;
         mHiglightMenuItemId = higlightMenuItemId;
-        mUserEducationHelper =
-                new UserEducationHelper(mActivity, mHandler, trackerFromProfileFactory);
+        mUserEducationHelper = new UserEducationHelper(mActivity, mHandler);
     }
 
     /**
diff --git a/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerInProductHelpControllerFactory.java b/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerInProductHelpControllerFactory.java
index c2d578b..08ba52b9 100644
--- a/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerInProductHelpControllerFactory.java
+++ b/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerInProductHelpControllerFactory.java
@@ -9,11 +9,8 @@
 
 import androidx.annotation.IdRes;
 
-import org.chromium.base.Function;
 import org.chromium.base.supplier.Supplier;
-import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.ui.appmenu.AppMenuHandler;
-import org.chromium.components.feature_engagement.Tracker;
 import org.chromium.ui.base.WindowAndroid;
 
 /**
@@ -22,9 +19,9 @@
 public class AppBannerInProductHelpControllerFactory {
     public static AppBannerInProductHelpController createAppBannerInProductHelpController(
             Activity activity, AppMenuHandler appMenuHandler, Supplier<View> menuButtonView,
-            @IdRes int higlightMenuItemId, Function<Profile, Tracker> trackerFromProfileFactory) {
-        return new AppBannerInProductHelpController(activity, appMenuHandler, menuButtonView,
-                higlightMenuItemId, trackerFromProfileFactory);
+            @IdRes int higlightMenuItemId) {
+        return new AppBannerInProductHelpController(
+                activity, appMenuHandler, menuButtonView, higlightMenuItemId);
     }
 
     public static void attach(
diff --git a/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerInProductHelpControllerProvider.java b/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerInProductHelpControllerProvider.java
index 093d4a2..6f059dc 100644
--- a/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerInProductHelpControllerProvider.java
+++ b/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerInProductHelpControllerProvider.java
@@ -4,9 +4,9 @@
 
 package org.chromium.chrome.browser.banners;
 
-import org.chromium.base.Function;
 import org.chromium.base.UnownedUserDataKey;
 import org.chromium.base.annotations.CalledByNative;
+import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.components.feature_engagement.FeatureConstants;
 import org.chromium.components.feature_engagement.Tracker;
@@ -22,17 +22,6 @@
     private static final UnownedUserDataKey<AppBannerInProductHelpController> KEY =
             new UnownedUserDataKey<>(AppBannerInProductHelpController.class);
 
-    private static Function<Profile, Tracker> sTrackerFromProfileFactory;
-
-    /**
-     * Sets the factory to obtain a Tracker from.
-     * @param trackerFromProfileFactory The factory to use.
-     */
-    public static void setTrackerFromProfileFactory(
-            Function<Profile, Tracker> trackerFromProfileFactory) {
-        sTrackerFromProfileFactory = trackerFromProfileFactory;
-    }
-
     /**
      * Get the shared {@link AppBannerInProductHelpController} from the provided {@link
      * WindowAndroid}.
@@ -60,7 +49,7 @@
     private static String showInProductHelp(WebContents webContents) {
         // Consult the tracker to see if the IPH can be shown.
         final Tracker tracker =
-                sTrackerFromProfileFactory.apply(Profile.fromWebContents(webContents));
+                TrackerFactory.getTrackerForProfile(Profile.fromWebContents(webContents));
         if (!tracker.wouldTriggerHelpUI(FeatureConstants.PWA_INSTALL_AVAILABLE_FEATURE)) {
             // Tracker replied that the request to show will not be honored. Return whether the
             // limit of how often to show has been exceeded.
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 82f4982..89a682d5 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -83,7 +83,6 @@
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
-#include "chrome/common/extensions/chrome_extensions_client.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/chromium_strings.h"
@@ -176,6 +175,7 @@
 #include "chrome/browser/extensions/event_router_forwarder.h"
 #include "chrome/browser/media_galleries/media_file_system_registry.h"
 #include "chrome/browser/ui/apps/chrome_app_window_client.h"
+#include "chrome/common/extensions/chrome_extensions_client.h"
 #include "chrome/common/initialize_extensions_client.h"
 #include "components/storage_monitor/storage_monitor.h"
 #include "extensions/common/extension_l10n_util.h"
diff --git a/chrome/browser/browser_switcher/browser_switcher_service_browsertest.cc b/chrome/browser/browser_switcher/browser_switcher_service_browsertest.cc
index b9e4f64c..902aaf6 100644
--- a/chrome/browser/browser_switcher/browser_switcher_service_browsertest.cc
+++ b/chrome/browser/browser_switcher/browser_switcher_service_browsertest.cc
@@ -737,15 +737,16 @@
   // No policies configured.
 
   // LBS extension is installed.
-  auto extension = extensions::ExtensionBuilder()
-                       .SetLocation(extensions::Manifest::INTERNAL)
-                       .SetID(kLBSExtensionId)
-                       .SetManifest(extensions::DictionaryBuilder()
-                                        .Set("name", "Legacy Browser Support")
-                                        .Set("manifest_version", 2)
-                                        .Set("version", "5.9")
-                                        .Build())
-                       .Build();
+  auto extension =
+      extensions::ExtensionBuilder()
+          .SetLocation(extensions::mojom::ManifestLocation::kInternal)
+          .SetID(kLBSExtensionId)
+          .SetManifest(extensions::DictionaryBuilder()
+                           .Set("name", "Legacy Browser Support")
+                           .Set("manifest_version", 2)
+                           .Set("version", "5.9")
+                           .Build())
+          .Build();
   extensions::ExtensionSystem::Get(browser()->profile())
       ->extension_service()
       ->AddExtension(extension.get());
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 16064e0..124b46b38 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -28,6 +28,7 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/no_destructor.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
@@ -318,8 +319,13 @@
 namespace {
 
 #if !defined(OS_ANDROID)
-// Holds the RunLoop for the non-Android MainMessageLoopRun() to Run().
-base::RunLoop* g_run_loop = nullptr;
+// Initialized in PreMainMessageLoopRun() and handed off to content:: in
+// WillRunMainMessageLoop() (or in TakeRunLoopForTest() in tests)
+std::unique_ptr<base::RunLoop>& GetMainRunLoopInstance() {
+  static base::NoDestructor<std::unique_ptr<base::RunLoop>>
+      main_run_loop_instance;
+  return *main_run_loop_instance;
+}
 #endif
 
 // This function provides some ways to test crash and assertion handling
@@ -480,18 +486,6 @@
 }
 #endif  // !defined(OS_ANDROID)
 
-class ScopedMainMessageLoopRunEvent {
- public:
-  ScopedMainMessageLoopRunEvent() {
-    TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
-        "toplevel", "ChromeBrowserMainParts::MainMessageLoopRun", this);
-  }
-  ~ScopedMainMessageLoopRunEvent() {
-    TRACE_EVENT_NESTABLE_ASYNC_END0(
-        "toplevel", "ChromeBrowserMainParts::MainMessageLoopRun", this);
-  }
-};
-
 }  // namespace
 
 // BrowserMainParts ------------------------------------------------------------
@@ -903,8 +897,8 @@
 #if !defined(OS_ANDROID)
   // Create the RunLoop for MainMessageLoopRun() to use, and pass a copy of
   // its QuitClosure to the BrowserProcessImpl to call when it is time to exit.
-  DCHECK(!g_run_loop);
-  g_run_loop = new base::RunLoop;
+  DCHECK(!GetMainRunLoopInstance());
+  GetMainRunLoopInstance() = std::make_unique<base::RunLoop>();
 
   // These members must be initialized before returning from this function.
   // Android doesn't use StartupBrowserCreator.
@@ -1039,13 +1033,15 @@
     chrome_extra_parts_[i]->PostCreateThreads();
 }
 
-void ChromeBrowserMainParts::PreMainMessageLoopRun() {
+int ChromeBrowserMainParts::PreMainMessageLoopRun() {
   TRACE_EVENT0("startup", "ChromeBrowserMainParts::PreMainMessageLoopRun");
 
   result_code_ = PreMainMessageLoopRunImpl();
 
   for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
     chrome_extra_parts_[i]->PreMainMessageLoopRun();
+
+  return result_code_;
 }
 
 // PreMainMessageLoopRun calls these extra stages in the following order:
@@ -1683,7 +1679,8 @@
 #endif  // defined(OS_MAC)
 
     // Transfer ownership of the browser's lifetime to the BrowserProcess.
-    browser_process_->SetQuitClosure(g_run_loop->QuitWhenIdleClosure());
+    browser_process_->SetQuitClosure(
+        GetMainRunLoopInstance()->QuitWhenIdleClosure());
     DCHECK(!run_message_loop_);
     run_message_loop_ = true;
   }
@@ -1718,21 +1715,17 @@
   return result_code_;
 }
 
-bool ChromeBrowserMainParts::MainMessageLoopRun(int* result_code) {
-  // Trace the entry and exit of this method. We don't use the TRACE_EVENT0
-  // macro because the tracing infrastructure doesn't expect a synchronous event
-  // around the main loop of a thread.
-  ScopedMainMessageLoopRunEvent scoped_main_message_loop_run_event;
+void ChromeBrowserMainParts::WillRunMainMessageLoop(
+    std::unique_ptr<base::RunLoop>& run_loop) {
 #if defined(OS_ANDROID)
   // Chrome on Android does not use default MessageLoop. It has its own
   // Android specific MessageLoop
   NOTREACHED();
-  return true;
 #else
-  // Set the result code set in PreMainMessageLoopRun or set above.
-  *result_code = result_code_;
-  if (!run_message_loop_)
-    return true;  // Don't run the default message loop.
+  if (!run_message_loop_) {
+    run_loop.reset();
+    return;
+  }
 
   // These should be invoked as close to the start of the browser's
   // UI thread message loop as possible to get a stable measurement
@@ -1741,13 +1734,20 @@
 
   DCHECK(base::CurrentUIThread::IsSet());
 
-  g_run_loop->Run();
+  DCHECK(GetMainRunLoopInstance());
+  run_loop = std::move(GetMainRunLoopInstance());
 
-  return true;
+  // Trace the entry and exit of this main message loop. We don't use the
+  // TRACE_EVENT_BEGIN0 macro because the tracing infrastructure doesn't expect
+  // a synchronous event around the main loop of a thread.
+  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
+      "toplevel", "ChromeBrowserMainParts::MainMessageLoopRun", this);
 #endif  // defined(OS_ANDROID)
 }
 
 void ChromeBrowserMainParts::PostMainMessageLoopRun() {
+  TRACE_EVENT_NESTABLE_ASYNC_END0(
+      "toplevel", "ChromeBrowserMainParts::MainMessageLoopRun", this);
   TRACE_EVENT0("startup", "ChromeBrowserMainParts::PostMainMessageLoopRun");
 #if defined(OS_ANDROID)
   // Chrome on Android does not use default MessageLoop. It has its own
@@ -1854,8 +1854,7 @@
 #if !defined(OS_ANDROID)
 // static
 std::unique_ptr<base::RunLoop> ChromeBrowserMainParts::TakeRunLoopForTest() {
-  auto run_loop = base::WrapUnique<base::RunLoop>(g_run_loop);
-  g_run_loop = nullptr;
-  return run_loop;
+  DCHECK(GetMainRunLoopInstance());
+  return std::move(GetMainRunLoopInstance());
 }
 #endif
diff --git a/chrome/browser/chrome_browser_main.h b/chrome/browser/chrome_browser_main.h
index bbddfaa..d5d8c17 100644
--- a/chrome/browser/chrome_browser_main.h
+++ b/chrome/browser/chrome_browser_main.h
@@ -70,8 +70,9 @@
   void PostMainMessageLoopStart() override;
   int PreCreateThreads() override;
   void PostCreateThreads() override;
-  void PreMainMessageLoopRun() override;
-  bool MainMessageLoopRun(int* result_code) override;
+  int PreMainMessageLoopRun() override;
+  void WillRunMainMessageLoop(
+      std::unique_ptr<base::RunLoop>& run_loop) override;
   void PostMainMessageLoopRun() override;
   void PostDestroyThreads() override;
 
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index ae7f707..e266c95 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -328,7 +328,6 @@
 #include "content/public/common/user_agent.h"
 #include "content/public/common/window_container_type.mojom-shared.h"
 #include "device/vr/buildflags/buildflags.h"
-#include "extensions/browser/process_map.h"
 #include "extensions/buildflags/buildflags.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "google_apis/google_api_keys.h"
@@ -582,6 +581,7 @@
 #include "extensions/browser/guest_view/web_view/web_view_permission_helper.h"
 #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
 #include "extensions/browser/process_manager.h"
+#include "extensions/browser/process_map.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_set.h"
diff --git a/chrome/browser/chrome_resource_bundle_helper.cc b/chrome/browser/chrome_resource_bundle_helper.cc
index a29adeb..1f817b5 100644
--- a/chrome/browser/chrome_resource_bundle_helper.cc
+++ b/chrome/browser/chrome_resource_bundle_helper.cc
@@ -20,7 +20,6 @@
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "extensions/buildflags/buildflags.h"
-#include "extensions/common/extension_l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 
 #if defined(OS_ANDROID)
@@ -32,6 +31,10 @@
 #include "chrome/common/pref_names.h"
 #endif
 
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+#include "extensions/common/extension_l10n_util.h"
+#endif
+
 namespace {
 
 extern void InitializeLocalState(
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index cffa062..b25b1bbe 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -709,12 +709,6 @@
     "../ash/crosapi/test_mojo_connection_manager.h",
     "../ash/crosapi/url_handler_ash.cc",
     "../ash/crosapi/url_handler_ash.h",
-    "../ash/crosapi/video_capture_device_ash.cc",
-    "../ash/crosapi/video_capture_device_ash.h",
-    "../ash/crosapi/video_capture_device_factory_ash.cc",
-    "../ash/crosapi/video_capture_device_factory_ash.h",
-    "../ash/crosapi/video_frame_handler_ash.cc",
-    "../ash/crosapi/video_frame_handler_ash.h",
     "../ash/crosapi/window_util.cc",
     "../ash/crosapi/window_util.h",
     "../ash/login/app_mode/kiosk_launch_controller.cc",
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index 6447baa..fd0ee2f 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -579,7 +579,7 @@
 
 // Threads are initialized between MainMessageLoopStart and MainMessageLoopRun.
 // about_flags settings are applied in ChromeBrowserMainParts::PreCreateThreads.
-void ChromeBrowserMainPartsChromeos::PreMainMessageLoopRun() {
+int ChromeBrowserMainPartsChromeos::PreMainMessageLoopRun() {
   network_change_manager_client_.reset(new NetworkChangeManagerClient(
       static_cast<net::NetworkChangeNotifierPosix*>(
           content::GetNetworkChangeNotifier())));
@@ -663,7 +663,7 @@
   chromeos::cfm::InitializeCfmServices();
 #endif  // BUILDFLAG(PLATFORM_CFM)
 
-  ChromeBrowserMainPartsLinux::PreMainMessageLoopRun();
+  return ChromeBrowserMainPartsLinux::PreMainMessageLoopRun();
 }
 
 void ChromeBrowserMainPartsChromeos::PreProfileInit() {
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.h b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
index 1cf64f7..d3b9dc6 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.h
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
@@ -123,7 +123,7 @@
   int PreEarlyInitialization() override;
   void PreMainMessageLoopStart() override;
   void PostMainMessageLoopStart() override;
-  void PreMainMessageLoopRun() override;
+  int PreMainMessageLoopRun() override;
 
   // Stages called from PreMainMessageLoopRun.
   void PreProfileInit() override;
diff --git a/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/ui_handler_unittest.cc b/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/ui_handler_unittest.cc
index 4fb243c..b89f1527 100644
--- a/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/ui_handler_unittest.cc
+++ b/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/ui_handler_unittest.cc
@@ -26,6 +26,8 @@
 #include "extensions/common/features/feature_channel.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using extensions::mojom::ManifestLocation;
+
 namespace {
 
 const char kErrorWindowAlreadyExists[] =
@@ -126,7 +128,7 @@
     extension_ = extensions::ExtensionBuilder(
                      /*extension_name=*/"LoginScreenUi test extension")
                      .SetID(kWhitelistedExtensionID1)
-                     .SetLocation(extensions::Manifest::EXTERNAL_POLICY)
+                     .SetLocation(ManifestLocation::kExternalPolicy)
                      .AddPermission(kPermissionName)
                      .AddFlags(extensions::Extension::FOR_LOGIN_SCREEN)
                      .Build();
@@ -293,7 +295,7 @@
   scoped_refptr<const extensions::Extension> other_extension =
       extensions::ExtensionBuilder(/*extension_name=*/"Imprivata")
           .SetID(kWhitelistedExtensionID2)
-          .SetLocation(extensions::Manifest::EXTERNAL_POLICY)
+          .SetLocation(ManifestLocation::kExternalPolicy)
           .AddPermission(kPermissionName)
           .AddFlags(extensions::Extension::FOR_LOGIN_SCREEN)
           .Build();
@@ -372,7 +374,7 @@
   scoped_refptr<const extensions::Extension> other_profile_extension =
       extensions::ExtensionBuilder("other profile" /*extension_name*/)
           .SetID(kWhitelistedExtensionID2)  // whitelisted
-          .SetLocation(extensions::Manifest::EXTERNAL_POLICY)
+          .SetLocation(ManifestLocation::kExternalPolicy)
           .AddPermission(kPermissionName)
           .AddFlags(extensions::Extension::FOR_LOGIN_SCREEN)
           .Build();
@@ -384,7 +386,7 @@
   scoped_refptr<const extensions::Extension> no_permission_extension =
       extensions::ExtensionBuilder("no permission extension" /*extension_name*/)
           .SetID(kWhitelistedExtensionID2)  // whitelisted
-          .SetLocation(extensions::Manifest::EXTERNAL_POLICY)
+          .SetLocation(ManifestLocation::kExternalPolicy)
           .AddFlags(extensions::Extension::FOR_LOGIN_SCREEN)
           .Build();
   extension_registry_->AddEnabled(no_permission_extension);
diff --git a/chrome/browser/chromeos/extensions/permissions_updater_delegate_chromeos_unittest.cc b/chrome/browser/chromeos/extensions/permissions_updater_delegate_chromeos_unittest.cc
index ea0164e..5e7824e 100644
--- a/chrome/browser/chromeos/extensions/permissions_updater_delegate_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/extensions/permissions_updater_delegate_chromeos_unittest.cc
@@ -32,7 +32,7 @@
 
 scoped_refptr<const Extension> CreateExtension(const std::string& id) {
   return ExtensionBuilder("test")
-      .SetLocation(Manifest::INTERNAL)
+      .SetLocation(mojom::ManifestLocation::kInternal)
       .SetID(id)
       .Build();
 }
diff --git a/chrome/browser/chromeos/extensions/signin_screen_policy_provider_unittest.cc b/chrome/browser/chromeos/extensions/signin_screen_policy_provider_unittest.cc
index 46dfc17..82e99bd 100644
--- a/chrome/browser/chromeos/extensions/signin_screen_policy_provider_unittest.cc
+++ b/chrome/browser/chromeos/extensions/signin_screen_policy_provider_unittest.cc
@@ -9,9 +9,11 @@
 #include "components/version_info/version_info.h"
 #include "extensions/common/extension_builder.h"
 #include "extensions/common/features/feature_channel.h"
+#include "extensions/common/mojom/manifest.mojom-shared.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using extensions::Extension;
+using extensions::mojom::ManifestLocation;
 
 namespace {
 
@@ -23,7 +25,7 @@
 
 scoped_refptr<const extensions::Extension> CreateTestApp(
     const std::string& extension_id,
-    extensions::Manifest::Location location) {
+    ManifestLocation location) {
   return extensions::ExtensionBuilder()
       .SetManifest(
           extensions::DictionaryBuilder()
@@ -63,8 +65,8 @@
 
 TEST_F(SigninScreenPolicyProviderTest, DenyRandomPolicyExtension) {
   // Arbitrary extension (though installed via policy) should be blocked.
-  scoped_refptr<const extensions::Extension> extension = CreateTestApp(
-      kRandomExtensionId, extensions::Manifest::Location::EXTERNAL_POLICY);
+  scoped_refptr<const extensions::Extension> extension =
+      CreateTestApp(kRandomExtensionId, ManifestLocation::kExternalPolicy);
   std::u16string error;
   EXPECT_FALSE(provider_.UserMayLoad(extension.get(), &error));
   EXPECT_FALSE(error.empty());
@@ -72,8 +74,8 @@
 
 TEST_F(SigninScreenPolicyProviderTest, AllowEssentialExtension) {
   // Essential component extensions for the login screen should always work.
-  scoped_refptr<const extensions::Extension> extension = CreateTestApp(
-      kGnubbyExtensionId, extensions::Manifest::Location::EXTERNAL_COMPONENT);
+  scoped_refptr<const extensions::Extension> extension =
+      CreateTestApp(kGnubbyExtensionId, ManifestLocation::kExternalComponent);
   std::u16string error;
   EXPECT_TRUE(provider_.UserMayLoad(extension.get(), &error));
   EXPECT_TRUE(error.empty());
@@ -84,9 +86,8 @@
   // via policy. This test should be changed in future as we evolve feature
   // requirements.
   extensions::ScopedCurrentChannel channel(version_info::Channel::STABLE);
-  scoped_refptr<const extensions::Extension> extension =
-      CreateTestApp(kSampleSigninExtensionId,
-                    extensions::Manifest::Location::EXTERNAL_POLICY);
+  scoped_refptr<const extensions::Extension> extension = CreateTestApp(
+      kSampleSigninExtensionId, ManifestLocation::kExternalPolicy);
   std::u16string error;
   EXPECT_TRUE(provider_.UserMayLoad(extension.get(), &error));
   EXPECT_TRUE(error.empty());
@@ -96,17 +97,16 @@
   // Google-developed extensions, if not installed via policy, should
   // be disabled.
   extensions::ScopedCurrentChannel channel(version_info::Channel::STABLE);
-  scoped_refptr<const extensions::Extension> extension =
-      CreateTestApp(kSampleSigninExtensionId,
-                    extensions::Manifest::Location::EXTERNAL_COMPONENT);
+  scoped_refptr<const extensions::Extension> extension = CreateTestApp(
+      kSampleSigninExtensionId, ManifestLocation::kExternalComponent);
   std::u16string error;
   EXPECT_FALSE(provider_.UserMayLoad(extension.get(), &error));
   EXPECT_FALSE(error.empty());
 }
 
 TEST_F(SigninScreenPolicyProviderTest, DenyRandomNonPolicyExtension) {
-  scoped_refptr<const extensions::Extension> extension = CreateTestApp(
-      kRandomExtensionId, extensions::Manifest::Location::EXTERNAL_COMPONENT);
+  scoped_refptr<const extensions::Extension> extension =
+      CreateTestApp(kRandomExtensionId, ManifestLocation::kExternalComponent);
   std::u16string error;
   EXPECT_FALSE(provider_.UserMayLoad(extension.get(), &error));
   EXPECT_FALSE(error.empty());
diff --git a/chrome/browser/chromeos/full_restore/app_launch_handler_browsertest.cc b/chrome/browser/chromeos/full_restore/app_launch_handler_browsertest.cc
index 0a10190..3314f99 100644
--- a/chrome/browser/chromeos/full_restore/app_launch_handler_browsertest.cc
+++ b/chrome/browser/chromeos/full_restore/app_launch_handler_browsertest.cc
@@ -410,10 +410,7 @@
   ASSERT_EQ(count + 1u, BrowserList::GetInstance()->size());
 
   // TODO(sammiequon): Check the values from the actual browser window.
-  auto window = std::make_unique<aura::Window>(nullptr);
-  window->Init(ui::LAYER_NOT_DRAWN);
-  window->SetProperty(::full_restore::kRestoreWindowIdKey, kId);
-  auto stored_window_info = ::full_restore::GetWindowInfo(window.get());
+  auto stored_window_info = ::full_restore::GetWindowInfo(kId);
   EXPECT_EQ(kDeskId, *stored_window_info->desk_id);
   EXPECT_EQ(kRestoreBounds, *stored_window_info->restore_bounds);
   EXPECT_EQ(kCurrentBounds, *stored_window_info->current_bounds);
@@ -477,7 +474,7 @@
 
   // Close the window.
   CloseAppWindow(app_window);
-  ASSERT_FALSE(::full_restore::GetWindowInfo(window));
+  ASSERT_FALSE(::full_restore::GetWindowInfo(restore_window_id));
 
   // Remove the added desks.
   while (true) {
diff --git a/chrome/browser/chromeos/lock_screen_apps/app_manager_impl_unittest.cc b/chrome/browser/chromeos/lock_screen_apps/app_manager_impl_unittest.cc
index 277f242..6138008 100644
--- a/chrome/browser/chromeos/lock_screen_apps/app_manager_impl_unittest.cc
+++ b/chrome/browser/chromeos/lock_screen_apps/app_manager_impl_unittest.cc
@@ -255,15 +255,15 @@
     return base::FilePath();
   }
 
-  extensions::Manifest::Location GetAppLocation(TestAppLocation location) {
+  extensions::mojom::ManifestLocation GetAppLocation(TestAppLocation location) {
     switch (location) {
       case TestAppLocation::kUnpacked:
-        return extensions::Manifest::UNPACKED;
+        return extensions::mojom::ManifestLocation::kUnpacked;
       case TestAppLocation::kInternal:
-        return extensions::Manifest::INTERNAL;
+        return extensions::mojom::ManifestLocation::kInternal;
     }
 
-    return extensions::Manifest::UNPACKED;
+    return extensions::mojom::ManifestLocation::kUnpacked;
   }
 
   scoped_refptr<const extensions::Extension> CreateTestApp(
diff --git a/chrome/browser/chromeos/policy/cached_policy_key_loader_chromeos.cc b/chrome/browser/chromeos/policy/cached_policy_key_loader_chromeos.cc
index f70fca3..9768025 100644
--- a/chrome/browser/chromeos/policy/cached_policy_key_loader_chromeos.cc
+++ b/chrome/browser/chromeos/policy/cached_policy_key_loader_chromeos.cc
@@ -13,7 +13,6 @@
 #include "base/files/file_util.h"
 #include "base/location.h"
 #include "base/logging.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/sequenced_task_runner.h"
 #include "base/strings/stringprintf.h"
 #include "base/task_runner_util.h"
@@ -32,24 +31,6 @@
 // Maximum key size that will be loaded, in bytes.
 const size_t kKeySizeLimit = 16 * 1024;
 
-// Failures that can happen when loading the policy key,
-// This enum is used to define the buckets for an enumerated UMA histogram.
-// Hence,
-//   (a) existing enumerated constants should never be deleted or reordered, and
-//   (b) new constants should only be appended at the end of the enumeration.
-enum class ValidationFailure {
-  DBUS,
-  LOAD_KEY,
-
-  // Number of histogram buckets. Has to be the last element.
-  MAX_VALUE,
-};
-
-void SampleValidationFailure(ValidationFailure sample) {
-  UMA_HISTOGRAM_ENUMERATION("Enterprise.UserPolicyValidationFailure", sample,
-                            ValidationFailure::MAX_VALUE);
-}
-
 }  // namespace
 
 CachedPolicyKeyLoaderChromeOS::CachedPolicyKeyLoaderChromeOS(
@@ -158,9 +139,6 @@
     LOG(ERROR) << "Failed to read key at " << path.value();
   }
 
-  if (key.empty())
-    SampleValidationFailure(ValidationFailure::LOAD_KEY);
-
   return key;
 }
 
@@ -190,8 +168,6 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (!sanitized_username || sanitized_username->empty()) {
-    SampleValidationFailure(ValidationFailure::DBUS);
-
     // Don't bother trying to load a key if we don't know where it is - just
     // signal that the load attempt has finished.
     key_load_in_progress_ = false;
diff --git a/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller_browsertest.cc b/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller_browsertest.cc
index 739cbadd..c99162a 100644
--- a/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller_browsertest.cc
+++ b/chrome/browser/chromeos/policy/dlp/data_transfer_dlp_controller_browsertest.cc
@@ -208,15 +208,7 @@
   EXPECT_EQ(base::UTF8ToUTF16(kClipboardText1), result);
 }
 
-// Flaky on MSan bots: http://crbug.com/1178328
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_BlockDestination \
-  DISABLED_BlockDestination
-#else
-#define MAYBE_BlockDestination \
-  BlockDestination
-#endif
-IN_PROC_BROWSER_TEST_F(DataTransferDlpBrowserTest, MAYBE_BlockDestination) {
+IN_PROC_BROWSER_TEST_F(DataTransferDlpBrowserTest, BlockDestination) {
   SkipToLoginScreen();
   LogIn(kAccountId, kAccountPassword, kEmptyServices);
 
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_clipboard_notifier.cc b/chrome/browser/chromeos/policy/dlp/dlp_clipboard_notifier.cc
index bf27fff4..a4df1dd 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_clipboard_notifier.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_clipboard_notifier.cc
@@ -260,13 +260,7 @@
     std::move(blink_paste_cb_).Run(false);
     Observe(nullptr);
   }
-}
-
-void DlpClipboardNotifier::OnWidgetDestroyed(views::Widget* widget) {
-  if (!blink_paste_cb_.is_null()) {
-    std::move(blink_paste_cb_).Run(false);
-    Observe(nullptr);
-  }
+  DlpDataTransferNotifier::OnWidgetClosing(widget);
 }
 
 void DlpClipboardNotifier::WebContentsDestroyed() {
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_clipboard_notifier.h b/chrome/browser/chromeos/policy/dlp/dlp_clipboard_notifier.h
index 755e095..7735624c 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_clipboard_notifier.h
+++ b/chrome/browser/chromeos/policy/dlp/dlp_clipboard_notifier.h
@@ -75,7 +75,6 @@
 
   // views::WidgetObserver
   void OnWidgetClosing(views::Widget* widget) override;
-  void OnWidgetDestroyed(views::Widget* widget) override;
 
   // content::WebContentsObserver:
   void WebContentsDestroyed() override;
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_data_transfer_notifier.cc b/chrome/browser/chromeos/policy/dlp/dlp_data_transfer_notifier.cc
index 811b94f96..7b664ad 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_data_transfer_notifier.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_data_transfer_notifier.cc
@@ -131,18 +131,18 @@
 
 void DlpDataTransferNotifier::CloseWidget(views::Widget* widget,
                                           views::Widget::ClosedReason reason) {
-  if (widget && widget == widget_.get())
-    widget->CloseWithReason(reason);
+  if (widget_) {
+    DCHECK_EQ(widget, widget_.get());
+    widget_closing_timer_.Stop();
+    widget_->CloseWithReason(reason);
+  }
 }
 
 void DlpDataTransferNotifier::OnWidgetClosing(views::Widget* widget) {
-  if (widget == widget_.get())
-    widget_.reset();
-}
-
-void DlpDataTransferNotifier::OnWidgetDestroyed(views::Widget* widget) {
-  if (widget == widget_.get())
-    widget_.reset();
+  DCHECK_EQ(widget, widget_.get());
+  widget_->RemoveObserver(this);
+  widget_.reset();
+  widget_closing_timer_.Stop();
 }
 
 void DlpDataTransferNotifier::OnWidgetActivationChanged(views::Widget* widget,
@@ -165,14 +165,13 @@
 
   widget_->Show();
 
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE,
+  widget_closing_timer_.Start(
+      FROM_HERE, base::TimeDelta::FromMilliseconds(timeout_duration_ms),
       base::BindOnce(&DlpDataTransferNotifier::CloseWidget,
                      base::Unretained(this),
                      widget_.get(),  // Safe as DlpClipboardNotificationHelper
                                      // owns `widget_` and outlives it.
-                     views::Widget::ClosedReason::kUnspecified),
-      base::TimeDelta::FromMilliseconds(timeout_duration_ms));
+                     views::Widget::ClosedReason::kUnspecified));
 }
 
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_data_transfer_notifier.h b/chrome/browser/chromeos/policy/dlp/dlp_data_transfer_notifier.h
index 28b0822e..b94bbc6 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_data_transfer_notifier.h
+++ b/chrome/browser/chromeos/policy/dlp/dlp_data_transfer_notifier.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_CHROMEOS_POLICY_DLP_DLP_DATA_TRANSFER_NOTIFIER_H_
 #define CHROME_BROWSER_CHROMEOS_POLICY_DLP_DLP_DATA_TRANSFER_NOTIFIER_H_
 
+#include "base/timer/timer.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/views/widget/unique_widget_ptr.h"
 #include "ui/views/widget/widget.h"
@@ -39,18 +40,21 @@
   virtual void CloseWidget(views::Widget* widget,
                            views::Widget::ClosedReason reason);
 
+  // views::WidgetObserver
+  void OnWidgetClosing(views::Widget* widget) override;
+  void OnWidgetActivationChanged(views::Widget* widget, bool active) override;
+
+  // TODO(ayaelattar): Change to std::unique_ptr.
   views::UniqueWidgetPtr widget_;
 
  private:
-  // views::WidgetObserver
-  void OnWidgetClosing(views::Widget* widget) override;
-  void OnWidgetDestroyed(views::Widget* widget) override;
-  void OnWidgetActivationChanged(views::Widget* widget, bool active) override;
-
   void InitWidget();
 
+  // TODO(ayaelattar): Change `timeout_duration_ms` to TimeDelta.
   void ResizeAndShowWidget(const gfx::Size& bubble_size,
                            int timeout_duration_ms);
+
+  base::OneShotTimer widget_closing_timer_;
 };
 
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/lock_to_single_user_manager.cc b/chrome/browser/chromeos/policy/lock_to_single_user_manager.cc
index b1b23eba..6094a1bf 100644
--- a/chrome/browser/chromeos/policy/lock_to_single_user_manager.cc
+++ b/chrome/browser/chromeos/policy/lock_to_single_user_manager.cc
@@ -64,7 +64,15 @@
 }
 
 void LockToSingleUserManager::ActiveUserChanged(user_manager::User* user) {
-  if (user->IsAffiliated())
+  user->IsAffiliatedAsync(
+      base::BindOnce(&LockToSingleUserManager::OnUserAffiliationEstablished,
+                     weak_factory_.GetWeakPtr(), user));
+}
+
+void LockToSingleUserManager::OnUserAffiliationEstablished(
+    user_manager::User* user,
+    bool is_affiliated) {
+  if (is_affiliated)
     return;
 
   int policy_value = -1;
diff --git a/chrome/browser/chromeos/policy/lock_to_single_user_manager.h b/chrome/browser/chromeos/policy/lock_to_single_user_manager.h
index aa672d7d..5e92de7 100644
--- a/chrome/browser/chromeos/policy/lock_to_single_user_manager.h
+++ b/chrome/browser/chromeos/policy/lock_to_single_user_manager.h
@@ -48,6 +48,10 @@
   // chromeos::VmStartingObserver:
   void OnVmStarting() override;
 
+  // On affiliation established of the active user.
+  void OnUserAffiliationEstablished(user_manager::User* user,
+                                    bool is_affiliated);
+
   // Add observers for VM starting events
   void AddVmStartingObservers(user_manager::User* user);
 
diff --git a/chrome/browser/chromeos/policy/lock_to_single_user_manager_unittest.cc b/chrome/browser/chromeos/policy/lock_to_single_user_manager_unittest.cc
index 1a1125fe..ed1a11d 100644
--- a/chrome/browser/chromeos/policy/lock_to_single_user_manager_unittest.cc
+++ b/chrome/browser/chromeos/policy/lock_to_single_user_manager_unittest.cc
@@ -216,6 +216,13 @@
   EXPECT_TRUE(is_device_locked());
 }
 
+TEST_F(LockToSingleUserManagerTest, LateAffilitionNotificationTest) {
+  SetPolicyValue(enterprise_management::DeviceRebootOnUserSignoutProto::ALWAYS);
+  EXPECT_FALSE(is_device_locked());
+  LogInUser(false /* is_affiliated */);
+  EXPECT_TRUE(is_device_locked());
+}
+
 TEST_F(LockToSingleUserManagerTest, NeverLockTest) {
   SetPolicyValue(enterprise_management::DeviceRebootOnUserSignoutProto::NEVER);
   LogInUser(false /* is_affiliated */);
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.cc b/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.cc
index 4940c66c..130de7a0 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.cc
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.cc
@@ -10,7 +10,6 @@
 #include "base/callback_helpers.h"
 #include "base/debug/dump_without_crashing.h"
 #include "base/logging.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/sequence_checker.h"
 #include "base/sequenced_task_runner.h"
 #include "chrome/browser/ash/crosapi/browser_manager.h"
@@ -174,10 +173,6 @@
     UserCloudPolicyValidator* validator) {
   DCHECK(!is_active_directory_);
 
-  UMA_HISTOGRAM_ENUMERATION("Enterprise.UserPolicyValidationStoreStatus",
-                            validator->status(),
-                            UserCloudPolicyValidator::VALIDATION_STATUS_SIZE);
-
   validation_result_ = validator->GetValidationResult();
   if (!validator->success()) {
     status_ = STATUS_VALIDATION_ERROR;
@@ -267,10 +262,6 @@
 
 void UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated(
     UserCloudPolicyValidator* validator) {
-  UMA_HISTOGRAM_ENUMERATION("Enterprise.UserPolicyValidationLoadStatus",
-                            validator->status(),
-                            UserCloudPolicyValidator::VALIDATION_STATUS_SIZE);
-
   validation_result_ = validator->GetValidationResult();
   if (!validator->success()) {
     status_ = STATUS_VALIDATION_ERROR;
diff --git a/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc b/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc
index 01478bc7..f8b7ed30 100644
--- a/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc
+++ b/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc
@@ -334,40 +334,28 @@
   // A network change forces the config to be fetched.
   SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_3G);
 
-  for (const bool set_render_frame_id : {false, true}) {
-    auto resource_request = std::make_unique<network::ResourceRequest>();
-    if (set_render_frame_id)
-      resource_request->render_frame_id = MSG_ROUTING_CONTROL;
-    // Change the URL for different test cases because a bypassed URL may be
-    // added to the local cache by network service proxy delegate.
-    if (set_render_frame_id) {
-      resource_request->url = GetURLWithMockHost(
-          origin_server, "/echoheader?Chrome-Proxy&random=1");
-    } else {
-      resource_request->url = GetURLWithMockHost(
-          origin_server, "/echoheader?Chrome-Proxy&random=2");
-    }
+  auto resource_request = std::make_unique<network::ResourceRequest>();
+  resource_request->url =
+      GetURLWithMockHost(origin_server, "/echoheader?Chrome-Proxy");
 
-    auto simple_loader = network::SimpleURLLoader::Create(
-        std::move(resource_request), TRAFFIC_ANNOTATION_FOR_TESTS);
+  auto simple_loader = network::SimpleURLLoader::Create(
+      std::move(resource_request), TRAFFIC_ANNOTATION_FOR_TESTS);
 
-    auto* storage_partition =
-        content::BrowserContext::GetDefaultStoragePartition(
-            browser()->profile());
-    auto url_loader_factory =
-        storage_partition->GetURLLoaderFactoryForBrowserProcess();
+  auto* storage_partition =
+      content::BrowserContext::GetDefaultStoragePartition(browser()->profile());
+  auto url_loader_factory =
+      storage_partition->GetURLLoaderFactoryForBrowserProcess();
 
-    base::RunLoop loop;
-    simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
-        url_loader_factory.get(),
-        base::BindLambdaForTesting(
-            [&](std::unique_ptr<std::string> response_body) {
-              loop.Quit();
-              ASSERT_TRUE(response_body);
-              EXPECT_EQ(kDummyBody, *response_body);
-            }));
-    loop.Run();
-  }
+  base::RunLoop loop;
+  simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+      url_loader_factory.get(),
+      base::BindLambdaForTesting(
+          [&](std::unique_ptr<std::string> response_body) {
+            loop.Quit();
+            ASSERT_TRUE(response_body);
+            EXPECT_EQ(kDummyBody, *response_body);
+          }));
+  loop.Run();
 }
 
 
diff --git a/chrome/browser/data_saver/subresource_redirect_login_robots_browsertest.cc b/chrome/browser/data_saver/subresource_redirect_login_robots_browsertest.cc
index 8108a7f..eca34ac 100644
--- a/chrome/browser/data_saver/subresource_redirect_login_robots_browsertest.cc
+++ b/chrome/browser/data_saver/subresource_redirect_login_robots_browsertest.cc
@@ -74,10 +74,10 @@
           image_compression_server_.GetURL();
       // This rules fetch timeout is chosen such that the tests would have
       // enough time to fetch the rules without causing a timeout.
-      params["robots_rules_receive_timeout"] = "1500";
+      params["robots_rules_receive_timeout"] = "2500";
       // Allow first 5 images to be loaded faster.
       params["first_k_subresource_limit"] = "5";
-      params["robots_rules_receive_first_k_timeout_ms"] = "1000";
+      params["robots_rules_receive_first_k_timeout_ms"] = "2000";
       enabled_features.emplace_back(blink::features::kSubresourceRedirect,
                                     params);
       login_detection_params["logged_in_sites"] = "https://loggedin.com";
@@ -210,8 +210,9 @@
 }
 
 // Test is flaky. See https://crbug.com/1187754
-IN_PROC_BROWSER_TEST_F(SubresourceRedirectLoginRobotsBrowserTest,
-                       DISABLEDTestImageDisallowedByRobots) {
+IN_PROC_BROWSER_TEST_F(
+    SubresourceRedirectLoginRobotsBrowserTest,
+    DISABLE_ON_WIN_MAC_CHROMEOS(TestImageDisallowedByRobots)) {
   CreateUkmRecorder();
   robots_rules_server_.AddRobotsRules(GetHttpsTestURL("/"),
                                       {{kRuleTypeDisallow, ""}});
@@ -430,8 +431,9 @@
 
 // Test is flaky. See https://crbug.com/1187754
 // Verify an new image loads fine after robots rules fetch is complete.
-IN_PROC_BROWSER_TEST_F(SubresourceRedirectLoginRobotsBrowserTest,
-                       DISABLED_TestImageLoadAfterRobotsFetch) {
+IN_PROC_BROWSER_TEST_F(
+    SubresourceRedirectLoginRobotsBrowserTest,
+    DISABLE_ON_WIN_MAC_CHROMEOS(TestImageLoadAfterRobotsFetch)) {
   robots_rules_server_.AddRobotsRules(
       GetHttpsTestURL("/"),
       {{kRuleTypeAllow, "/load_image/image.png"}, {kRuleTypeDisallow, ""}});
@@ -868,9 +870,9 @@
          "')"});
     EXPECT_TRUE(RunScriptExtractBool(load_image_url));
     EXPECT_TRUE(RunScriptExtractBool("checkImage()"));
-    // The image should load closer to 1 second.
+    // The image should load closer to 2 seconds.
     EXPECT_LT(base::TimeDelta::FromSecondsD(0.9), elapsed_timer.Elapsed());
-    EXPECT_GT(base::TimeDelta::FromSecondsD(1.2), elapsed_timer.Elapsed());
+    EXPECT_GT(base::TimeDelta::FromSecondsD(2.2), elapsed_timer.Elapsed());
   }
 
   FetchHistogramsFromChildProcesses();
@@ -894,8 +896,8 @@
          "')"});
     EXPECT_TRUE(RunScriptExtractBool(load_image_url));
     EXPECT_TRUE(RunScriptExtractBool("checkImage()"));
-    // The image should load closer to 1.5 second.
-    EXPECT_LT(base::TimeDelta::FromSecondsD(1.4), elapsed_timer.Elapsed());
+    // The image should load closer to 2.5 seconds.
+    EXPECT_LT(base::TimeDelta::FromSecondsD(2.4), elapsed_timer.Elapsed());
   }
 
   FetchHistogramsFromChildProcesses();
diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc
index 9f3e66a..cebed2a 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate.cc
@@ -1619,7 +1619,7 @@
       web_contents_getter,
       base::BindOnce(&OnDownloadAcquireFileAccessPermissionDone,
                      web_contents_getter, url, request_method,
-                     std::move(request_initiator), base::Passed(&cb)));
+                     std::move(request_initiator), std::move(cb)));
 #else
   CheckCanDownload(web_contents_getter, url, request_method,
                    std::move(request_initiator),
diff --git a/chrome/browser/enterprise/connectors/connectors_prefs.cc b/chrome/browser/enterprise/connectors/connectors_prefs.cc
index b2cf8c8f..0d9a930 100644
--- a/chrome/browser/enterprise/connectors/connectors_prefs.cc
+++ b/chrome/browser/enterprise/connectors/connectors_prefs.cc
@@ -72,12 +72,14 @@
   registry->RegisterIntegerPref(kOnFileDownloadedScopePref, 0);
   registry->RegisterIntegerPref(kOnBulkDataEntryScopePref, 0);
   registry->RegisterIntegerPref(kOnSecurityEventScopePref, 0);
-  // Device Trust prefs
   registry->RegisterListPref(kContextAwareAccessSignalsAllowlistPref);
-  registry->RegisterStringPref(kDeviceTrustPrivateKeyPref, std::string());
-  registry->RegisterStringPref(kDeviceTrustPublicKeyPref, std::string());
 
   RegisterFileSystemPrefs(registry);
 }
 
+void RegisterLocalPrefs(PrefRegistrySimple* registry) {
+  registry->RegisterStringPref(kDeviceTrustPrivateKeyPref, std::string());
+  registry->RegisterStringPref(kDeviceTrustPublicKeyPref, std::string());
+}
+
 }  // namespace enterprise_connectors
diff --git a/chrome/browser/enterprise/connectors/connectors_prefs.h b/chrome/browser/enterprise/connectors/connectors_prefs.h
index 1f3e34d..2a6cff99 100644
--- a/chrome/browser/enterprise/connectors/connectors_prefs.h
+++ b/chrome/browser/enterprise/connectors/connectors_prefs.h
@@ -34,19 +34,19 @@
 extern const char kOnBulkDataEntryScopePref[];
 extern const char kOnSecurityEventScopePref[];
 
-// The pref name where this class stores the encrypted private key;
-// TODO(b/178422353): The attestation key should be per device. If two
-// instances of chrome are running, they should report the same key.
+// The pref name where this class stores the encrypted private key.
 // If the machine supports storage in TPM, the private key will be
-// stored there.
+// stored there; otherwise, it will be stored in the local state.
 extern const char kDeviceTrustPrivateKeyPref[];
 // The pref name where this class stores the public key;
 // If the machine supports storage in TPM, the public key will be
-// stored there.
+// stored there; owtherwise, it will be stored in the local state.
 extern const char kDeviceTrustPublicKeyPref[];
 
 void RegisterProfilePrefs(PrefRegistrySimple* registry);
 
+void RegisterLocalPrefs(PrefRegistrySimple* registry);
+
 }  // namespace enterprise_connectors
 
 #endif  // CHROME_BROWSER_ENTERPRISE_CONNECTORS_CONNECTORS_PREFS_H_
diff --git a/chrome/browser/enterprise/connectors/device_trust/device_trust_key_pair.cc b/chrome/browser/enterprise/connectors/device_trust/device_trust_key_pair.cc
index 89f6e85..f715a74 100644
--- a/chrome/browser/enterprise/connectors/device_trust/device_trust_key_pair.cc
+++ b/chrome/browser/enterprise/connectors/device_trust/device_trust_key_pair.cc
@@ -15,6 +15,7 @@
 #include "base/strings/string_util.h"
 #include "base/util/values/values_util.h"
 #include "base/values.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/enterprise/connectors/connectors_prefs.h"
 #include "chrome/common/pref_names.h"
 #include "components/os_crypt/os_crypt.h"
@@ -75,20 +76,15 @@
 
 }  // namespace
 
-DeviceTrustKeyPair::DeviceTrustKeyPair(Profile* profile) : profile_(profile) {
-  Init();
-}
+DeviceTrustKeyPair::DeviceTrustKeyPair() = default;
 
 DeviceTrustKeyPair::~DeviceTrustKeyPair() = default;
 
 bool DeviceTrustKeyPair::Init() {
-  PrefService* prefs = profile_->GetPrefs();
-
-  origins_ = prefs->GetList(
-      enterprise_connectors::kContextAwareAccessSignalsAllowlistPref);
+  PrefService* const local_state = g_browser_process->local_state();
 
   std::string base64_encrypted_private_key_info =
-      prefs->GetString(enterprise_connectors::kDeviceTrustPrivateKeyPref);
+      local_state->GetString(enterprise_connectors::kDeviceTrustPrivateKeyPref);
 
   // No key pair stored.
   if (base64_encrypted_private_key_info.empty()) {
@@ -125,8 +121,8 @@
     return false;
   }
 
-  PrefService* prefs = profile_->GetPrefs();
-  // Add private encoded encrypted private key to prefs.
+  PrefService* const local_state = g_browser_process->local_state();
+  // Add private encoded encrypted private key to local_state.
   std::vector<uint8_t> private_key;
   if (!key_pair_->ExportPrivateKey(&private_key))
     return false;
@@ -142,11 +138,12 @@
   // The string must be encoded as base64 for storage in local state.
   std::string encoded;
   base::Base64Encode(encrypted_key, &encoded);
-  prefs->SetString(enterprise_connectors::kDeviceTrustPrivateKeyPref, encoded);
+  local_state->SetString(enterprise_connectors::kDeviceTrustPrivateKeyPref,
+                         encoded);
 
-  // Add public key to prefs.
-  prefs->SetString(enterprise_connectors::kDeviceTrustPublicKeyPref,
-                   ExportPEMPublicKey());
+  // Add public key to local_state.
+  local_state->SetString(enterprise_connectors::kDeviceTrustPublicKeyPref,
+                         ExportPEMPublicKey());
 
   return true;
 }
diff --git a/chrome/browser/enterprise/connectors/device_trust/device_trust_key_pair.h b/chrome/browser/enterprise/connectors/device_trust/device_trust_key_pair.h
index 0c8d07b..6516d227 100644
--- a/chrome/browser/enterprise/connectors/device_trust/device_trust_key_pair.h
+++ b/chrome/browser/enterprise/connectors/device_trust/device_trust_key_pair.h
@@ -32,8 +32,7 @@
 //
 class DeviceTrustKeyPair {
  public:
-  DeviceTrustKeyPair() = delete;
-  explicit DeviceTrustKeyPair(Profile* profile);
+  DeviceTrustKeyPair();
   DeviceTrustKeyPair(const DeviceTrustKeyPair&) = delete;
   DeviceTrustKeyPair& operator=(const DeviceTrustKeyPair&) = delete;
   ~DeviceTrustKeyPair();
@@ -46,17 +45,14 @@
   // string otherwise.
   std::string ExportPEMPublicKey();
 
- private:
-  // TODO(b/181059258) Replace with url_matcher::URLMatcher.
-  const base::ListValue* origins_;
-  std::unique_ptr<crypto::ECPrivateKey> key_pair_;
-  Profile* profile_;
-
   // Load key pair from prefs if available, if not, it will generate a
   // new key pair and store the encoded encrypted version of it into prefs.
   // Return strue on success.
   bool Init();
 
+ private:
+  std::unique_ptr<crypto::ECPrivateKey> key_pair_;
+
   // Store encrypted private key and public key into prefs.
   // Return strue on success.
   bool StoreKeyPair();
diff --git a/chrome/browser/enterprise/connectors/device_trust/device_trust_key_pair_unittest.cc b/chrome/browser/enterprise/connectors/device_trust/device_trust_key_pair_unittest.cc
index 700a1395..b2b6531 100644
--- a/chrome/browser/enterprise/connectors/device_trust/device_trust_key_pair_unittest.cc
+++ b/chrome/browser/enterprise/connectors/device_trust/device_trust_key_pair_unittest.cc
@@ -7,30 +7,21 @@
 #include "chrome/browser/enterprise/connectors/connectors_prefs.h"
 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
 #include "chrome/common/pref_names.h"
-#include "chrome/test/base/testing_profile.h"
-#include "components/os_crypt/os_crypt.h"
+#include "chrome/test/base/scoped_testing_local_state.h"
+#include "chrome/test/base/testing_browser_process.h"
 #include "components/os_crypt/os_crypt_mocker.h"
-#include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace {
-
-const base::Value origins[]{base::Value("example1.example.com"),
-                            base::Value("example2.example.com")};
-
-}  // namespace
 
 namespace policy {
 
 class DeviceTrustKeyPairTest : public testing::Test {
  public:
+  DeviceTrustKeyPairTest() : local_state_(TestingBrowserProcess::GetGlobal()) {}
   void SetUp() override {
     testing::Test::SetUp();
     OSCryptMocker::SetUp();
-
-    prefs()->SetUserPref(
-        enterprise_connectors::kContextAwareAccessSignalsAllowlistPref,
-        std::make_unique<base::ListValue>(origins));
+    key_.Init();
   }
 
   void TearDown() override {
@@ -38,29 +29,20 @@
     testing::Test::TearDown();
   }
 
-  TestingPrefServiceSimple* GetTestingLocalState();
-  sync_preferences::TestingPrefServiceSyncable* prefs() {
-    return profile_->GetTestingPrefService();
-  }
-  TestingProfile* profile() { return profile_.get(); }
+  policy::DeviceTrustKeyPair key_;
 
  private:
-  content::BrowserTaskEnvironment task_environment_;
-  std::unique_ptr<TestingProfile> profile_ = std::make_unique<TestingProfile>();
+  ScopedTestingLocalState local_state_;
 };
 
 TEST_F(DeviceTrustKeyPairTest, ExportPrivateKey) {
-  policy::DeviceTrustKeyPair key(profile());
-
-  std::string private_key = key.ExportPEMPrivateKey();
+  std::string private_key = key_.ExportPEMPrivateKey();
   EXPECT_TRUE(base::StartsWith(private_key, "-----BEGIN PRIVATE KEY-----\n"));
   EXPECT_TRUE(base::EndsWith(private_key, "-----END PRIVATE KEY-----\n"));
 }
 
 TEST_F(DeviceTrustKeyPairTest, ExportPublicKey) {
-  policy::DeviceTrustKeyPair key(profile());
-
-  std::string public_key = key.ExportPEMPublicKey();
+  std::string public_key = key_.ExportPEMPublicKey();
   EXPECT_TRUE(base::StartsWith(public_key, "-----BEGIN PUBLIC KEY-----\n"));
   EXPECT_TRUE(base::EndsWith(public_key, "-----END PUBLIC KEY-----\n"));
 }
diff --git a/chrome/browser/enterprise/connectors/device_trust/device_trust_service.cc b/chrome/browser/enterprise/connectors/device_trust/device_trust_service.cc
index 7c431af..eb48d96 100644
--- a/chrome/browser/enterprise/connectors/device_trust/device_trust_service.cc
+++ b/chrome/browser/enterprise/connectors/device_trust/device_trust_service.cc
@@ -4,8 +4,6 @@
 
 #include "chrome/browser/enterprise/connectors/device_trust/device_trust_service.h"
 
-#include "base/base64.h"
-#include "base/logging.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/enterprise/connectors/connectors_prefs.h"
@@ -26,7 +24,7 @@
       signal_report_callback_(
           base::BindOnce(&DeviceTrustService::OnSignalReported,
                          base::Unretained(this))) {
-  key_pair_ = std::make_unique<DeviceTrustKeyPair>(profile);
+  key_pair_ = std::make_unique<DeviceTrustKeyPair>();
   pref_observer_.Init(prefs_);
   pref_observer_.Add(kContextAwareAccessSignalsAllowlistPref,
                      base::BindRepeating(&DeviceTrustService::OnPolicyUpdated,
@@ -49,12 +47,13 @@
 }
 
 void DeviceTrustService::OnPolicyUpdated() {
-  if (!reporter_) {
+  if (!key_pair_ || !reporter_) {
     return;
   }
 
   if (!first_report_sent_ &&
       IsEnabled()) {  // Policy enabled for the first time.
+    key_pair_->Init();
     reporter_->Init(
         base::BindRepeating(
             [](DeviceTrustService* self) { return self->IsEnabled(); },
diff --git a/chrome/browser/enterprise/connectors/device_trust/device_trust_service.h b/chrome/browser/enterprise/connectors/device_trust/device_trust_service.h
index 1f4fb06a..e533495 100644
--- a/chrome/browser/enterprise/connectors/device_trust/device_trust_service.h
+++ b/chrome/browser/enterprise/connectors/device_trust/device_trust_service.h
@@ -14,6 +14,7 @@
 
 #include <memory>
 
+class KeyedService;
 class Profile;
 class PrefService;
 namespace enterprise_connectors {
diff --git a/chrome/browser/enterprise/connectors/device_trust/device_trust_service_unittest.cc b/chrome/browser/enterprise/connectors/device_trust/device_trust_service_unittest.cc
index 1c3debca..ff513d1 100644
--- a/chrome/browser/enterprise/connectors/device_trust/device_trust_service_unittest.cc
+++ b/chrome/browser/enterprise/connectors/device_trust/device_trust_service_unittest.cc
@@ -9,6 +9,8 @@
 #include "chrome/browser/enterprise/connectors/device_trust/mock_signal_reporter.h"
 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
 #include "chrome/common/pref_names.h"
+#include "chrome/test/base/scoped_testing_local_state.h"
+#include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/os_crypt/os_crypt_mocker.h"
 #include "content/public/test/browser_task_environment.h"
@@ -26,6 +28,8 @@
 namespace policy {
 class DeviceTrustServiceTest : public testing::Test {
  public:
+  DeviceTrustServiceTest() : local_state_(TestingBrowserProcess::GetGlobal()) {}
+
   void SetUp() override {
     testing::Test::SetUp();
     OSCryptMocker::SetUp();
@@ -83,6 +87,7 @@
 
   content::BrowserTaskEnvironment task_environment_;
   std::unique_ptr<TestingProfile> profile_ = std::make_unique<TestingProfile>();
+  ScopedTestingLocalState local_state_;
 };
 
 TEST_F(DeviceTrustServiceTest, StartWithEnabledPolicy) {
diff --git a/chrome/browser/enterprise/connectors/reporting/reporting_service_settings.cc b/chrome/browser/enterprise/connectors/reporting/reporting_service_settings.cc
index 5fa6919..bc666655 100644
--- a/chrome/browser/enterprise/connectors/reporting/reporting_service_settings.cc
+++ b/chrome/browser/enterprise/connectors/reporting/reporting_service_settings.cc
@@ -4,12 +4,40 @@
 
 #include "chrome/browser/enterprise/connectors/reporting/reporting_service_settings.h"
 
+#include "base/command_line.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/enterprise/connectors/service_provider_config.h"
 #include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h"
+#include "chrome/browser/policy/chrome_browser_policy_connector.h"
 #include "components/policy/core/browser/url_util.h"
 
 namespace enterprise_connectors {
 
+namespace {
+
+constexpr char kReportingConnectorUrlFlag[] = "reporting-connector-url";
+
+base::Optional<GURL> GetUrlOverride() {
+  // Ignore this flag on Stable and Beta to avoid abuse.
+  if (!g_browser_process || !g_browser_process->browser_policy_connector()
+                                 ->IsCommandLineSwitchSupported()) {
+    return base::nullopt;
+  }
+
+  base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
+  if (cmd->HasSwitch(kReportingConnectorUrlFlag)) {
+    GURL url = GURL(cmd->GetSwitchValueASCII(kReportingConnectorUrlFlag));
+    if (url.is_valid())
+      return url;
+    else
+      VLOG(1) << "--reporting-connector-url is set to an invalid URL";
+  }
+
+  return base::nullopt;
+}
+
+}  // namespace
+
 ReportingServiceSettings::ReportingServiceSettings(
     const base::Value& settings_value,
     const ServiceProviderConfig& service_provider_config) {
@@ -57,7 +85,8 @@
 
   ReportingSettings settings;
 
-  settings.reporting_url = GURL(service_provider_->reporting_url());
+  settings.reporting_url =
+      GetUrlOverride().value_or(GURL(service_provider_->reporting_url()));
   DCHECK(settings.reporting_url.is_valid());
 
   settings.enabled_event_names.insert(enabled_event_names_.begin(),
diff --git a/chrome/browser/enterprise/connectors/reporting/reporting_service_settings_unittest.cc b/chrome/browser/enterprise/connectors/reporting/reporting_service_settings_unittest.cc
index 2a1df32e..a7453501 100644
--- a/chrome/browser/enterprise/connectors/reporting/reporting_service_settings_unittest.cc
+++ b/chrome/browser/enterprise/connectors/reporting/reporting_service_settings_unittest.cc
@@ -4,13 +4,19 @@
 
 #include "chrome/browser/enterprise/connectors/reporting/reporting_service_settings.h"
 
+#include "base/command_line.h"
 #include "base/json/json_reader.h"
 #include "base/no_destructor.h"
 #include "chrome/browser/enterprise/connectors/connectors_service.h"
 #include "chrome/browser/enterprise/connectors/service_provider_config.h"
+#include "chrome/browser/policy/chrome_browser_policy_connector.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "chrome/browser/ash/settings/scoped_cros_settings_test_helper.h"
+#endif
+
 namespace enterprise_connectors {
 
 namespace {
@@ -69,6 +75,13 @@
 
  private:
   content::BrowserTaskEnvironment task_environment_;
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  // This is necessary so the URL flag code works on CrOS. If it's absent, a
+  // CrOS DCHECK fails when trying to access the
+  // BrowserPolicyConnectorChromeOS as it is not completely initialized.
+  ash::ScopedCrosSettingsTestHelper cros_settings_;
+#endif
 };
 
 TEST_P(ReportingServiceSettingsTest, Test) {
@@ -94,6 +107,26 @@
   }
 }
 
+TEST_P(ReportingServiceSettingsTest, FlagOverride) {
+  base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
+  cmd->AppendSwitchASCII("reporting-connector-url", "https://test.com/reports");
+  policy::ChromeBrowserPolicyConnector::EnableCommandLineSupportForTesting();
+
+  auto settings = base::JSONReader::Read(settings_value(),
+                                         base::JSON_ALLOW_TRAILING_COMMAS);
+  ASSERT_TRUE(settings.has_value());
+
+  ServiceProviderConfig config(kServiceProviderConfig);
+  ReportingServiceSettings service_settings(settings.value(), config);
+
+  auto reporting_settings = service_settings.GetReportingSettings();
+  ASSERT_EQ((expected_settings() != nullptr), reporting_settings.has_value());
+  if (expected_settings()) {
+    ASSERT_TRUE(reporting_settings->reporting_url.is_valid());
+    ASSERT_EQ(reporting_settings->reporting_url, "https://test.com/reports");
+  }
+}
+
 INSTANTIATE_TEST_CASE_P(
     ,
     ReportingServiceSettingsTest,
diff --git a/chrome/browser/enterprise/reporting/extension_info_unittest.cc b/chrome/browser/enterprise/reporting/extension_info_unittest.cc
index 0877052..1e24159 100644
--- a/chrome/browser/enterprise/reporting/extension_info_unittest.cc
+++ b/chrome/browser/enterprise/reporting/extension_info_unittest.cc
@@ -11,6 +11,8 @@
 #include "extensions/common/manifest_constants.h"
 #include "extensions/common/value_builder.h"
 
+using extensions::mojom::ManifestLocation;
+
 namespace em = enterprise_management;
 
 namespace enterprise_reporting {
@@ -39,7 +41,7 @@
 
   scoped_refptr<const extensions::Extension> BuildExtension(
       const std::string& id = kId,
-      extensions::Manifest::Location location = extensions::Manifest::UNPACKED,
+      ManifestLocation location = ManifestLocation::kUnpacked,
       bool is_app = false,
       bool from_webstore = false) {
     extensions::ExtensionBuilder extensionBuilder(
@@ -155,9 +157,8 @@
 }
 
 TEST_F(ExtensionInfoTest, ComponentExtension) {
-  auto extension1 = BuildExtension(kId, extensions::Manifest::COMPONENT);
-  auto extension2 =
-      BuildExtension(kId2, extensions::Manifest::EXTERNAL_COMPONENT);
+  auto extension1 = BuildExtension(kId, ManifestLocation::kComponent);
+  auto extension2 = BuildExtension(kId2, ManifestLocation::kExternalComponent);
 
   em::ChromeUserProfileInfo info;
   AppendExtensionInfoIntoProfileReport(profile(), &info);
@@ -166,9 +167,9 @@
 }
 
 TEST_F(ExtensionInfoTest, FromWebstoreFlag) {
-  auto extension1 = BuildExtension(kId, extensions::Manifest::UNPACKED,
+  auto extension1 = BuildExtension(kId, ManifestLocation::kUnpacked,
                                    /*is_app=*/false, /*from_webstore=*/false);
-  auto extension2 = BuildExtension(kId2, extensions::Manifest::UNPACKED,
+  auto extension2 = BuildExtension(kId2, ManifestLocation::kUnpacked,
                                    /*is_app=*/false, /*from_webstore=*/true);
 
   em::ChromeUserProfileInfo info;
diff --git a/chrome/browser/extensions/api/declarative_content/content_action_unittest.cc b/chrome/browser/extensions/api/declarative_content/content_action_unittest.cc
index 22ea2b4..2ec7426 100644
--- a/chrome/browser/extensions/api/declarative_content/content_action_unittest.cc
+++ b/chrome/browser/extensions/api/declarative_content/content_action_unittest.cc
@@ -38,6 +38,7 @@
 using base::test::ParseJson;
 using testing::HasSubstr;
 using ContentActionType = declarative_content_constants::ContentActionType;
+using extensions::mojom::ManifestLocation;
 
 std::unique_ptr<base::DictionaryValue> SimpleManifest() {
   return DictionaryBuilder()
@@ -120,7 +121,7 @@
   scoped_refptr<const Extension> extension =
       ExtensionBuilder()
           .SetManifest(manifest.Build())
-          .SetLocation(Manifest::COMPONENT)
+          .SetLocation(ManifestLocation::kComponent)
           .Build();
   env.GetExtensionService()->AddExtension(extension.get());
 
@@ -149,7 +150,7 @@
   scoped_refptr<const Extension> extension =
       ExtensionBuilder("extension")
           .SetAction(GetParam())
-          .SetLocation(Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .Build();
 
   env.GetExtensionService()->AddExtension(extension.get());
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
index 7a48c1a0..b60b13bb 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
@@ -223,7 +223,7 @@
   scoped_refptr<const Extension> extension =
       ExtensionBuilder()
           .SetManifest(manifest.Build())
-          .SetLocation(Manifest::INTERNAL)
+          .SetLocation(mojom::ManifestLocation::kInternal)
           .SetID(id)
           .Build();
   service()->AddExtension(extension.get());
diff --git a/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc b/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc
index 6f0cd03..323510b 100644
--- a/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc
+++ b/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc
@@ -56,6 +56,8 @@
 
 namespace extensions {
 
+using mojom::ManifestLocation;
+
 namespace developer = api::developer_private;
 
 namespace {
@@ -160,7 +162,7 @@
   const scoped_refptr<const Extension> CreateExtension(
       const std::string& name,
       std::unique_ptr<base::ListValue> permissions,
-      Manifest::Location location) {
+      mojom::ManifestLocation location) {
     const std::string kId = crx_file::id_util::GenerateId(name);
     scoped_refptr<const Extension> extension =
         ExtensionBuilder()
@@ -268,7 +270,7 @@
   scoped_refptr<const Extension> extension =
       ExtensionBuilder()
           .SetManifest(std::move(manifest))
-          .SetLocation(Manifest::UNPACKED)
+          .SetLocation(ManifestLocation::kUnpacked)
           .SetPath(data_dir())
           .SetID(id)
           .Build();
@@ -367,7 +369,7 @@
   id = crx_file::id_util::GenerateId("beta");
   extension = ExtensionBuilder()
                   .SetManifest(std::move(manifest_copy))
-                  .SetLocation(Manifest::EXTERNAL_PREF)
+                  .SetLocation(ManifestLocation::kExternalPref)
                   .SetID(id)
                   .Build();
   service()->AddExtension(extension.get());
@@ -444,7 +446,7 @@
 TEST_F(ExtensionInfoGeneratorUnitTest, RuntimeHostPermissions) {
   scoped_refptr<const Extension> all_urls_extension = CreateExtension(
       "all_urls", ListBuilder().Append(kAllHostsPermission).Build(),
-      Manifest::INTERNAL);
+      ManifestLocation::kInternal);
 
   std::unique_ptr<developer::ExtensionInfo> info =
       GenerateExtensionInfo(all_urls_extension->id());
@@ -490,8 +492,8 @@
 
   // An extension that doesn't request any host permissions should not have
   // runtime access controls.
-  scoped_refptr<const Extension> no_urls_extension =
-      CreateExtension("no urls", ListBuilder().Build(), Manifest::INTERNAL);
+  scoped_refptr<const Extension> no_urls_extension = CreateExtension(
+      "no urls", ListBuilder().Build(), ManifestLocation::kInternal);
   info = GenerateExtensionInfo(no_urls_extension->id());
   EXPECT_FALSE(info->permissions.runtime_host_permissions);
 }
@@ -503,7 +505,7 @@
        RuntimeHostPermissionsBeyondRequestedScope) {
   scoped_refptr<const Extension> extension =
       CreateExtension("extension", ListBuilder().Append("http://*/*").Build(),
-                      Manifest::INTERNAL);
+                      ManifestLocation::kInternal);
 
   std::unique_ptr<developer::ExtensionInfo> info =
       GenerateExtensionInfo(extension->id());
@@ -551,7 +553,7 @@
                           .Append("https://example.com/*")
                           .Append("https://chromium.org/*")
                           .Build(),
-                      Manifest::INTERNAL);
+                      ManifestLocation::kInternal);
 
   std::unique_ptr<developer::ExtensionInfo> info =
       GenerateExtensionInfo(extension->id());
@@ -587,7 +589,7 @@
 TEST_F(ExtensionInfoGeneratorUnitTest, RuntimeHostPermissionsAllURLs) {
   scoped_refptr<const Extension> all_urls_extension = CreateExtension(
       "all_urls", ListBuilder().Append(kAllHostsPermission).Build(),
-      Manifest::INTERNAL);
+      ManifestLocation::kInternal);
 
   // Withholding host permissions should result in the extension being set to
   // run on click.
@@ -628,7 +630,7 @@
                           .Append("*://example.com/*")
                           .Append("https://chromium.org/*")
                           .Build(),
-                      Manifest::INTERNAL);
+                      ManifestLocation::kInternal);
   ScriptingPermissionsModifier modifier(profile(), extension);
   modifier.SetWithholdHostPermissions(true);
 
@@ -766,7 +768,7 @@
 TEST_F(ExtensionInfoGeneratorUnitTest, ActiveTabFileUrls) {
   scoped_refptr<const Extension> extension =
       CreateExtension("activeTab", ListBuilder().Append("activeTab").Build(),
-                      Manifest::INTERNAL);
+                      ManifestLocation::kInternal);
   std::unique_ptr<developer::ExtensionInfo> info =
       GenerateExtensionInfo(extension->id());
 
@@ -777,10 +779,12 @@
 
 // Tests that blocklisted extensions are returned by the ExtensionInfoGenerator.
 TEST_F(ExtensionInfoGeneratorUnitTest, Blocklisted) {
-  const scoped_refptr<const Extension> extension1 = CreateExtension(
-      "test1", std::make_unique<base::ListValue>(), Manifest::INTERNAL);
-  const scoped_refptr<const Extension> extension2 = CreateExtension(
-      "test2", std::make_unique<base::ListValue>(), Manifest::INTERNAL);
+  const scoped_refptr<const Extension> extension1 =
+      CreateExtension("test1", std::make_unique<base::ListValue>(),
+                      ManifestLocation::kInternal);
+  const scoped_refptr<const Extension> extension2 =
+      CreateExtension("test2", std::make_unique<base::ListValue>(),
+                      ManifestLocation::kInternal);
 
   std::string id1 = extension1->id();
   std::string id2 = extension2->id();
diff --git a/chrome/browser/extensions/api/file_system/consent_provider_unittest.cc b/chrome/browser/extensions/api/file_system/consent_provider_unittest.cc
index 6e8b06e..5d0b9cc 100644
--- a/chrome/browser/extensions/api/file_system/consent_provider_unittest.cc
+++ b/chrome/browser/extensions/api/file_system/consent_provider_unittest.cc
@@ -28,6 +28,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 using extensions::file_system_api::ConsentProvider;
+using extensions::mojom::ManifestLocation;
 using file_manager::Volume;
 
 namespace extensions {
@@ -146,7 +147,7 @@
   {
     scoped_refptr<const Extension> component_extension(
         ExtensionBuilder("Test", ExtensionBuilder::Type::PLATFORM_APP)
-            .SetLocation(Manifest::COMPONENT)
+            .SetLocation(ManifestLocation::kComponent)
             .Build());
     TestingConsentProviderDelegate delegate;
     ConsentProvider provider(&delegate);
@@ -159,7 +160,7 @@
   {
     scoped_refptr<const Extension> allowlisted_component_extension(
         ExtensionBuilder("Test", ExtensionBuilder::Type::PLATFORM_APP)
-            .SetLocation(Manifest::COMPONENT)
+            .SetLocation(ManifestLocation::kComponent)
             .Build());
     TestingConsentProviderDelegate delegate;
     delegate.SetComponentAllowlist(allowlisted_component_extension->id());
@@ -183,7 +184,7 @@
   {
     scoped_refptr<const Extension> allowlisted_extension(
         ExtensionBuilder("Test", ExtensionBuilder::Type::PLATFORM_APP)
-            .SetLocation(Manifest::COMPONENT)
+            .SetLocation(ManifestLocation::kComponent)
             .AddPermission("fileSystem.requestDownloads")
             .Build());
     TestingConsentProviderDelegate delegate;
diff --git a/chrome/browser/extensions/api/image_writer_private/operation_manager.cc b/chrome/browser/extensions/api/image_writer_private/operation_manager.cc
index 3612551..f5daeff 100644
--- a/chrome/browser/extensions/api/image_writer_private/operation_manager.cc
+++ b/chrome/browser/extensions/api/image_writer_private/operation_manager.cc
@@ -43,13 +43,6 @@
   extension_registry_observation_.Observe(
       ExtensionRegistry::Get(browser_context_));
   process_manager_observation_.Observe(ProcessManager::Get(browser_context_));
-  Profile* profile = Profile::FromBrowserContext(browser_context_);
-  registrar_.Add(this,
-                 extensions::NOTIFICATION_EXTENSION_PROCESS_TERMINATED,
-                 content::Source<Profile>(profile));
-  registrar_.Add(this,
-                 extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
-                 content::Source<Profile>(profile));
 }
 
 OperationManager::~OperationManager() {
@@ -257,25 +250,9 @@
   process_manager_observation_.Reset();
 }
 
-void OperationManager::Observe(int type,
-                               const content::NotificationSource& source,
-                               const content::NotificationDetails& details) {
-  switch (type) {
-    case extensions::NOTIFICATION_EXTENSION_PROCESS_TERMINATED: {
-      DeleteOperation(content::Details<const Extension>(details).ptr()->id());
-      break;
-    }
-    case extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE:
-      // Note: |ExtensionHost::extension()| can be null if the extension was
-      // already unloaded, use ExtensionHost::extension_id() instead.
-      DeleteOperation(
-          content::Details<ExtensionHost>(details)->extension_id());
-      break;
-    default: {
-      NOTREACHED();
-      break;
-    }
-  }
+void OperationManager::OnExtensionProcessTerminated(
+    const Extension* extension) {
+  DeleteOperation(extension->id());
 }
 
 OperationManager* OperationManager::Get(content::BrowserContext* context) {
diff --git a/chrome/browser/extensions/api/image_writer_private/operation_manager.h b/chrome/browser/extensions/api/image_writer_private/operation_manager.h
index 93558baf..7265d5b2 100644
--- a/chrome/browser/extensions/api/image_writer_private/operation_manager.h
+++ b/chrome/browser/extensions/api/image_writer_private/operation_manager.h
@@ -16,7 +16,6 @@
 #include "chrome/browser/extensions/api/image_writer_private/operation.h"
 #include "chrome/common/extensions/api/image_writer_private.h"
 #include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
 #include "extensions/browser/browser_context_keyed_api_factory.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_registry_observer.h"
@@ -40,7 +39,6 @@
 // Manages image writer operations for the current profile.  Including clean-up
 // and message routing.
 class OperationManager : public BrowserContextKeyedAPI,
-                         public content::NotificationObserver,
                          public ExtensionRegistryObserver,
                          public ProcessManagerObserver,
                          public base::SupportsWeakPtr<OperationManager> {
@@ -94,11 +92,6 @@
     return "OperationManager";
   }
 
-  // NotificationObserver:
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
-
   // ExtensionRegistryObserver:
   void OnExtensionUnloaded(content::BrowserContext* browser_context,
                            const Extension* extension,
@@ -108,6 +101,7 @@
   // ProcessManagerObserver:
   void OnBackgroundHostClose(const std::string& extension_id) override;
   void OnProcessManagerShutdown(ProcessManager* manager) override;
+  void OnExtensionProcessTerminated(const Extension* extension) override;
 
   Operation* GetOperation(const ExtensionId& extension_id);
   void DeleteOperation(const ExtensionId& extension_id);
@@ -120,7 +114,6 @@
 
   content::BrowserContext* browser_context_;
   OperationMap operations_;
-  content::NotificationRegistrar registrar_;
 
   // Listen to extension unloaded notification.
   base::ScopedObservation<ExtensionRegistry, ExtensionRegistryObserver>
diff --git a/chrome/browser/extensions/api/management/management_api_unittest.cc b/chrome/browser/extensions/api/management/management_api_unittest.cc
index 58a8a5b..d41012b 100644
--- a/chrome/browser/extensions/api/management/management_api_unittest.cc
+++ b/chrome/browser/extensions/api/management/management_api_unittest.cc
@@ -50,6 +50,8 @@
 #include "extensions/common/error_utils.h"
 #endif
 
+using extensions::mojom::ManifestLocation;
+
 namespace extensions {
 
 namespace {
@@ -213,17 +215,21 @@
 // Test that component extensions cannot be disabled, and that policy extensions
 // can be disabled only by component/policy extensions.
 TEST_F(ManagementApiUnitTest, ComponentPolicyDisabling) {
-  auto component =
-      ExtensionBuilder("component").SetLocation(Manifest::COMPONENT).Build();
-  auto component2 =
-      ExtensionBuilder("component2").SetLocation(Manifest::COMPONENT).Build();
-  auto policy =
-      ExtensionBuilder("policy").SetLocation(Manifest::EXTERNAL_POLICY).Build();
+  auto component = ExtensionBuilder("component")
+                       .SetLocation(ManifestLocation::kComponent)
+                       .Build();
+  auto component2 = ExtensionBuilder("component2")
+                        .SetLocation(ManifestLocation::kComponent)
+                        .Build();
+  auto policy = ExtensionBuilder("policy")
+                    .SetLocation(ManifestLocation::kExternalPolicy)
+                    .Build();
   auto policy2 = ExtensionBuilder("policy2")
-                     .SetLocation(Manifest::EXTERNAL_POLICY)
+                     .SetLocation(ManifestLocation::kExternalPolicy)
                      .Build();
-  auto internal =
-      ExtensionBuilder("internal").SetLocation(Manifest::INTERNAL).Build();
+  auto internal = ExtensionBuilder("internal")
+                      .SetLocation(ManifestLocation::kInternal)
+                      .Build();
 
   service()->AddExtension(component.get());
   service()->AddExtension(component2.get());
@@ -266,15 +272,18 @@
 // Test that policy extensions can be enabled only by component/policy
 // extensions.
 TEST_F(ManagementApiUnitTest, ComponentPolicyEnabling) {
-  auto component =
-      ExtensionBuilder("component").SetLocation(Manifest::COMPONENT).Build();
-  auto policy =
-      ExtensionBuilder("policy").SetLocation(Manifest::EXTERNAL_POLICY).Build();
+  auto component = ExtensionBuilder("component")
+                       .SetLocation(ManifestLocation::kComponent)
+                       .Build();
+  auto policy = ExtensionBuilder("policy")
+                    .SetLocation(ManifestLocation::kExternalPolicy)
+                    .Build();
   auto policy2 = ExtensionBuilder("policy2")
-                     .SetLocation(Manifest::EXTERNAL_POLICY)
+                     .SetLocation(ManifestLocation::kExternalPolicy)
                      .Build();
-  auto internal =
-      ExtensionBuilder("internal").SetLocation(Manifest::INTERNAL).Build();
+  auto internal = ExtensionBuilder("internal")
+                      .SetLocation(ManifestLocation::kInternal)
+                      .Build();
 
   service()->AddExtension(component.get());
   service()->AddExtension(policy.get());
diff --git a/chrome/browser/extensions/api/permissions/permissions_api_unittest.cc b/chrome/browser/extensions/api/permissions/permissions_api_unittest.cc
index e0e44e2..4c8d1b1 100644
--- a/chrome/browser/extensions/api/permissions/permissions_api_unittest.cc
+++ b/chrome/browser/extensions/api/permissions/permissions_api_unittest.cc
@@ -43,7 +43,7 @@
   if (allow_file_access)
     creation_flags |= Extension::ALLOW_FILE_ACCESS;
   return ExtensionBuilder()
-      .SetLocation(Manifest::INTERNAL)
+      .SetLocation(mojom::ManifestLocation::kInternal)
       .SetManifest(DictionaryBuilder()
                        .Set("name", name)
                        .Set("description", "foo")
diff --git a/chrome/browser/extensions/api/search/search_api_apitest.cc b/chrome/browser/extensions/api/search/search_api_apitest.cc
index 388e480..a6c55066 100644
--- a/chrome/browser/extensions/api/search/search_api_apitest.cc
+++ b/chrome/browser/extensions/api/search/search_api_apitest.cc
@@ -18,7 +18,13 @@
 }
 
 // Test incognito browser in extension default spanning mode.
-IN_PROC_BROWSER_TEST_F(SearchApiTest, Incognito) {
+// Disabled due to flakes on Ozone testers; see https://crbug.com/1188651.
+#if defined(USE_OZONE)
+#define MAYBE_Incognito DISABLED_Incognito
+#else
+#define MAYBE_Incognito Incognito
+#endif
+IN_PROC_BROWSER_TEST_F(SearchApiTest, MAYBE_Incognito) {
   ResultCatcher catcher;
   CreateIncognitoBrowser(browser()->profile());
   ASSERT_TRUE(RunExtensionTest({.name = "search/query/incognito"},
diff --git a/chrome/browser/extensions/api/sessions/sessions_apitest.cc b/chrome/browser/extensions/api/sessions/sessions_apitest.cc
index 22efe59..d2ec2c8 100644
--- a/chrome/browser/extensions/api/sessions/sessions_apitest.cc
+++ b/chrome/browser/extensions/api/sessions/sessions_apitest.cc
@@ -188,7 +188,7 @@
 void ExtensionSessionsTest::CreateTestExtension() {
   extension_ = ExtensionBuilder("Test")
                    .AddPermissions({"sessions", "tabs"})
-                   .SetLocation(Manifest::INTERNAL)
+                   .SetLocation(mojom::ManifestLocation::kInternal)
                    .Build();
 }
 
diff --git a/chrome/browser/extensions/error_console/error_console_unittest.cc b/chrome/browser/extensions/error_console/error_console_unittest.cc
index 3f6fd549..d5a0748 100644
--- a/chrome/browser/extensions/error_console/error_console_unittest.cc
+++ b/chrome/browser/extensions/error_console/error_console_unittest.cc
@@ -201,7 +201,7 @@
                            .Set("version", "0.0.1")
                            .Set("manifest_version", 2)
                            .Build())
-          .SetLocation(Manifest::UNPACKED)
+          .SetLocation(mojom::ManifestLocation::kUnpacked)
           .SetID(crx_file::id_util::GenerateId("unpacked"))
           .Build();
   scoped_refptr<const Extension> packed_extension =
@@ -211,7 +211,7 @@
                            .Set("version", "0.0.1")
                            .Set("manifest_version", 2)
                            .Build())
-          .SetLocation(Manifest::INTERNAL)
+          .SetLocation(mojom::ManifestLocation::kInternal)
           .SetID(crx_file::id_util::GenerateId("packed"))
           .Build();
 
diff --git a/chrome/browser/extensions/extension_action_runner_unittest.cc b/chrome/browser/extensions/extension_action_runner_unittest.cc
index 4f5148d..e8bba4f1 100644
--- a/chrome/browser/extensions/extension_action_runner_unittest.cc
+++ b/chrome/browser/extensions/extension_action_runner_unittest.cc
@@ -106,7 +106,7 @@
                   .Set("permissions",
                        ListBuilder().Append(kAllHostsPermission).Build())
                   .Build())
-          .SetLocation(Manifest::INTERNAL)
+          .SetLocation(mojom::ManifestLocation::kInternal)
           .SetID(kId)
           .Build();
 
diff --git a/chrome/browser/extensions/extension_checkup_unittest.cc b/chrome/browser/extensions/extension_checkup_unittest.cc
index 0d9f18a..225cace 100644
--- a/chrome/browser/extensions/extension_checkup_unittest.cc
+++ b/chrome/browser/extensions/extension_checkup_unittest.cc
@@ -39,12 +39,14 @@
     // Install policy extension.
     scoped_refptr<const Extension> policy_extension =
         ExtensionBuilder("policy")
-            .SetLocation(Manifest::EXTERNAL_POLICY)
+            .SetLocation(mojom::ManifestLocation::kExternalPolicy)
             .Build();
     service()->AddExtension(policy_extension.get());
     // Install component extension.
     scoped_refptr<const Extension> component_extension =
-        ExtensionBuilder("component").SetLocation(Manifest::COMPONENT).Build();
+        ExtensionBuilder("component")
+            .SetLocation(mojom::ManifestLocation::kComponent)
+            .Build();
     service()->AddExtension(component_extension.get());
     // Load a default installed extension.
     int creation_flags = Extension::WAS_INSTALLED_BY_DEFAULT;
diff --git a/chrome/browser/extensions/extension_context_menu_model_unittest.cc b/chrome/browser/extensions/extension_context_menu_model_unittest.cc
index 1129f1f7..c9063473 100644
--- a/chrome/browser/extensions/extension_context_menu_model_unittest.cc
+++ b/chrome/browser/extensions/extension_context_menu_model_unittest.cc
@@ -68,6 +68,7 @@
 namespace extensions {
 
 using display::test::ScopedScreenOverride;
+using mojom::ManifestLocation;
 
 namespace {
 
@@ -240,11 +241,11 @@
   // specified by |action_key|.
   const Extension* AddExtension(const std::string& name,
                                 const char* action_key,
-                                Manifest::Location location);
+                                ManifestLocation location);
   const Extension* AddExtensionWithHostPermission(
       const std::string& name,
       const char* action_key,
-      Manifest::Location location,
+      ManifestLocation location,
       const std::string& host_permission);
   // TODO(devlin): Consolidate this with the methods above.
   void InitializeAndAddExtension(const Extension& extension);
@@ -285,7 +286,7 @@
 const Extension* ExtensionContextMenuModelTest::AddExtension(
     const std::string& name,
     const char* action_key,
-    Manifest::Location location) {
+    ManifestLocation location) {
   return AddExtensionWithHostPermission(name, action_key, location,
                                         std::string());
 }
@@ -293,7 +294,7 @@
 const Extension* ExtensionContextMenuModelTest::AddExtensionWithHostPermission(
     const std::string& name,
     const char* action_key,
-    Manifest::Location location,
+    ManifestLocation location,
     const std::string& host_permission) {
   DictionaryBuilder manifest;
   manifest.Set("name", name)
@@ -427,8 +428,9 @@
 
   // Test that management policy can determine whether or not policy-installed
   // extensions can be installed/uninstalled.
-  const Extension* extension = AddExtension(
-      "extension", manifest_keys::kPageAction, Manifest::EXTERNAL_POLICY);
+  const Extension* extension =
+      AddExtension("extension", manifest_keys::kPageAction,
+                   ManifestLocation::kExternalPolicy);
 
   ExtensionContextMenuModel menu(extension, GetBrowser(),
                                  ExtensionContextMenuModel::PINNED, nullptr,
@@ -478,7 +480,7 @@
         ExtensionBuilder()
             .SetManifest(base::WrapUnique(manifest->DeepCopy()))
             .SetID(crx_file::id_util::GenerateId("component"))
-            .SetLocation(Manifest::COMPONENT)
+            .SetLocation(ManifestLocation::kComponent)
             .Build();
     service()->AddExtension(extension.get());
 
@@ -510,7 +512,7 @@
         ExtensionBuilder()
             .SetManifest(std::move(manifest))
             .SetID(crx_file::id_util::GenerateId("component_opts"))
-            .SetLocation(Manifest::COMPONENT)
+            .SetLocation(ManifestLocation::kComponent)
             .Build();
     ExtensionContextMenuModel menu(extension.get(), GetBrowser(),
                                    ExtensionContextMenuModel::PINNED, nullptr,
@@ -527,8 +529,8 @@
 TEST_F(ExtensionContextMenuModelTest,
        ExtensionContextMenuStandardItemsAlwaysVisible) {
   InitializeEmptyExtensionService();
-  const Extension* extension =
-      AddExtension("extension", manifest_keys::kPageAction, Manifest::INTERNAL);
+  const Extension* extension = AddExtension(
+      "extension", manifest_keys::kPageAction, ManifestLocation::kInternal);
 
   ExtensionContextMenuModel menu(extension, GetBrowser(),
                                  ExtensionContextMenuModel::PINNED, nullptr,
@@ -557,13 +559,11 @@
   Browser* browser = GetBrowser();
   extension_action_test_util::CreateToolbarModelForProfile(profile());
   const Extension* page_action =
-      AddExtension("page_action_extension",
-                     manifest_keys::kPageAction,
-                     Manifest::INTERNAL);
+      AddExtension("page_action_extension", manifest_keys::kPageAction,
+                   ManifestLocation::kInternal);
   const Extension* browser_action =
-      AddExtension("browser_action_extension",
-                     manifest_keys::kBrowserAction,
-                     Manifest::INTERNAL);
+      AddExtension("browser_action_extension", manifest_keys::kBrowserAction,
+                   ManifestLocation::kInternal);
 
   // For laziness.
   const ExtensionContextMenuModel::MenuEntries visibility_command =
@@ -625,10 +625,10 @@
   Browser* browser = GetBrowser();
   extension_action_test_util::CreateToolbarModelForProfile(profile());
   const Extension* extension = AddExtension(
-      "extension", manifest_keys::kBrowserAction, Manifest::INTERNAL);
+      "extension", manifest_keys::kBrowserAction, ManifestLocation::kInternal);
   const Extension* force_pinned_extension =
       AddExtension("force_pinned_extension", manifest_keys::kBrowserAction,
-                   Manifest::INTERNAL);
+                   ManifestLocation::kInternal);
 
   std::string json = base::StringPrintf(
       R"({
@@ -678,7 +678,7 @@
   InitializeEmptyExtensionService();
 
   const Extension* extension = AddExtension(
-      "extension", manifest_keys::kBrowserAction, Manifest::INTERNAL);
+      "extension", manifest_keys::kBrowserAction, ManifestLocation::kInternal);
   const std::string extension_id = extension->id();
   ASSERT_TRUE(registry()->enabled_extensions().GetByID(extension_id));
 
@@ -711,7 +711,7 @@
   // Add an extension with all urls, and withhold permission.
   const Extension* extension =
       AddExtensionWithHostPermission("extension", manifest_keys::kBrowserAction,
-                                     Manifest::INTERNAL, "*://*/*");
+                                     ManifestLocation::kInternal, "*://*/*");
   ScriptingPermissionsModifier(profile(), extension)
       .SetWithholdHostPermissions(true);
   EXPECT_TRUE(registry()->enabled_extensions().Contains(extension->id()));
@@ -858,7 +858,7 @@
   // should still be present.
   const Extension* single_host_extension = AddExtensionWithHostPermission(
       "single_host_extension", manifest_keys::kBrowserAction,
-      Manifest::INTERNAL, "http://www.example.com/*");
+      ManifestLocation::kInternal, "http://www.example.com/*");
   ExtensionContextMenuModel single_host_menu(
       single_host_extension, GetBrowser(), ExtensionContextMenuModel::PINNED,
       nullptr, true);
@@ -870,7 +870,7 @@
   InitializeEmptyExtensionService();
   {
     const Extension* page_action = AddExtension(
-        "page_action", manifest_keys::kPageAction, Manifest::INTERNAL);
+        "page_action", manifest_keys::kPageAction, ManifestLocation::kInternal);
     ASSERT_TRUE(page_action);
     ExtensionContextMenuModel menu(page_action, GetBrowser(),
                                    ExtensionContextMenuModel::PINNED, nullptr,
@@ -880,8 +880,9 @@
     EXPECT_GE(0, inspect_popup_index);
   }
   {
-    const Extension* browser_action = AddExtension(
-        "browser_action", manifest_keys::kBrowserAction, Manifest::INTERNAL);
+    const Extension* browser_action =
+        AddExtension("browser_action", manifest_keys::kBrowserAction,
+                     ManifestLocation::kInternal);
     ExtensionContextMenuModel menu(browser_action, GetBrowser(),
                                    ExtensionContextMenuModel::PINNED, nullptr,
                                    true);
@@ -892,8 +893,8 @@
   {
     // An extension with no specified action has one synthesized. However,
     // there will never be a popup to inspect, so we shouldn't add a menu item.
-    const Extension* no_action = AddExtension(
-        "no_action", nullptr, Manifest::INTERNAL);
+    const Extension* no_action =
+        AddExtension("no_action", nullptr, ManifestLocation::kInternal);
     ExtensionContextMenuModel menu(no_action, GetBrowser(),
                                    ExtensionContextMenuModel::PINNED, nullptr,
                                    true);
@@ -1173,7 +1174,7 @@
   // Add an extension with all urls, and withhold permissions.
   const Extension* extension =
       AddExtensionWithHostPermission("extension", manifest_keys::kBrowserAction,
-                                     Manifest::INTERNAL, "<all_urls>");
+                                     ManifestLocation::kInternal, "<all_urls>");
   ScriptingPermissionsModifier(profile(), extension)
       .SetWithholdHostPermissions(true);
 
@@ -1237,7 +1238,7 @@
   // Add an extension with all urls, and withhold permissions.
   const Extension* extension =
       AddExtensionWithHostPermission("extension", manifest_keys::kBrowserAction,
-                                     Manifest::INTERNAL, "<all_urls>");
+                                     ManifestLocation::kInternal, "<all_urls>");
   ScriptingPermissionsModifier modifier(profile(), extension);
   modifier.SetWithholdHostPermissions(true);
 
diff --git a/chrome/browser/extensions/extension_garbage_collector_chromeos_unittest.cc b/chrome/browser/extensions/extension_garbage_collector_chromeos_unittest.cc
index 846cfe1..5a9ba408 100644
--- a/chrome/browser/extensions/extension_garbage_collector_chromeos_unittest.cc
+++ b/chrome/browser/extensions/extension_garbage_collector_chromeos_unittest.cc
@@ -123,7 +123,7 @@
         .SetVersion(version)
         .SetID(id)
         .SetPath(path)
-        .SetLocation(Manifest::INTERNAL)
+        .SetLocation(mojom::ManifestLocation::kInternal)
         .Build();
   }
 
diff --git a/chrome/browser/extensions/extension_install_prompt_unittest.cc b/chrome/browser/extensions/extension_install_prompt_unittest.cc
index 5c9e256..6c7045c 100644
--- a/chrome/browser/extensions/extension_install_prompt_unittest.cc
+++ b/chrome/browser/extensions/extension_install_prompt_unittest.cc
@@ -263,7 +263,7 @@
   scoped_refptr<const Extension> extension =
       ExtensionBuilder("all_hosts")
           .AddPermission("<all_urls>")
-          .SetLocation(Manifest::EXTERNAL_POLICY)
+          .SetLocation(mojom::ManifestLocation::kExternalPolicy)
           .Build();
   content::TestWebContentsFactory factory;
   ExtensionInstallPrompt prompt(factory.CreateWebContents(profile()));
diff --git a/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc b/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc
index 8e49485..670e8b0 100644
--- a/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc
+++ b/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc
@@ -51,6 +51,8 @@
 #include "extensions/common/value_builder.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using extensions::mojom::ManifestLocation;
+
 namespace {
 
 const char kId1[] = "iccfkkhkfiphcjdakkmcjmkfboccmndk";
@@ -187,7 +189,7 @@
 
   testing::AssertionResult LoadGenericExtension(const std::string& index,
                                                 const std::string& id,
-                                                Manifest::Location location) {
+                                                ManifestLocation location) {
     ExtensionBuilder builder;
     builder.SetManifest(DictionaryBuilder()
                             .Set("name", std::string("Extension " + index))
@@ -203,10 +205,9 @@
     return testing::AssertionFailure() << "Could not install extension: " << id;
   }
 
-  testing::AssertionResult LoadExtensionWithAction(
-      const std::string& index,
-      const std::string& id,
-      Manifest::Location location) {
+  testing::AssertionResult LoadExtensionWithAction(const std::string& index,
+                                                   const std::string& id,
+                                                   ManifestLocation location) {
     ExtensionBuilder builder;
     builder.SetManifest(
         DictionaryBuilder()
@@ -229,7 +230,7 @@
   testing::AssertionResult LoadExtensionOverridingHome(
       const std::string& index,
       const std::string& id,
-      Manifest::Location location) {
+      ManifestLocation location) {
     ExtensionBuilder builder;
     builder.SetManifest(DictionaryBuilder()
                             .Set("name", std::string("Extension " + index))
@@ -252,7 +253,7 @@
   testing::AssertionResult LoadExtensionOverridingStart(
       const std::string& index,
       const std::string& id,
-      Manifest::Location location) {
+      ManifestLocation location) {
     ExtensionBuilder builder;
     builder.SetManifest(
         DictionaryBuilder()
@@ -277,7 +278,7 @@
   testing::AssertionResult LoadExtensionOverridingNtp(
       const std::string& index,
       const std::string& id,
-      Manifest::Location location) {
+      ManifestLocation location) {
     ExtensionBuilder builder;
     builder.SetManifest(
         DictionaryBuilder()
@@ -300,7 +301,7 @@
   testing::AssertionResult LoadExtensionOverridingProxy(
       const std::string& index,
       const std::string& id,
-      Manifest::Location location) {
+      ManifestLocation location) {
     ExtensionBuilder builder;
     builder.SetManifest(
         DictionaryBuilder()
@@ -432,8 +433,10 @@
        DISABLED_BubbleCorrectlyReshowsOnDeactivationDismissal) {
   Init();
 
-  ASSERT_TRUE(LoadExtensionOverridingNtp("1", kId1, Manifest::INTERNAL));
-  ASSERT_TRUE(LoadExtensionOverridingNtp("2", kId2, Manifest::INTERNAL));
+  ASSERT_TRUE(
+      LoadExtensionOverridingNtp("1", kId1, ManifestLocation::kInternal));
+  ASSERT_TRUE(
+      LoadExtensionOverridingNtp("2", kId2, ManifestLocation::kInternal));
   std::unique_ptr<TestExtensionMessageBubbleController> controller(
       new TestExtensionMessageBubbleController(
           new NtpOverriddenBubbleDelegate(browser()->profile()), browser()));
@@ -502,9 +505,11 @@
   Init();
   // Add three extensions, and control two of them in this test (extension 1
   // and 2).
-  ASSERT_TRUE(LoadExtensionWithAction("1", kId1, Manifest::COMMAND_LINE));
-  ASSERT_TRUE(LoadGenericExtension("2", kId2, Manifest::UNPACKED));
-  ASSERT_TRUE(LoadGenericExtension("3", kId3, Manifest::EXTERNAL_POLICY));
+  ASSERT_TRUE(
+      LoadExtensionWithAction("1", kId1, ManifestLocation::kCommandLine));
+  ASSERT_TRUE(LoadGenericExtension("2", kId2, ManifestLocation::kUnpacked));
+  ASSERT_TRUE(
+      LoadGenericExtension("3", kId3, ManifestLocation::kExternalPolicy));
 
   std::unique_ptr<TestExtensionMessageBubbleController> controller(
       new TestExtensionMessageBubbleController(
@@ -584,9 +589,11 @@
   // Add three extensions, and control two of them in this test (extension 1
   // and 2). Extension 1 is a regular extension, Extension 2 is UNPACKED so it
   // counts as a DevMode extension.
-  ASSERT_TRUE(LoadExtensionWithAction("1", kId1, Manifest::COMMAND_LINE));
-  ASSERT_TRUE(LoadGenericExtension("2", kId2, Manifest::UNPACKED));
-  ASSERT_TRUE(LoadGenericExtension("3", kId3, Manifest::EXTERNAL_POLICY));
+  ASSERT_TRUE(
+      LoadExtensionWithAction("1", kId1, ManifestLocation::kCommandLine));
+  ASSERT_TRUE(LoadGenericExtension("2", kId2, ManifestLocation::kUnpacked));
+  ASSERT_TRUE(
+      LoadGenericExtension("3", kId3, ManifestLocation::kExternalPolicy));
 
   std::unique_ptr<TestExtensionMessageBubbleController> controller(
       new TestExtensionMessageBubbleController(
@@ -669,7 +676,7 @@
       FeatureSwitch::force_dev_mode_highlighting(), true);
   Init();
 
-  ASSERT_TRUE(LoadGenericExtension("1", kId1, Manifest::UNPACKED));
+  ASSERT_TRUE(LoadGenericExtension("1", kId1, ManifestLocation::kUnpacked));
 
   auto get_controller = [](Browser* browser) {
     auto controller = std::make_unique<TestExtensionMessageBubbleController>(
@@ -747,10 +754,12 @@
         // Load two extensions overriding home page and one overriding something
         // unrelated (to check for interference). Extension 2 should still win
         // on the home page setting.
-        ASSERT_TRUE(LoadExtensionOverridingHome("1", kId1, Manifest::UNPACKED));
-        ASSERT_TRUE(LoadExtensionOverridingHome("2", kId2, Manifest::UNPACKED));
-        ASSERT_TRUE(
-            LoadExtensionOverridingStart("3", kId3, Manifest::UNPACKED));
+        ASSERT_TRUE(LoadExtensionOverridingHome("1", kId1,
+                                                ManifestLocation::kUnpacked));
+        ASSERT_TRUE(LoadExtensionOverridingHome("2", kId2,
+                                                ManifestLocation::kUnpacked));
+        ASSERT_TRUE(LoadExtensionOverridingStart("3", kId3,
+                                                 ManifestLocation::kUnpacked));
         break;
       case BUBBLE_TYPE_SEARCH_ENGINE:
         // We deliberately skip testing the search engine since it relies on
@@ -763,11 +772,12 @@
         // Load two extensions overriding start page and one overriding
         // something unrelated (to check for interference). Extension 2 should
         // still win on the startup page setting.
-        ASSERT_TRUE(
-            LoadExtensionOverridingStart("1", kId1, Manifest::UNPACKED));
-        ASSERT_TRUE(
-            LoadExtensionOverridingStart("2", kId2, Manifest::UNPACKED));
-        ASSERT_TRUE(LoadExtensionOverridingHome("3", kId3, Manifest::UNPACKED));
+        ASSERT_TRUE(LoadExtensionOverridingStart("1", kId1,
+                                                 ManifestLocation::kUnpacked));
+        ASSERT_TRUE(LoadExtensionOverridingStart("2", kId2,
+                                                 ManifestLocation::kUnpacked));
+        ASSERT_TRUE(LoadExtensionOverridingHome("3", kId3,
+                                                ManifestLocation::kUnpacked));
         break;
       default:
         NOTREACHED();
@@ -881,7 +891,8 @@
 // enabled extension is uninstalled.
 TEST_F(ExtensionMessageBubbleTest, BubbleClosedAfterEnabledExtensionUninstall) {
   Init();
-  ASSERT_TRUE(LoadExtensionOverridingNtp("1", kId1, Manifest::UNPACKED));
+  ASSERT_TRUE(
+      LoadExtensionOverridingNtp("1", kId1, ManifestLocation::kUnpacked));
 
   auto controller = std::make_unique<TestExtensionMessageBubbleController>(
       new NtpOverriddenBubbleDelegate(browser()->profile()), browser());
@@ -914,7 +925,8 @@
 TEST_F(ExtensionMessageBubbleTest,
        BubbleClosedAfterDisabledExtensionUninstall) {
   Init();
-  ASSERT_TRUE(LoadExtensionOverridingNtp("1", kId1, Manifest::COMMAND_LINE));
+  ASSERT_TRUE(
+      LoadExtensionOverridingNtp("1", kId1, ManifestLocation::kCommandLine));
 
   auto controller = std::make_unique<TestExtensionMessageBubbleController>(
       new SuspiciousExtensionBubbleDelegate(browser()->profile()), browser());
@@ -968,9 +980,9 @@
   FeatureSwitch::ScopedOverride force_dev_mode_highlighting(
       FeatureSwitch::force_dev_mode_highlighting(), true);
   Init();
-  ASSERT_TRUE(LoadGenericExtension("1", kId1, Manifest::UNPACKED));
-  ASSERT_TRUE(LoadGenericExtension("2", kId2, Manifest::UNPACKED));
-  ASSERT_TRUE(LoadGenericExtension("3", kId3, Manifest::UNPACKED));
+  ASSERT_TRUE(LoadGenericExtension("1", kId1, ManifestLocation::kUnpacked));
+  ASSERT_TRUE(LoadGenericExtension("2", kId2, ManifestLocation::kUnpacked));
+  ASSERT_TRUE(LoadGenericExtension("3", kId3, ManifestLocation::kUnpacked));
 
   auto controller = std::make_unique<TestExtensionMessageBubbleController>(
       new DevModeBubbleDelegate(browser()->profile()), browser());
@@ -1013,9 +1025,12 @@
   // Load two extensions overriding new tab page and one overriding something
   // unrelated (to check for interference). Extension 2 should still win
   // on the new tab page setting.
-  ASSERT_TRUE(LoadExtensionOverridingNtp("1", kId1, Manifest::UNPACKED));
-  ASSERT_TRUE(LoadExtensionOverridingNtp("2", kId2, Manifest::UNPACKED));
-  ASSERT_TRUE(LoadExtensionOverridingStart("3", kId3, Manifest::UNPACKED));
+  ASSERT_TRUE(
+      LoadExtensionOverridingNtp("1", kId1, ManifestLocation::kUnpacked));
+  ASSERT_TRUE(
+      LoadExtensionOverridingNtp("2", kId2, ManifestLocation::kUnpacked));
+  ASSERT_TRUE(
+      LoadExtensionOverridingStart("3", kId3, ManifestLocation::kUnpacked));
 
   std::unique_ptr<TestExtensionMessageBubbleController> controller(
       new TestExtensionMessageBubbleController(
@@ -1123,18 +1138,21 @@
 // still pass on Linux and Mac.
 TEST_F(ExtensionMessageBubbleTest, ShowNtpBubblePerProfilePerExtensionTest) {
   Init();
-  ASSERT_TRUE(LoadExtensionOverridingNtp("1", kId1, Manifest::UNPACKED));
+  ASSERT_TRUE(
+      LoadExtensionOverridingNtp("1", kId1, ManifestLocation::kUnpacked));
   std::unique_ptr<TestExtensionMessageBubbleController> controller(
       std::make_unique<TestExtensionMessageBubbleController>(
           new NtpOverriddenBubbleDelegate(browser()->profile()), browser()));
   ShowAndDismissBubbleByDeactivation(controller.get(), "Extension 1");
 
-  ASSERT_TRUE(LoadExtensionOverridingNtp("2", kId2, Manifest::UNPACKED));
+  ASSERT_TRUE(
+      LoadExtensionOverridingNtp("2", kId2, ManifestLocation::kUnpacked));
   controller = std::make_unique<TestExtensionMessageBubbleController>(
       new NtpOverriddenBubbleDelegate(browser()->profile()), browser());
   ShowAndDismissBubbleByDeactivation(controller.get(), "Extension 2");
 
-  ASSERT_TRUE(LoadExtensionOverridingNtp("3", kId3, Manifest::UNPACKED));
+  ASSERT_TRUE(
+      LoadExtensionOverridingNtp("3", kId3, ManifestLocation::kUnpacked));
   controller = std::make_unique<TestExtensionMessageBubbleController>(
       new NtpOverriddenBubbleDelegate(browser()->profile()), browser());
   ShowAndDismissBubbleByDeactivation(controller.get(), "Extension 3");
@@ -1181,9 +1199,12 @@
   // Load two extensions overriding proxy and one overriding something
   // unrelated (to check for interference). Extension 2 should still win
   // on the proxy setting.
-  ASSERT_TRUE(LoadExtensionOverridingProxy("1", kId1, Manifest::UNPACKED));
-  ASSERT_TRUE(LoadExtensionOverridingProxy("2", kId2, Manifest::UNPACKED));
-  ASSERT_TRUE(LoadExtensionOverridingStart("3", kId3, Manifest::UNPACKED));
+  ASSERT_TRUE(
+      LoadExtensionOverridingProxy("1", kId1, ManifestLocation::kUnpacked));
+  ASSERT_TRUE(
+      LoadExtensionOverridingProxy("2", kId2, ManifestLocation::kUnpacked));
+  ASSERT_TRUE(
+      LoadExtensionOverridingStart("3", kId3, ManifestLocation::kUnpacked));
 
   // The bubble will not show if the extension was installed in the last 7 days
   // so we artificially set the install time to simulate an old install during
@@ -1307,7 +1328,7 @@
   ToolbarActionsModel* model = ToolbarActionsModel::Get(profile());
   base::RunLoop().RunUntilIdle();
 
-  ASSERT_TRUE(LoadExtensionWithAction("1", kId1, Manifest::UNPACKED));
+  ASSERT_TRUE(LoadExtensionWithAction("1", kId1, ManifestLocation::kUnpacked));
 
   auto controller = std::make_unique<TestExtensionMessageBubbleController>(
       new DevModeBubbleDelegate(browser()->profile()), browser());
@@ -1333,7 +1354,7 @@
   ToolbarActionsModel* model = ToolbarActionsModel::Get(profile());
   base::RunLoop().RunUntilIdle();
 
-  ASSERT_TRUE(LoadExtensionWithAction("1", kId1, Manifest::UNPACKED));
+  ASSERT_TRUE(LoadExtensionWithAction("1", kId1, ManifestLocation::kUnpacked));
 
   auto controller = std::make_unique<TestExtensionMessageBubbleController>(
       new DevModeBubbleDelegate(browser()->profile()), browser());
@@ -1360,7 +1381,7 @@
   ToolbarActionsModel* model = ToolbarActionsModel::Get(profile());
   base::RunLoop().RunUntilIdle();
 
-  ASSERT_TRUE(LoadExtensionWithAction("1", kId1, Manifest::UNPACKED));
+  ASSERT_TRUE(LoadExtensionWithAction("1", kId1, ManifestLocation::kUnpacked));
 
   auto controller = std::make_unique<TestExtensionMessageBubbleController>(
       new DevModeBubbleDelegate(browser()->profile()), browser());
@@ -1380,7 +1401,8 @@
 TEST_F(ExtensionMessageBubbleTest, TestShouldShowMethod) {
   Init();
   ExtensionRegistry* registry = ExtensionRegistry::Get(profile());
-  ASSERT_TRUE(LoadExtensionOverridingNtp("1", kId1, Manifest::UNPACKED));
+  ASSERT_TRUE(
+      LoadExtensionOverridingNtp("1", kId1, ManifestLocation::kUnpacked));
   ASSERT_TRUE(registry->enabled_extensions().GetByID(kId1));
 
   std::unique_ptr<TestExtensionMessageBubbleController> ntp_bubble_controller(
diff --git a/chrome/browser/extensions/extension_prefs_unittest.cc b/chrome/browser/extensions/extension_prefs_unittest.cc
index 6aa63a4..781e780 100644
--- a/chrome/browser/extensions/extension_prefs_unittest.cc
+++ b/chrome/browser/extensions/extension_prefs_unittest.cc
@@ -945,7 +945,7 @@
     // Adding a component extension.
     component_extension_ =
         ExtensionBuilder("a")
-            .SetLocation(Manifest::COMPONENT)
+            .SetLocation(mojom::ManifestLocation::kComponent)
             .SetPath(prefs_.extensions_dir().AppendASCII("a"))
             .Build();
     prefs_.AddExtension(component_extension_.get());
@@ -953,7 +953,7 @@
     // Adding a non component extension.
     no_component_extension_ =
         ExtensionBuilder("b")
-            .SetLocation(Manifest::INTERNAL)
+            .SetLocation(mojom::ManifestLocation::kInternal)
             .SetPath(prefs_.extensions_dir().AppendASCII("b"))
             .Build();
     prefs_.AddExtension(no_component_extension_.get());
diff --git a/chrome/browser/extensions/extension_protocols_unittest.cc b/chrome/browser/extensions/extension_protocols_unittest.cc
index 1437721..da7103b 100644
--- a/chrome/browser/extensions/extension_protocols_unittest.cc
+++ b/chrome/browser/extensions/extension_protocols_unittest.cc
@@ -804,7 +804,7 @@
       ExtensionBuilder()
           .SetManifest(std::move(manifest))
           .SetPath(unpacked_path)
-          .SetLocation(Manifest::INTERNAL)
+          .SetLocation(mojom::ManifestLocation::kInternal)
           .Build();
   ASSERT_TRUE(extension);
 
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index f2a978e..801ecb7 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -172,6 +172,7 @@
 using content::BrowserThread;
 using content::DOMStorageContext;
 using content::PluginService;
+using extensions::mojom::ManifestLocation;
 
 namespace extensions {
 
@@ -258,7 +259,7 @@
 
 scoped_refptr<const Extension> CreateExtension(const std::string& name,
                                                const base::FilePath& path,
-                                               Manifest::Location location) {
+                                               ManifestLocation location) {
   return ExtensionBuilder(name).SetPath(path).SetLocation(location).Build();
 }
 
@@ -6971,7 +6972,7 @@
   scoped_refptr<const Extension> external_component_extension = CreateExtension(
       "external_component_extension",
       base::FilePath(FILE_PATH_LITERAL("//external_component_extension")),
-      Manifest::EXTERNAL_COMPONENT);
+      ManifestLocation::kExternalComponent);
   service_->AddExtension(external_component_extension.get());
   EXPECT_TRUE(registry()->enabled_extensions().Contains(
       external_component_extension->id()));
@@ -6983,7 +6984,7 @@
   scoped_refptr<const Extension> component_extension = CreateExtension(
       "component_extension",
       base::FilePath(FILE_PATH_LITERAL("//component_extension")),
-      Manifest::COMPONENT);
+      ManifestLocation::kComponent);
   service_->AddExtension(component_extension.get());
   EXPECT_TRUE(
       registry()->enabled_extensions().Contains(component_extension->id()));
@@ -7708,12 +7709,12 @@
   scoped_refptr<const Extension> cast_extension =
       ExtensionBuilder("stable")
           .SetID(cast_stable)
-          .SetLocation(Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .Build();
   scoped_refptr<const Extension> cast_beta_extension =
       ExtensionBuilder("beta")
           .SetID(cast_beta)
-          .SetLocation(Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .Build();
   service()->AddExtension(cast_extension.get());
   service()->AddExtension(cast_beta_extension.get());
@@ -7733,7 +7734,7 @@
   scoped_refptr<const Extension> cast_extension =
       ExtensionBuilder("stable")
           .SetID(cast_stable)
-          .SetLocation(Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .Build();
   service()->AddExtension(cast_extension.get());
   service()->DisableExtension(cast_stable, disable_reason::DISABLE_USER_ACTION);
@@ -7752,7 +7753,7 @@
   scoped_refptr<const Extension> genius_extension =
       ExtensionBuilder("genius")
           .SetID(genius_app)
-          .SetLocation(Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .Build();
   service()->AddComponentExtension(genius_extension.get());
   ASSERT_TRUE(registry()->enabled_extensions().Contains(genius_app));
@@ -7771,7 +7772,7 @@
   scoped_refptr<const Extension> good_extension =
       ExtensionBuilder("good")
           .SetID(good0)
-          .SetLocation(Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .Build();
   service()->AddComponentExtension(good_extension.get());
   ASSERT_TRUE(registry()->enabled_extensions().Contains(good0));
@@ -7790,12 +7791,12 @@
   scoped_refptr<const Extension> cast_extension =
       ExtensionBuilder("stable")
           .SetID(cast_stable)
-          .SetLocation(Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .Build();
   scoped_refptr<const Extension> genius_extension =
       ExtensionBuilder("genius")
           .SetID(genius_app)
-          .SetLocation(Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .Build();
   service()->AddExtension(cast_extension.get());
   service()->AddComponentExtension(genius_extension.get());
diff --git a/chrome/browser/extensions/extension_web_ui_unittest.cc b/chrome/browser/extensions/extension_web_ui_unittest.cc
index 29c025fd2..e1fbcc7 100644
--- a/chrome/browser/extensions/extension_web_ui_unittest.cc
+++ b/chrome/browser/extensions/extension_web_ui_unittest.cc
@@ -31,6 +31,8 @@
 #include "chrome/browser/ash/settings/scoped_cros_settings_test_helper.h"
 #endif
 
+using extensions::mojom::ManifestLocation;
+
 namespace extensions {
 
 namespace {
@@ -87,7 +89,7 @@
   scoped_refptr<const Extension> ext_unpacked(
       ExtensionBuilder()
           .SetManifest(manifest.Build())
-          .SetLocation(Manifest::UNPACKED)
+          .SetLocation(ManifestLocation::kUnpacked)
           .SetID("abcdefghijabcdefghijabcdefghijaa")
           .Build());
   extension_service_->AddExtension(ext_unpacked.get());
@@ -123,7 +125,7 @@
   scoped_refptr<const Extension> ext_component(
       ExtensionBuilder()
           .SetManifest(manifest2.Build())
-          .SetLocation(Manifest::COMPONENT)
+          .SetLocation(ManifestLocation::kComponent)
           .SetID("bbabcdefghijabcdefghijabcdefghij")
           .Build());
   extension_service_->AddComponentExtension(ext_component.get());
@@ -265,7 +267,7 @@
         DictionaryBuilder().Set("newtab", "newtab.html").Build();
     scoped_refptr<const Extension> extension =
         ExtensionBuilder(name)
-            .SetLocation(Manifest::INTERNAL)
+            .SetLocation(ManifestLocation::kInternal)
             .SetManifestKey("chrome_url_overrides",
                             std::move(chrome_url_overrides))
             .Build();
diff --git a/chrome/browser/extensions/install_tracker_unittest.cc b/chrome/browser/extensions/install_tracker_unittest.cc
index 58949bf3..1779b63 100644
--- a/chrome/browser/extensions/install_tracker_unittest.cc
+++ b/chrome/browser/extensions/install_tracker_unittest.cc
@@ -31,7 +31,7 @@
 
 scoped_refptr<const Extension> CreateDummyExtension(const std::string& id) {
   return extensions::ExtensionBuilder("Dummy name")
-      .SetLocation(extensions::Manifest::INTERNAL)
+      .SetLocation(extensions::mojom::ManifestLocation::kInternal)
       .SetID(id)
       .Build();
 }
diff --git a/chrome/browser/extensions/install_verifier_unittest.cc b/chrome/browser/extensions/install_verifier_unittest.cc
index 7082fc57..4501f018 100644
--- a/chrome/browser/extensions/install_verifier_unittest.cc
+++ b/chrome/browser/extensions/install_verifier_unittest.cc
@@ -19,6 +19,8 @@
 #include "extensions/common/value_builder.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using extensions::mojom::ManifestLocation;
+
 namespace extensions {
 
 class InstallVerifierTest : public ExtensionServiceTestBase {
@@ -68,27 +70,28 @@
   GURL non_store_update_url("https://example.com");
   struct {
     const char* test_name;
-    Manifest::Location location;
+    ManifestLocation location;
     base::Optional<GURL> update_url;
     FromStoreStatus expected_from_store_status;
     MustRemainDisabledStatus expected_must_remain_disabled_status;
   } test_cases[] = {
-      {"internal from store", Manifest::INTERNAL, store_update_url, FROM_STORE,
-       CAN_BE_ENABLED},
-      {"internal non-store update url", Manifest::INTERNAL,
+      {"internal from store", ManifestLocation::kInternal, store_update_url,
+       FROM_STORE, CAN_BE_ENABLED},
+      {"internal non-store update url", ManifestLocation::kInternal,
        non_store_update_url, NOT_FROM_STORE, MUST_REMAIN_DISABLED},
-      {"internal no update url", Manifest::INTERNAL, base::nullopt,
+      {"internal no update url", ManifestLocation::kInternal, base::nullopt,
        NOT_FROM_STORE, MUST_REMAIN_DISABLED},
-      {"unpacked from store", Manifest::UNPACKED, store_update_url, FROM_STORE,
-       CAN_BE_ENABLED},
-      {"unpacked non-store update url", Manifest::UNPACKED,
+      {"unpacked from store", ManifestLocation::kUnpacked, store_update_url,
+       FROM_STORE, CAN_BE_ENABLED},
+      {"unpacked non-store update url", ManifestLocation::kUnpacked,
        non_store_update_url, NOT_FROM_STORE, CAN_BE_ENABLED},
-      {"unpacked no update url", Manifest::UNPACKED, base::nullopt,
+      {"unpacked no update url", ManifestLocation::kUnpacked, base::nullopt,
        NOT_FROM_STORE, CAN_BE_ENABLED},
-      {"external from store", Manifest::EXTERNAL_POLICY_DOWNLOAD,
+      {"external from store", ManifestLocation::kExternalPolicyDownload,
        store_update_url, FROM_STORE, CAN_BE_ENABLED},
-      {"external non-store update url", Manifest::EXTERNAL_POLICY_DOWNLOAD,
-       non_store_update_url, NOT_FROM_STORE, CAN_BE_ENABLED},
+      {"external non-store update url",
+       ManifestLocation::kExternalPolicyDownload, non_store_update_url,
+       NOT_FROM_STORE, CAN_BE_ENABLED},
   };
 
   InstallVerifier* install_verifier = InstallVerifier::Get(profile());
@@ -102,7 +105,8 @@
     }
     scoped_refptr<const Extension> extension = extension_builder.Build();
 
-    if (Manifest::IsPolicyLocation(test_case.location))
+    if (Manifest::IsPolicyLocation(
+            static_cast<Manifest::Location>(test_case.location)))
       AddExtensionAsPolicyInstalled(extension->id());
 
     EXPECT_EQ(test_case.expected_from_store_status == FROM_STORE,
diff --git a/chrome/browser/extensions/installed_loader_unittest.cc b/chrome/browser/extensions/installed_loader_unittest.cc
index f665824..3ec9b3b 100644
--- a/chrome/browser/extensions/installed_loader_unittest.cc
+++ b/chrome/browser/extensions/installed_loader_unittest.cc
@@ -44,7 +44,8 @@
 const Extension* InstalledLoaderUnitTest::AddExtension() {
   // Metrics aren't recorded for unpacked extensions, so we need to make sure
   // the extension has an INTERNAL location.
-  constexpr Manifest::Location kManifestLocation = Manifest::INTERNAL;
+  constexpr mojom::ManifestLocation kManifestLocation =
+      mojom::ManifestLocation::kInternal;
   scoped_refptr<const Extension> extension = ExtensionBuilder("test")
                                                  .AddPermissions({"<all_urls>"})
                                                  .SetLocation(kManifestLocation)
diff --git a/chrome/browser/extensions/permission_messages_unittest.cc b/chrome/browser/extensions/permission_messages_unittest.cc
index c4b4b1e..2124689 100644
--- a/chrome/browser/extensions/permission_messages_unittest.cc
+++ b/chrome/browser/extensions/permission_messages_unittest.cc
@@ -61,7 +61,7 @@
                .SetManifestKey("optional_permissions",
                                std::move(optional_permissions))
                .SetID(crx_file::id_util::GenerateId("extension"))
-               .SetLocation(Manifest::INTERNAL)
+               .SetLocation(mojom::ManifestLocation::kInternal)
                .Build();
     env_.GetExtensionService()->AddExtension(app_.get());
   }
diff --git a/chrome/browser/extensions/permissions_updater_unittest.cc b/chrome/browser/extensions/permissions_updater_unittest.cc
index 8dc82b6..259e384 100644
--- a/chrome/browser/extensions/permissions_updater_unittest.cc
+++ b/chrome/browser/extensions/permissions_updater_unittest.cc
@@ -47,7 +47,7 @@
     std::unique_ptr<base::Value> permissions,
     const std::string& name) {
   return ExtensionBuilder()
-      .SetLocation(Manifest::INTERNAL)
+      .SetLocation(mojom::ManifestLocation::kInternal)
       .SetManifest(
           DictionaryBuilder()
               .Set("name", name)
diff --git a/chrome/browser/extensions/scripting_permissions_modifier_unittest.cc b/chrome/browser/extensions/scripting_permissions_modifier_unittest.cc
index 6b37529..5295f54b 100644
--- a/chrome/browser/extensions/scripting_permissions_modifier_unittest.cc
+++ b/chrome/browser/extensions/scripting_permissions_modifier_unittest.cc
@@ -31,6 +31,8 @@
 #include "extensions/test/test_extension_dir.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
+using extensions::mojom::ManifestLocation;
+
 namespace extensions {
 
 namespace {
@@ -107,7 +109,7 @@
         ExtensionBuilder(test_case_name)
             .AddPermissions(test_case)
             .AddContentScript("foo.js", test_case)
-            .SetLocation(Manifest::INTERNAL)
+            .SetLocation(ManifestLocation::kInternal)
             .Build();
 
     PermissionsUpdater(profile()).InitializePermissions(extension.get());
@@ -155,7 +157,7 @@
       ExtensionBuilder("a")
           .AddPermissions({kHostGoogle, kHostChromium})
           .AddContentScript("foo.js", {kHostGoogle})
-          .SetLocation(Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .AddFlags(Extension::WITHHOLD_PERMISSIONS)
           .Build();
 
@@ -412,7 +414,7 @@
       ExtensionBuilder("a")
           .AddPermission(URLPattern::kAllUrlsPattern)
           .AddContentScript("foo.js", {URLPattern::kAllUrlsPattern})
-          .SetLocation(Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .Build();
   PermissionsUpdater updater(profile());
   updater.InitializePermissions(extension.get());
@@ -442,7 +444,7 @@
       ExtensionBuilder("extension")
           .AddPermission(URLPattern::kAllUrlsPattern)
           .AddContentScript("foo.js", {URLPattern::kAllUrlsPattern})
-          .SetLocation(Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .Build();
   PermissionsUpdater(profile()).InitializePermissions(extension.get());
 
@@ -499,12 +501,14 @@
   InitializeEmptyExtensionService();
 
   struct {
-    Manifest::Location location;
+    ManifestLocation location;
     bool can_be_affected;
   } test_cases[] = {
-      {Manifest::INTERNAL, true},   {Manifest::EXTERNAL_PREF, true},
-      {Manifest::UNPACKED, true},   {Manifest::EXTERNAL_POLICY_DOWNLOAD, false},
-      {Manifest::COMPONENT, false},
+      {ManifestLocation::kInternal, true},
+      {ManifestLocation::kExternalPref, true},
+      {ManifestLocation::kUnpacked, true},
+      {ManifestLocation::kExternalPolicyDownload, false},
+      {ManifestLocation::kComponent, false},
   };
 
   for (const auto& test_case : test_cases) {
@@ -1021,7 +1025,7 @@
   scoped_refptr<const Extension> extension =
       ExtensionBuilder("extension")
           .AddContentScript("foo.js", {"https://www.example.com/foo"})
-          .SetLocation(Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .Build();
   InitializeExtensionPermissions(profile(), *extension);
 
diff --git a/chrome/browser/extensions/standard_management_policy_provider_unittest.cc b/chrome/browser/extensions/standard_management_policy_provider_unittest.cc
index 67e73552..ff0aa31 100644
--- a/chrome/browser/extensions/standard_management_policy_provider_unittest.cc
+++ b/chrome/browser/extensions/standard_management_policy_provider_unittest.cc
@@ -16,6 +16,8 @@
 #include "extensions/common/manifest_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using extensions::mojom::ManifestLocation;
+
 namespace extensions {
 
 class StandardManagementPolicyProviderTest : public testing::Test {
@@ -25,7 +27,7 @@
         provider_(settings_.get()) {}
 
  protected:
-  scoped_refptr<const Extension> CreateExtension(Manifest::Location location) {
+  scoped_refptr<const Extension> CreateExtension(ManifestLocation location) {
     return ExtensionBuilder("test").SetLocation(location).Build();
   }
 
@@ -40,7 +42,7 @@
 // Tests the behavior of the ManagementPolicy provider methods for an
 // extension required by policy.
 TEST_F(StandardManagementPolicyProviderTest, RequiredExtension) {
-  auto extension = CreateExtension(Manifest::EXTERNAL_POLICY_DOWNLOAD);
+  auto extension = CreateExtension(ManifestLocation::kExternalPolicyDownload);
 
   std::u16string error16;
   EXPECT_TRUE(provider_.UserMayLoad(extension.get(), &error16));
@@ -55,10 +57,10 @@
 
   // Component/policy extensions can modify and disable policy extensions, while
   // all others cannot.
-  auto component = CreateExtension(Manifest::COMPONENT);
+  auto component = CreateExtension(ManifestLocation::kComponent);
   auto policy = extension;
-  auto policy2 = CreateExtension(Manifest::EXTERNAL_POLICY);
-  auto internal = CreateExtension(Manifest::INTERNAL);
+  auto policy2 = CreateExtension(ManifestLocation::kExternalPolicy);
+  auto internal = CreateExtension(ManifestLocation::kInternal);
   EXPECT_TRUE(provider_.ExtensionMayModifySettings(component.get(),
                                                    policy.get(), nullptr));
   EXPECT_TRUE(provider_.ExtensionMayModifySettings(policy2.get(), policy.get(),
@@ -70,7 +72,7 @@
 // Tests the behavior of the ManagementPolicy provider methods for a component
 // extension.
 TEST_F(StandardManagementPolicyProviderTest, ComponentExtension) {
-  auto extension = CreateExtension(Manifest::COMPONENT);
+  auto extension = CreateExtension(ManifestLocation::kComponent);
 
   std::u16string error16;
   EXPECT_TRUE(provider_.UserMayLoad(extension.get(), &error16));
@@ -83,9 +85,9 @@
 
   // No extension can modify or disable component extensions.
   auto component = extension;
-  auto component2 = CreateExtension(Manifest::COMPONENT);
-  auto policy = CreateExtension(Manifest::EXTERNAL_POLICY);
-  auto internal = CreateExtension(Manifest::INTERNAL);
+  auto component2 = CreateExtension(ManifestLocation::kComponent);
+  auto policy = CreateExtension(ManifestLocation::kExternalPolicy);
+  auto internal = CreateExtension(ManifestLocation::kInternal);
   EXPECT_FALSE(provider_.ExtensionMayModifySettings(component2.get(),
                                                     component.get(), nullptr));
   EXPECT_FALSE(provider_.ExtensionMayModifySettings(policy.get(),
@@ -97,7 +99,7 @@
 // Tests the behavior of the ManagementPolicy provider methods for a regular
 // extension.
 TEST_F(StandardManagementPolicyProviderTest, NotRequiredExtension) {
-  auto extension = CreateExtension(Manifest::INTERNAL);
+  auto extension = CreateExtension(ManifestLocation::kInternal);
 
   std::u16string error16;
   EXPECT_TRUE(provider_.UserMayLoad(extension.get(), &error16));
@@ -108,10 +110,10 @@
   EXPECT_EQ(std::u16string(), error16);
 
   // All extension types can modify or disable internal extensions.
-  auto component = CreateExtension(Manifest::COMPONENT);
-  auto policy = CreateExtension(Manifest::EXTERNAL_POLICY);
+  auto component = CreateExtension(ManifestLocation::kComponent);
+  auto policy = CreateExtension(ManifestLocation::kExternalPolicy);
   auto internal = extension;
-  auto external_pref = CreateExtension(Manifest::EXTERNAL_PREF);
+  auto external_pref = CreateExtension(ManifestLocation::kExternalPref);
   EXPECT_TRUE(provider_.ExtensionMayModifySettings(component.get(),
                                                    internal.get(), nullptr));
   EXPECT_TRUE(provider_.ExtensionMayModifySettings(policy.get(), internal.get(),
diff --git a/chrome/browser/extensions/webstore_installer_browsertest.cc b/chrome/browser/extensions/webstore_installer_browsertest.cc
index a4d3645..e18db1c 100644
--- a/chrome/browser/extensions/webstore_installer_browsertest.cc
+++ b/chrome/browser/extensions/webstore_installer_browsertest.cc
@@ -183,7 +183,7 @@
   // Simulate another mechanism installing the same extension.
   scoped_refptr<const Extension> extension =
       ExtensionBuilder()
-          .SetLocation(Manifest::INTERNAL)
+          .SetLocation(mojom::ManifestLocation::kInternal)
           .SetID(kTestExtensionId)
           .SetManifest(std::move(manifest))
           .Build();
diff --git a/chrome/browser/extensions/webstore_reinstaller_browsertest.cc b/chrome/browser/extensions/webstore_reinstaller_browsertest.cc
index 808ecb3..aee0f73 100644
--- a/chrome/browser/extensions/webstore_reinstaller_browsertest.cc
+++ b/chrome/browser/extensions/webstore_reinstaller_browsertest.cc
@@ -64,15 +64,16 @@
   // Build an extension with the same id as our test extension and add it.
   const std::string kExtensionName("ReinstallerExtension");
   scoped_refptr<const Extension> extension =
-      ExtensionBuilder().SetLocation(Manifest::INTERNAL)
-                      .SetID(kTestExtensionId)
-                      .SetManifest(
-                          DictionaryBuilder().Set("name", kExtensionName)
-                                             .Set("description", "Foo")
-                                             .Set("manifest_version", 2)
-                                             .Set("version", "1.0")
-                                             .Build())
-                      .Build();
+      ExtensionBuilder()
+          .SetLocation(mojom::ManifestLocation::kInternal)
+          .SetID(kTestExtensionId)
+          .SetManifest(DictionaryBuilder()
+                           .Set("name", kExtensionName)
+                           .Set("description", "Foo")
+                           .Set("manifest_version", 2)
+                           .Set("version", "1.0")
+                           .Build())
+          .Build();
   extension_service()->AddExtension(extension.get());
   ExtensionRegistry* registry = ExtensionRegistry::Get(profile());
   ASSERT_TRUE(registry->enabled_extensions().GetByID(kTestExtensionId));
diff --git a/chrome/browser/feature_engagement/BUILD.gn b/chrome/browser/feature_engagement/BUILD.gn
new file mode 100644
index 0000000..1faf45a
--- /dev/null
+++ b/chrome/browser/feature_engagement/BUILD.gn
@@ -0,0 +1,33 @@
+# Copyright 2021 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("//build/config/android/config.gni")
+import("//build/config/android/rules.gni")
+
+android_library("java") {
+  sources = [
+    "java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotMonitor.java",
+    "java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotMonitorDelegate.java",
+    "java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotTabObserver.java",
+    "java/src/org/chromium/chrome/browser/feature_engagement/TrackerFactory.java",
+  ]
+
+  deps = [
+    "//base:base_java",
+    "//base:jni_java",
+    "//chrome/browser/profiles/android:java",
+    "//chrome/browser/tab:java",
+    "//components/feature_engagement/public:public_java",
+    "//components/ukm/android:java",
+    "//content/public/android:content_java",
+    "//third_party/androidx:androidx_annotation_annotation_java",
+    "//third_party/androidx:androidx_core_core_java",
+    "//ui/android:ui_full_java",
+  ]
+  annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
+}
+
+generate_jni("jni_headers") {
+  sources = [ "java/src/org/chromium/chrome/browser/feature_engagement/TrackerFactory.java" ]
+}
diff --git a/chrome/browser/feature_engagement/DEPS b/chrome/browser/feature_engagement/DEPS
index dad41f6..a4bd2f1 100644
--- a/chrome/browser/feature_engagement/DEPS
+++ b/chrome/browser/feature_engagement/DEPS
@@ -4,6 +4,7 @@
   "+chrome/browser/ui/views/feature_promos/feature_promo_bubble_view.h",
   "+chrome/browser/ui/views/frame/browser_view.h",
   "+chrome/browser/ui/views/toolbar/toolbar_view.h",
+  "+content/public/android/java",
 ]
 
 specific_include_rules = {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/feature_engagement/OWNERS b/chrome/browser/feature_engagement/java/src/org/chromium/chrome/browser/feature_engagement/OWNERS
similarity index 100%
rename from chrome/android/java/src/org/chromium/chrome/browser/feature_engagement/OWNERS
rename to chrome/browser/feature_engagement/java/src/org/chromium/chrome/browser/feature_engagement/OWNERS
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotMonitor.java b/chrome/browser/feature_engagement/java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotMonitor.java
similarity index 100%
rename from chrome/android/java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotMonitor.java
rename to chrome/browser/feature_engagement/java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotMonitor.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotMonitorDelegate.java b/chrome/browser/feature_engagement/java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotMonitorDelegate.java
similarity index 79%
rename from chrome/android/java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotMonitorDelegate.java
rename to chrome/browser/feature_engagement/java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotMonitorDelegate.java
index b2a50925..199b37b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotMonitorDelegate.java
+++ b/chrome/browser/feature_engagement/java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotMonitorDelegate.java
@@ -7,4 +7,6 @@
 /**
  * This class serves as a callback from ScreenshotMonitor.
  */
-public interface ScreenshotMonitorDelegate { void onScreenshotTaken(); }
\ No newline at end of file
+public interface ScreenshotMonitorDelegate {
+    void onScreenshotTaken();
+}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotTabObserver.java b/chrome/browser/feature_engagement/java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotTabObserver.java
similarity index 100%
rename from chrome/android/java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotTabObserver.java
rename to chrome/browser/feature_engagement/java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotTabObserver.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/feature_engagement/TrackerFactory.java b/chrome/browser/feature_engagement/java/src/org/chromium/chrome/browser/feature_engagement/TrackerFactory.java
similarity index 100%
rename from chrome/android/java/src/org/chromium/chrome/browser/feature_engagement/TrackerFactory.java
rename to chrome/browser/feature_engagement/java/src/org/chromium/chrome/browser/feature_engagement/TrackerFactory.java
diff --git a/chrome/browser/media/webrtc/desktop_capture_access_handler_unittest.cc b/chrome/browser/media/webrtc/desktop_capture_access_handler_unittest.cc
index 459a97c..54d64b8 100644
--- a/chrome/browser/media/webrtc/desktop_capture_access_handler_unittest.cc
+++ b/chrome/browser/media/webrtc/desktop_capture_access_handler_unittest.cc
@@ -352,7 +352,7 @@
       switches::kAllowHttpScreenCapture);
 
   extensions::ExtensionBuilder extensionBuilder("Component Extension");
-  extensionBuilder.SetLocation(extensions::Manifest::COMPONENT);
+  extensionBuilder.SetLocation(extensions::mojom::ManifestLocation::kComponent);
   auto extension = extensionBuilder.Build();
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
@@ -389,7 +389,7 @@
       switches::kAllowHttpScreenCapture);
 
   extensions::ExtensionBuilder extensionBuilder("Component Extension");
-  extensionBuilder.SetLocation(extensions::Manifest::COMPONENT);
+  extensionBuilder.SetLocation(extensions::mojom::ManifestLocation::kComponent);
   auto extension = extensionBuilder.Build();
 
   std::unique_ptr<aura::Window> primary_root_window =
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.cc b/chrome/browser/metrics/chrome_metrics_service_client.cc
index 6e14acd..52c6a8e 100644
--- a/chrome/browser/metrics/chrome_metrics_service_client.cc
+++ b/chrome/browser/metrics/chrome_metrics_service_client.cc
@@ -514,6 +514,10 @@
   return metrics::AsProtobufChannel(chrome::GetChannel());
 }
 
+bool ChromeMetricsServiceClient::IsExtendedStableChannel() {
+  return chrome::IsExtendedStableChannel();
+}
+
 std::string ChromeMetricsServiceClient::GetVersionString() {
   return metrics::GetVersionString();
 }
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.h b/chrome/browser/metrics/chrome_metrics_service_client.h
index b7fafa1..650ea5e 100644
--- a/chrome/browser/metrics/chrome_metrics_service_client.h
+++ b/chrome/browser/metrics/chrome_metrics_service_client.h
@@ -65,6 +65,7 @@
   std::string GetApplicationLocale() override;
   bool GetBrand(std::string* brand_code) override;
   metrics::SystemProfileProto::Channel GetChannel() override;
+  bool IsExtendedStableChannel() override;
   std::string GetVersionString() override;
   void OnEnvironmentUpdate(std::string* serialized_environment) override;
   void CollectFinalMetricsForLog(base::OnceClosure done_callback) override;
diff --git a/chrome/browser/metrics/extensions_metrics_provider_unittest.cc b/chrome/browser/metrics/extensions_metrics_provider_unittest.cc
index 517ba77d..ba3b00c 100644
--- a/chrome/browser/metrics/extensions_metrics_provider_unittest.cc
+++ b/chrome/browser/metrics/extensions_metrics_provider_unittest.cc
@@ -32,11 +32,12 @@
 #include "third_party/metrics_proto/extension_install.pb.h"
 #include "third_party/metrics_proto/system_profile.pb.h"
 
-using metrics::ExtensionInstallProto;
+using extensions::DictionaryBuilder;
 using extensions::Extension;
 using extensions::ExtensionBuilder;
 using extensions::Manifest;
-using extensions::DictionaryBuilder;
+using extensions::mojom::ManifestLocation;
+using metrics::ExtensionInstallProto;
 
 namespace {
 
@@ -188,7 +189,9 @@
     // Test basic prototype construction. All fields should be present, except
     // disable reasons (which should be empty).
     scoped_refptr<const Extension> extension =
-        ExtensionBuilder("test").SetLocation(Manifest::INTERNAL).Build();
+        ExtensionBuilder("test")
+            .SetLocation(ManifestLocation::kInternal)
+            .Build();
     add_extension(extension.get());
     ExtensionInstallProto install = ConstructProto(*extension);
     EXPECT_TRUE(install.has_type());
@@ -248,7 +251,7 @@
     // as such.
     scoped_refptr<const Extension> extension =
         ExtensionBuilder("app", ExtensionBuilder::Type::PLATFORM_APP)
-            .SetLocation(Manifest::INTERNAL)
+            .SetLocation(ManifestLocation::kInternal)
             .Build();
     add_extension(extension.get());
     ExtensionInstallProto install = ConstructProto(*extension);
@@ -258,7 +261,9 @@
   {
     // Test the install location.
     scoped_refptr<const Extension> extension =
-        ExtensionBuilder("unpacked").SetLocation(Manifest::UNPACKED).Build();
+        ExtensionBuilder("unpacked")
+            .SetLocation(ManifestLocation::kUnpacked)
+            .Build();
     add_extension(extension.get());
     ExtensionInstallProto install = ConstructProto(*extension);
     EXPECT_EQ(ExtensionInstallProto::UNPACKED, install.install_location());
@@ -268,7 +273,7 @@
     // Test the extension action as a browser action.
     scoped_refptr<const Extension> extension =
         ExtensionBuilder("browser_action")
-            .SetLocation(Manifest::INTERNAL)
+            .SetLocation(ManifestLocation::kInternal)
             .SetAction(ExtensionBuilder::ActionType::BROWSER_ACTION)
             .Build();
     add_extension(extension.get());
@@ -280,7 +285,7 @@
     // Test the extension action as a page action.
     scoped_refptr<const Extension> extension =
         ExtensionBuilder("page_action")
-            .SetLocation(Manifest::INTERNAL)
+            .SetLocation(ManifestLocation::kInternal)
             .SetAction(ExtensionBuilder::ActionType::PAGE_ACTION)
             .Build();
     add_extension(extension.get());
@@ -292,7 +297,7 @@
     // Test the disable reasons field.
     scoped_refptr<const Extension> extension =
         ExtensionBuilder("disable_reasons")
-            .SetLocation(Manifest::INTERNAL)
+            .SetLocation(ManifestLocation::kInternal)
             .Build();
     add_extension(extension.get());
     prefs()->SetExtensionDisabled(
@@ -335,7 +340,7 @@
         .Set("scripts", extensions::ListBuilder().Append("script.js").Build());
     scoped_refptr<const Extension> extension =
         ExtensionBuilder("event_page")
-            .SetLocation(Manifest::INTERNAL)
+            .SetLocation(ManifestLocation::kInternal)
             .MergeManifest(DictionaryBuilder()
                                .Set("background", background.Build())
                                .Build())
@@ -353,7 +358,7 @@
         .Set("scripts", extensions::ListBuilder().Append("script.js").Build());
     scoped_refptr<const Extension> extension =
         ExtensionBuilder("persisent_background")
-            .SetLocation(Manifest::INTERNAL)
+            .SetLocation(ManifestLocation::kInternal)
             .MergeManifest(DictionaryBuilder()
                                .Set("background", background.Build())
                                .Build())
@@ -379,7 +384,9 @@
   {
     // Test changing the blacklist state.
     scoped_refptr<const Extension> extension =
-        ExtensionBuilder("blacklist").SetLocation(Manifest::INTERNAL).Build();
+        ExtensionBuilder("blacklist")
+            .SetLocation(ManifestLocation::kInternal)
+            .Build();
     add_extension(extension.get());
     prefs()->SetExtensionBlocklistState(
         extension->id(), extensions::BLOCKLISTED_SECURITY_VULNERABILITY);
@@ -392,7 +399,9 @@
     // Test that the installed_in_this_sample_period boolean is correctly
     // reported.
     scoped_refptr<const Extension> extension =
-        ExtensionBuilder("installtime").SetLocation(Manifest::INTERNAL).Build();
+        ExtensionBuilder("installtime")
+            .SetLocation(ManifestLocation::kInternal)
+            .Build();
     add_extension(extension.get());
     set_last_sample_time(base::Time::Now() + base::TimeDelta::FromMinutes(60));
     ExtensionInstallProto install = ConstructProto(*extension);
diff --git a/chrome/browser/metrics/power/power_metrics_reporter.cc b/chrome/browser/metrics/power/power_metrics_reporter.cc
index 147c32e..7732127 100644
--- a/chrome/browser/metrics/power/power_metrics_reporter.cc
+++ b/chrome/browser/metrics/power/power_metrics_reporter.cc
@@ -25,26 +25,6 @@
 constexpr const char* kBatterySamplingDelayHistogramName =
     "Power.BatterySamplingDelay";
 
-// Calculates the UKM bucket |value| falls in and returns it. This rounds down
-// |value| to the nearest multiple of 10, capping it to prevent reporting more
-// bits of information than needed. With an interval of 120 seconds the number
-// of distinct values that can be reported by this function is 14:
-//    0, 10, 20, ..., 120 + an overflow bucket (130).
-//
-// Note: |GetLinearBucketMin(sample, 10)| is used here instead of
-// GetExponentialBucketMinForUserTiming as the exponential approach isn't
-// granular enough (e.g. it maxes out at 64 for an interval of 120 seconds).
-int64_t GetBucketForSample(base::TimeDelta value,
-                           base::TimeDelta interval_length) {
-  // Allows detection of inconsistent data
-  const base::TimeDelta kIntervalLengthPadding =
-      base::TimeDelta::FromSeconds(15);
-  const int kBucketSize = 10;
-  return ukm::GetLinearBucketMin(
-      std::min(value, interval_length + kIntervalLengthPadding).InSeconds(),
-      kBucketSize);
-}
-
 }  // namespace
 
 PowerMetricsReporter::PowerMetricsReporter(
@@ -191,13 +171,9 @@
   auto source_id = usage_metrics.source_id_for_longest_visible_origin;
 
   ukm::builders::PowerUsageScenariosIntervalData builder(source_id);
-
-  builder.SetURLVisibilityTimeSeconds(GetBucketForSample(
-      usage_metrics.source_id_for_longest_visible_origin_duration,
-      interval_duration));
+  builder.SetURLVisibilityTimeSeconds(ukm::GetExponentialBucketMinForUserTiming(
+      usage_metrics.source_id_for_longest_visible_origin_duration.InSeconds()));
   builder.SetIntervalDurationSeconds(interval_duration.InSeconds());
-  // An exponential bucket is fine here as this value isn't limited to the
-  // interval duration.
   builder.SetUptimeSeconds(ukm::GetExponentialBucketMinForUserTiming(
       usage_metrics.uptime_at_interval_end.InSeconds()));
   builder.SetBatteryDischargeMode(static_cast<int64_t>(discharge_mode));
@@ -219,25 +195,29 @@
       usage_metrics.max_visible_window_count, 1.05));
   builder.SetTabClosed(ukm::GetExponentialBucketMinForCounts1000(
       usage_metrics.tabs_closed_during_interval));
-  builder.SetTimePlayingVideoInVisibleTab(GetBucketForSample(
-      usage_metrics.time_playing_video_in_visible_tab, interval_duration));
+  builder.SetTimePlayingVideoInVisibleTab(
+      ukm::GetExponentialBucketMinForUserTiming(
+          usage_metrics.time_playing_video_in_visible_tab.InSeconds()));
   builder.SetTopLevelNavigationEvents(ukm::GetExponentialBucketMinForCounts1000(
       usage_metrics.top_level_navigation_count));
   builder.SetUserInteractionCount(ukm::GetExponentialBucketMinForCounts1000(
       usage_metrics.user_interaction_count));
-  builder.SetFullscreenVideoSingleMonitorSeconds(GetBucketForSample(
-      usage_metrics.time_playing_video_full_screen_single_monitor,
-      interval_duration));
-  builder.SetTimeWithOpenWebRTCConnectionSeconds(GetBucketForSample(
-      usage_metrics.time_with_open_webrtc_connection, interval_duration));
-  builder.SetTimeSinceInteractionWithBrowserSeconds(GetBucketForSample(
-      usage_metrics.time_since_last_user_interaction_with_browser,
-      interval_duration));
-  builder.SetVideoCaptureSeconds(GetBucketForSample(
-      usage_metrics.time_capturing_video, interval_duration));
+  builder.SetFullscreenVideoSingleMonitorSeconds(
+      ukm::GetExponentialBucketMinForUserTiming(
+          usage_metrics.time_playing_video_full_screen_single_monitor
+              .InSeconds()));
+  builder.SetTimeWithOpenWebRTCConnectionSeconds(
+      ukm::GetExponentialBucketMinForUserTiming(
+          usage_metrics.time_with_open_webrtc_connection.InSeconds()));
+  builder.SetTimeSinceInteractionWithBrowserSeconds(
+      ukm::GetExponentialBucketMinForUserTiming(
+          usage_metrics.time_since_last_user_interaction_with_browser
+              .InSeconds()));
+  builder.SetVideoCaptureSeconds(ukm::GetExponentialBucketMinForUserTiming(
+      usage_metrics.time_capturing_video.InSeconds()));
   builder.SetBrowserShuttingDown(browser_shutdown::HasShutdownStarted());
-  builder.SetPlayingAudioSeconds(
-      GetBucketForSample(usage_metrics.time_playing_audio, interval_duration));
+  builder.SetPlayingAudioSeconds(ukm::GetExponentialBucketMinForUserTiming(
+      usage_metrics.time_playing_audio.InSeconds()));
 
   builder.Record(ukm_recorder);
 }
diff --git a/chrome/browser/metrics/power/power_metrics_reporter_unittest.cc b/chrome/browser/metrics/power/power_metrics_reporter_unittest.cc
index 7d92358..0623631 100644
--- a/chrome/browser/metrics/power/power_metrics_reporter_unittest.cc
+++ b/chrome/browser/metrics/power/power_metrics_reporter_unittest.cc
@@ -248,38 +248,35 @@
           fake_interval_data.user_interaction_count));
   test_ukm_recorder_.ExpectEntryMetric(
       entries[0], UkmEntry::kFullscreenVideoSingleMonitorSecondsName,
-      ukm::GetLinearBucketMin(
+      ukm::GetExponentialBucketMinForUserTiming(
           fake_interval_data.time_playing_video_full_screen_single_monitor
-              .InSeconds(),
-          10));
+              .InSeconds()));
   test_ukm_recorder_.ExpectEntryMetric(
       entries[0], UkmEntry::kTimeWithOpenWebRTCConnectionSecondsName,
-      ukm::GetLinearBucketMin(
-          fake_interval_data.time_with_open_webrtc_connection.InSeconds(), 10));
+      ukm::GetExponentialBucketMinForUserTiming(
+          fake_interval_data.time_with_open_webrtc_connection.InSeconds()));
   test_ukm_recorder_.ExpectEntryMetric(
       entries[0], UkmEntry::kTimePlayingVideoInVisibleTabName,
-      ukm::GetLinearBucketMin(
-          fake_interval_data.time_playing_video_in_visible_tab.InSeconds(),
-          10));
+      ukm::GetExponentialBucketMinForUserTiming(
+          fake_interval_data.time_playing_video_in_visible_tab.InSeconds()));
   test_ukm_recorder_.ExpectEntryMetric(
       entries[0], UkmEntry::kIntervalDurationSecondsName,
       kExpectedMetricsCollectionInterval.InSeconds());
   test_ukm_recorder_.ExpectEntryMetric(
       entries[0], UkmEntry::kTimeSinceInteractionWithBrowserSecondsName,
-      ukm::GetLinearBucketMin(
+      ukm::GetExponentialBucketMinForUserTiming(
           fake_interval_data.time_since_last_user_interaction_with_browser
-              .InSeconds(),
-          10));
+              .InSeconds()));
   test_ukm_recorder_.ExpectEntryMetric(
       entries[0], UkmEntry::kVideoCaptureSecondsName,
-      ukm::GetLinearBucketMin(
-          fake_interval_data.time_capturing_video.InSeconds(), 10));
+      ukm::GetExponentialBucketMinForUserTiming(
+          fake_interval_data.time_capturing_video.InSeconds()));
   test_ukm_recorder_.ExpectEntryMetric(
       entries[0], UkmEntry::kBrowserShuttingDownName, false);
   test_ukm_recorder_.ExpectEntryMetric(
       entries[0], UkmEntry::kPlayingAudioSecondsName,
-      ukm::GetLinearBucketMin(fake_interval_data.time_playing_audio.InSeconds(),
-                              10));
+      ukm::GetExponentialBucketMinForUserTiming(
+          fake_interval_data.time_playing_audio.InSeconds()));
 
   histogram_tester_.ExpectUniqueSample(kBatteryDischargeRateHistogramName, 2500,
                                        1);
@@ -555,31 +552,3 @@
       ukm::GetExponentialBucketMinForUserTiming(
           fake_interval_data.uptime_at_interval_end.InSeconds()));
 }
-
-TEST_F(PowerMetricsReporterUnitTest, DurationsLongerThanIntervalAreCapped) {
-  UsageScenarioDataStore::IntervalData fake_interval_data;
-
-  fake_interval_data.time_playing_video_full_screen_single_monitor =
-      kExpectedMetricsCollectionInterval * 100;
-
-  task_environment_.FastForwardBy(kExpectedMetricsCollectionInterval);
-  battery_states_.push(BatteryLevelProvider::BatteryState{
-      1, 1, 0.50, true, base::TimeTicks::Now()});
-  data_store_.SetIntervalDataToReturn(fake_interval_data);
-
-  performance_monitor::ProcessMonitor::Metrics fake_metrics = {};
-  fake_metrics.cpu_usage = 0.5;
-  WaitForNextSample(fake_metrics);
-
-  auto entries = test_ukm_recorder_.GetEntriesByName(
-      ukm::builders::PowerUsageScenariosIntervalData::kEntryName);
-  EXPECT_EQ(1u, entries.size());
-
-  EXPECT_EQ(entries[0]->source_id, ukm::kInvalidSourceId);
-  test_ukm_recorder_.ExpectEntryMetric(
-      entries[0], UkmEntry::kFullscreenVideoSingleMonitorSecondsName,
-      // Every value greater than |kExpectedMetricsCollectionInterval| should
-      // fall in the same overflow bucket.
-      ukm::GetLinearBucketMin(
-          kExpectedMetricsCollectionInterval.InSeconds() + 10, 10));
-}
diff --git a/chrome/browser/metrics/tab_stats/tab_stats_tracker.cc b/chrome/browser/metrics/tab_stats/tab_stats_tracker.cc
index 8e7f9f6..2b428d4 100644
--- a/chrome/browser/metrics/tab_stats/tab_stats_tracker.cc
+++ b/chrome/browser/metrics/tab_stats/tab_stats_tracker.cc
@@ -161,7 +161,7 @@
   }
 
   browser_list->AddObserver(this);
-  base::PowerMonitor::AddObserver(this);
+  base::PowerMonitor::AddPowerSuspendObserver(this);
 
   // Setup daily reporting of the stats aggregated in |tab_stats_data_store|.
   daily_event_->AddObserver(std::make_unique<TabStatsDailyObserver>(
@@ -206,7 +206,7 @@
 TabStatsTracker::~TabStatsTracker() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   BrowserList::GetInstance()->RemoveObserver(this);
-  base::PowerMonitor::RemoveObserver(this);
+  base::PowerMonitor::RemovePowerSuspendObserver(this);
 }
 
 // static
diff --git a/chrome/browser/metrics/tab_stats/tab_stats_tracker.h b/chrome/browser/metrics/tab_stats/tab_stats_tracker.h
index a1c6cfc3..4d28310 100644
--- a/chrome/browser/metrics/tab_stats/tab_stats_tracker.h
+++ b/chrome/browser/metrics/tab_stats/tab_stats_tracker.h
@@ -42,7 +42,7 @@
 //         std::make_unique<TabStatsTracker>(g_browser_process->local_state()));
 class TabStatsTracker : public TabStripModelObserver,
                         public BrowserListObserver,
-                        public base::PowerObserver {
+                        public base::PowerSuspendObserver {
  public:
   // Constructor. |pref_service| must outlive this object.
   explicit TabStatsTracker(PrefService* pref_service);
@@ -150,7 +150,8 @@
       TabStripModel* tab_strip_model,
       const TabStripModelChange& change,
       const TabStripSelectionChange& selection) override;
-  // base::PowerObserver:
+
+  // base::PowerSuspendObserver:
   void OnResume() override;
 
   // Callback when an interval timer triggers.
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
index 267616726..c5a82ec 100644
--- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
+++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
@@ -1583,8 +1583,11 @@
     // We need to debounce the call to shut down the process in case this state
     // is temporary (we don't want to the thrash the process). Any advertisment,
     // scanning or transfering will stop this timer from triggering.
+    // Logging disabled due to test failures; see https://crbug.com/1188613.
+#if 0
     NS_LOG(INFO) << __func__
                  << ": Scheduling process shutdown if not needed in 15 seconds";
+#endif
     // NOTE: Using base::Unretained is safe because if shutdown_pending_timer_
     // goes out of scope the timer will be canceled.
     process_shutdown_pending_timer_.Start(
diff --git a/chrome/browser/net/private_network_access_browsertest.cc b/chrome/browser/net/private_network_access_browsertest.cc
index de62d49b..228c27c4 100644
--- a/chrome/browser/net/private_network_access_browsertest.cc
+++ b/chrome/browser/net/private_network_access_browsertest.cc
@@ -471,7 +471,7 @@
   extensions::ExtensionBuilder builder("test");
   builder.SetPath(temp_dir.GetPath())
       .SetVersion("1.0")
-      .SetLocation(extensions::Manifest::EXTERNAL_POLICY_DOWNLOAD)
+      .SetLocation(extensions::mojom::ManifestLocation::kExternalPolicyDownload)
       .SetManifestKey("web_accessible_resources", std::move(resources));
 
   extensions::ExtensionService* service =
diff --git a/chrome/browser/net/system_network_context_manager_browsertest.cc b/chrome/browser/net/system_network_context_manager_browsertest.cc
index 7a0831a..dba495c 100644
--- a/chrome/browser/net/system_network_context_manager_browsertest.cc
+++ b/chrome/browser/net/system_network_context_manager_browsertest.cc
@@ -27,6 +27,7 @@
 #include "content/public/test/browser_test.h"
 #include "net/dns/public/dns_over_https_server_config.h"
 #include "net/dns/public/secure_dns_mode.h"
+#include "net/net_buildflags.h"
 #include "services/cert_verifier/test_cert_verifier_service_factory.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/network_service_buildflags.h"
diff --git a/chrome/browser/net/trial_comparison_cert_verifier_browsertest.cc b/chrome/browser/net/trial_comparison_cert_verifier_browsertest.cc
index 10ec923fc..f66bec0d 100644
--- a/chrome/browser/net/trial_comparison_cert_verifier_browsertest.cc
+++ b/chrome/browser/net/trial_comparison_cert_verifier_browsertest.cc
@@ -8,7 +8,6 @@
 #include "chrome/browser/net/trial_comparison_cert_verifier_controller.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/common/chrome_features.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/metrics/content/subprocess_metrics_provider.h"
@@ -47,7 +46,8 @@
     // None of these tests should generate a report, but set the trial to
     // uma_only mode anyway just to be safe.
     scoped_feature_->InitAndEnableFeatureWithParameters(
-        features::kCertDualVerificationTrialFeature, {{"uma_only", "true"}});
+        net::features::kCertDualVerificationTrialFeature,
+        {{"uma_only", "true"}});
   }
 
   ~TrialComparisonCertVerifierFeatureEnabledTest() override {
@@ -103,7 +103,8 @@
     scoped_feature_->InitWithFeaturesAndParameters(
         // None of these tests should generate a report, but set the trial to
         // uma_only mode anyway just to be safe.
-        {{features::kCertDualVerificationTrialFeature, {{"uma_only", "true"}}},
+        {{net::features::kCertDualVerificationTrialFeature,
+          {{"uma_only", "true"}}},
          // Enable the builtin verifier.
          {net::features::kCertVerifierBuiltinFeature, {}}},
         {});
diff --git a/chrome/browser/net/trial_comparison_cert_verifier_controller.cc b/chrome/browser/net/trial_comparison_cert_verifier_controller.cc
index a6a91962..931212e 100644
--- a/chrome/browser/net/trial_comparison_cert_verifier_controller.cc
+++ b/chrome/browser/net/trial_comparison_cert_verifier_controller.cc
@@ -19,7 +19,6 @@
 #include "chrome/browser/safe_browsing/certificate_reporting_service.h"
 #include "chrome/browser/safe_browsing/certificate_reporting_service_factory.h"
 #include "chrome/common/channel_info.h"
-#include "chrome/common/chrome_features.h"
 #include "components/safe_browsing/core/common/safe_browsing_prefs.h"
 #include "components/security_interstitials/content/certificate_error_report.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -71,7 +70,7 @@
 
   return is_official_build &&
          base::FeatureList::IsEnabled(
-             features::kCertDualVerificationTrialFeature) &&
+             net::features::kCertDualVerificationTrialFeature) &&
          !profile->IsOffTheRecord();
 }
 
@@ -111,9 +110,9 @@
     const net::CertVerifyResult& primary_result,
     const net::CertVerifyResult& trial_result,
     network::mojom::CertVerifierDebugInfoPtr debug_info) {
-  if (!IsAllowed() ||
-      base::GetFieldTrialParamByFeatureAsBool(
-          features::kCertDualVerificationTrialFeature, "uma_only", false)) {
+  if (!IsAllowed() || base::GetFieldTrialParamByFeatureAsBool(
+                          net::features::kCertDualVerificationTrialFeature,
+                          "uma_only", false)) {
     return;
   }
 
diff --git a/chrome/browser/net/trial_comparison_cert_verifier_controller_unittest.cc b/chrome/browser/net/trial_comparison_cert_verifier_controller_unittest.cc
index 22e07b41..cfb12627 100644
--- a/chrome/browser/net/trial_comparison_cert_verifier_controller_unittest.cc
+++ b/chrome/browser/net/trial_comparison_cert_verifier_controller_unittest.cc
@@ -16,7 +16,6 @@
 #include "chrome/browser/safe_browsing/certificate_reporting_service_factory.h"
 #include "chrome/browser/safe_browsing/certificate_reporting_service_test_utils.h"
 #include "chrome/browser/safe_browsing/test_safe_browsing_service.h"
-#include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
@@ -29,6 +28,7 @@
 #include "content/public/test/test_utils.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
+#include "net/base/features.h"
 #include "net/base/net_errors.h"
 #include "net/cert/cert_verify_result.h"
 #include "net/cert/x509_certificate.h"
@@ -279,7 +279,7 @@
        NotOfficialBuildTrialEnabled) {
   scoped_feature_ = std::make_unique<base::test::ScopedFeatureList>();
   scoped_feature_->InitAndEnableFeature(
-      features::kCertDualVerificationTrialFeature);
+      net::features::kCertDualVerificationTrialFeature);
   CreateController();
 
   EXPECT_FALSE(trial_controller().IsAllowed());
@@ -317,7 +317,7 @@
   TrialComparisonCertVerifierController::SetFakeOfficialBuildForTesting(true);
   scoped_feature_ = std::make_unique<base::test::ScopedFeatureList>();
   scoped_feature_->InitAndEnableFeature(
-      features::kCertDualVerificationTrialFeature);
+      net::features::kCertDualVerificationTrialFeature);
   CreateController();
 
   EXPECT_FALSE(trial_controller().IsAllowed());
@@ -398,7 +398,7 @@
   TrialComparisonCertVerifierController::SetFakeOfficialBuildForTesting(true);
   scoped_feature_ = std::make_unique<base::test::ScopedFeatureList>();
   scoped_feature_->InitAndEnableFeature(
-      features::kCertDualVerificationTrialFeature);
+      net::features::kCertDualVerificationTrialFeature);
   CreateController();
 
   mojo::Remote<network::mojom::TrialComparisonCertVerifierReportClient>
@@ -506,7 +506,7 @@
   TrialComparisonCertVerifierController::SetFakeOfficialBuildForTesting(true);
   scoped_feature_ = std::make_unique<base::test::ScopedFeatureList>();
   scoped_feature_->InitAndEnableFeatureWithParameters(
-      features::kCertDualVerificationTrialFeature, {{"uma_only", "true"}});
+      net::features::kCertDualVerificationTrialFeature, {{"uma_only", "true"}});
   CreateController();
 
   EXPECT_FALSE(trial_controller().IsAllowed());
@@ -542,7 +542,7 @@
   TrialComparisonCertVerifierController::SetFakeOfficialBuildForTesting(true);
   scoped_feature_ = std::make_unique<base::test::ScopedFeatureList>();
   scoped_feature_->InitAndEnableFeature(
-      features::kCertDualVerificationTrialFeature);
+      net::features::kCertDualVerificationTrialFeature);
   CreateController(profile()->GetPrimaryOTRProfile());
 
   EXPECT_FALSE(trial_controller().IsAllowed());
diff --git a/chrome/browser/obsolete_system/obsolete_system_linux.cc b/chrome/browser/obsolete_system/obsolete_system_linux.cc
index 164b224..df7859b 100644
--- a/chrome/browser/obsolete_system/obsolete_system_linux.cc
+++ b/chrome/browser/obsolete_system/obsolete_system_linux.cc
@@ -11,34 +11,22 @@
 #include "chrome/grit/chromium_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 
-namespace {
-
-bool IsObsoleteCpu() {
-#if defined(ARCH_CPU_X86_FAMILY)
-  return !base::CPU().has_sse3();
-#else
-  return false;
-#endif
-}
-
-}  // namespace
-
 // static
 bool ObsoleteSystem::IsObsoleteNowOrSoon() {
-  return IsObsoleteCpu();
+  return false;
 }
 
 // static
 std::u16string ObsoleteSystem::LocalizedObsoleteString() {
-  return l10n_util::GetStringUTF16(IDS_CPU_X86_SSE2_OBSOLETE_SOON);
+  return std::u16string();
 }
 
 // static
 bool ObsoleteSystem::IsEndOfTheLine() {
-  return CHROME_VERSION_MAJOR >= 88;
+  return true;
 }
 
 // static
 const char* ObsoleteSystem::GetLinkURL() {
-  return chrome::kCpuX86Sse2ObsoleteURL;
+  return "";
 }
diff --git a/chrome/browser/obsolete_system/obsolete_system_mac.cc b/chrome/browser/obsolete_system/obsolete_system_mac.cc
index 75b9e89e..119a8cb 100644
--- a/chrome/browser/obsolete_system/obsolete_system_mac.cc
+++ b/chrome/browser/obsolete_system/obsolete_system_mac.cc
@@ -27,37 +27,24 @@
          base::FeatureList::IsEnabled(features::kShow10_10ObsoleteInfobar);
 }
 
-bool IsObsoleteCpu() {
-#if defined(ARCH_CPU_X86_FAMILY)
-  return !base::CPU().has_sse3();
-#else
-  return false;
-#endif
-}
-
 }  // namespace
 
 // static
 bool ObsoleteSystem::IsObsoleteNowOrSoon() {
-  return IsObsoleteCpu() || IsObsoleteOsVersion();
+  return IsObsoleteOsVersion();
 }
 
 // static
 std::u16string ObsoleteSystem::LocalizedObsoleteString() {
-  // We check for an obsolete CPU first so that we don't nudge users through
-  // an OS upgrade, only to find out that they need a new computer anyway.
-  return IsObsoleteCpu()
-             ? l10n_util::GetStringUTF16(IDS_CPU_X86_SSE2_OBSOLETE_SOON)
-             : l10n_util::GetStringUTF16(IDS_MAC_10_10_OBSOLETE_SOON);
+  return l10n_util::GetStringUTF16(IDS_MAC_10_10_OBSOLETE_SOON);
 }
 
 // static
 bool ObsoleteSystem::IsEndOfTheLine() {
-  return IsObsoleteCpu() ? CHROME_VERSION_MAJOR >= 88 : true;
+  return true;
 }
 
 // static
 const char* ObsoleteSystem::GetLinkURL() {
-  return IsObsoleteCpu() ? chrome::kCpuX86Sse2ObsoleteURL
-                         : chrome::kMac10_10_ObsoleteURL;
+  return chrome::kMac10_10_ObsoleteURL;
 }
diff --git a/chrome/browser/obsolete_system/obsolete_system_win.cc b/chrome/browser/obsolete_system/obsolete_system_win.cc
index c597a89..311007c 100644
--- a/chrome/browser/obsolete_system/obsolete_system_win.cc
+++ b/chrome/browser/obsolete_system/obsolete_system_win.cc
@@ -18,37 +18,24 @@
   return base::win::GetVersion() < base::win::Version::WIN7;
 }
 
-bool IsObsoleteCpu() {
-#if defined(ARCH_CPU_X86_FAMILY)
-  return !base::CPU().has_sse3();
-#else
-  return false;
-#endif
-}
-
 }  // namespace
 
 // static
 bool ObsoleteSystem::IsObsoleteNowOrSoon() {
-  return IsObsoleteCpu() || IsObsoleteOsVersion();
+  return IsObsoleteOsVersion();
 }
 
 // static
 std::u16string ObsoleteSystem::LocalizedObsoleteString() {
-  // We check for an obsolete CPU first so that we don't nudge users through
-  // an OS upgrade, only to find out that they need a new computer anyway.
-  return IsObsoleteCpu()
-             ? l10n_util::GetStringUTF16(IDS_CPU_X86_SSE2_OBSOLETE_SOON)
-             : l10n_util::GetStringUTF16(IDS_WIN_XP_VISTA_OBSOLETE);
+  return l10n_util::GetStringUTF16(IDS_WIN_XP_VISTA_OBSOLETE);
 }
 
 // static
 bool ObsoleteSystem::IsEndOfTheLine() {
-  return IsObsoleteCpu() ? CHROME_VERSION_MAJOR >= 88 : true;
+  return true;
 }
 
 // static
 const char* ObsoleteSystem::GetLinkURL() {
-  return IsObsoleteCpu() ? chrome::kCpuX86Sse2ObsoleteURL
-                         : chrome::kWindowsXPVistaDeprecationURL;
+  return chrome::kWindowsXPVistaDeprecationURL;
 }
diff --git a/chrome/browser/password_manager/android/password_generation_controller_impl.cc b/chrome/browser/password_manager/android/password_generation_controller_impl.cc
index aab7356a..5da062a 100644
--- a/chrome/browser/password_manager/android/password_generation_controller_impl.cc
+++ b/chrome/browser/password_manager/android/password_generation_controller_impl.cc
@@ -96,7 +96,7 @@
 
   active_frame_driver_->GetPasswordManager()
       ->SetGenerationElementAndTypeForForm(
-          active_frame_driver_.get(), ui_data.form_data,
+          active_frame_driver_.get(), ui_data.form_data.unique_renderer_id,
           ui_data.generation_element_id, PasswordGenerationType::kAutomatic);
 
   if (!base::FeatureList::IsEnabled(
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index 9c4d78f..5bccfec 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -1437,7 +1437,8 @@
   gfx::RectF element_bounds_in_screen_space =
       GetBoundsInScreenSpace(element_bounds_in_top_frame_space);
   password_manager_.SetGenerationElementAndTypeForForm(
-      driver, ui_data.form_data, ui_data.generation_element_id, type);
+      driver, ui_data.form_data.unique_renderer_id,
+      ui_data.generation_element_id, type);
 
   popup_controller_ = PasswordGenerationPopupControllerImpl::GetOrCreate(
       popup_controller_, element_bounds_in_screen_space, ui_data,
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc
index a9cac7f..5dfdc769 100644
--- a/chrome/browser/pdf/pdf_extension_test.cc
+++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -900,6 +900,8 @@
                        ViewerPropertiesDialog) {
   // The properties dialog formats some values based on locale.
   base::test::ScopedRestoreICUDefaultLocale scoped_locale{"en_US"};
+  base::test::ScopedRestoreDefaultTimezone
+      scoped_timezone{"America/Los_Angeles"};
   RunTestsInJsModule("viewer_properties_dialog_test.js", "document_info.pdf");
 }
 
diff --git a/chrome/browser/performance_monitor/process_monitor.cc b/chrome/browser/performance_monitor/process_monitor.cc
index b2900ef..953f539 100644
--- a/chrome/browser/performance_monitor/process_monitor.cc
+++ b/chrome/browser/performance_monitor/process_monitor.cc
@@ -19,12 +19,12 @@
 #include "content/public/browser/child_process_data.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/common/content_constants.h"
-#include "extensions/browser/process_map.h"
 #include "extensions/buildflags/buildflags.h"
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
 #include "extensions/browser/extension_host.h"
 #include "extensions/browser/extension_registry.h"
+#include "extensions/browser/process_map.h"
 #include "extensions/common/manifest_handlers/background_info.h"
 #endif
 
diff --git a/chrome/browser/policy/cloud/chrome_browser_cloud_management_browsertest.cc b/chrome/browser/policy/cloud/chrome_browser_cloud_management_browsertest.cc
index c2b54c6b..aee61df 100644
--- a/chrome/browser/policy/cloud/chrome_browser_cloud_management_browsertest.cc
+++ b/chrome/browser/policy/cloud/chrome_browser_cloud_management_browsertest.cc
@@ -795,7 +795,8 @@
 };  // namespace policy
 
 // Flaky on linux & win: https://crbug.com/1105167
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
+    defined(OS_MAC)
 #define MAYBE_Test DISABLED_Test
 #else
 #define MAYBE_Test Test
diff --git a/chrome/browser/policy/test/system_features_policy_browsertest.cc b/chrome/browser/policy/test/system_features_policy_browsertest.cc
index e7aab89a..2463e7a1 100644
--- a/chrome/browser/policy/test/system_features_policy_browsertest.cc
+++ b/chrome/browser/policy/test/system_features_policy_browsertest.cc
@@ -256,12 +256,15 @@
   system_features.Append(kCameraFeature);
   system_features.Append(kScanningFeature);
   system_features.Append(kWebStoreFeature);
+  system_features.Append(kCanvasFeature);
   VisibilityFlags camera_expected_visibility =
       GetVisibilityFlags(true /* is_hidden */);
   VisibilityFlags scanning_expected_visibility =
       GetVisibilityFlags(true /* is_hidden */);
   VisibilityFlags web_store_expected_visibility =
       GetVisibilityFlags(true /* is_hidden */);
+  VisibilityFlags canvas_expected_visibility =
+      GetVisibilityFlags(true /* is_hidden */);
   // Disable app with hidden mode.
   UpdateSystemFeaturesDisableList(system_features.Clone(), kHiddenDisableMode);
   VerifyAppState(web_app::kCameraAppId,
@@ -273,6 +276,9 @@
   VerifyExtensionAppState(extensions::kWebStoreAppId,
                           apps::mojom::Readiness::kDisabledByPolicy, true,
                           web_store_expected_visibility);
+  VerifyAppState(web_app::kCanvasAppId,
+                 apps::mojom::Readiness::kDisabledByPolicy, true,
+                 canvas_expected_visibility);
   // Disable and block apps.
   camera_expected_visibility = GetVisibilityFlags(false /* is_hidden */);
   scanning_expected_visibility = GetVisibilityFlags(false /* is_hidden */);
@@ -280,6 +286,7 @@
   scanning_expected_visibility.show_in_launcher =
       apps::mojom::OptionalBool::kFalse;
   web_store_expected_visibility = GetVisibilityFlags(false /* is_hidden */);
+  canvas_expected_visibility = GetVisibilityFlags(false /* is_hidden */);
   UpdateSystemFeaturesDisableList(system_features.Clone(), kBlockedDisableMode);
   VerifyAppState(web_app::kCameraAppId,
                  apps::mojom::Readiness::kDisabledByPolicy, true,
@@ -290,6 +297,9 @@
   VerifyExtensionAppState(extensions::kWebStoreAppId,
                           apps::mojom::Readiness::kDisabledByPolicy, true,
                           web_store_expected_visibility);
+  VerifyAppState(web_app::kCanvasAppId,
+                 apps::mojom::Readiness::kDisabledByPolicy, true,
+                 canvas_expected_visibility);
   // Enable apps.
   UpdateSystemFeaturesDisableList(base::Value(), nullptr);
   VerifyAppState(web_app::kCameraAppId, apps::mojom::Readiness::kReady, false,
@@ -299,6 +309,8 @@
   VerifyExtensionAppState(extensions::kWebStoreAppId,
                           apps::mojom::Readiness::kReady, false,
                           web_store_expected_visibility);
+  VerifyAppState(web_app::kCanvasAppId, apps::mojom::Readiness::kReady, false,
+                 canvas_expected_visibility);
 }
 
 IN_PROC_BROWSER_TEST_F(SystemFeaturesPolicyTest, RedirectChromeSettingsURL) {
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index ea09ada..d170c8a 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -166,6 +166,7 @@
 #include "chrome/browser/extensions/api/commands/command_service.h"
 #include "chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.h"
 #include "chrome/browser/extensions/api/tabs/tabs_api.h"
+#include "chrome/browser/extensions/default_apps.h"
 #include "chrome/browser/extensions/extension_web_ui.h"
 #include "chrome/browser/extensions/ntp_overridden_bubble_delegate.h"
 #include "chrome/browser/ui/toolbar/toolbar_actions_bar.h"
@@ -356,8 +357,6 @@
 #include "components/onc/onc_pref_names.h"
 #include "components/quirks/quirks_manager.h"
 #include "extensions/browser/api/lock_screen_data/lock_screen_item_storage.h"
-#else
-#include "chrome/browser/extensions/default_apps.h"
 #endif
 
 #if defined(OS_MAC)
@@ -556,7 +555,6 @@
 // Register local state used only for migration (clearing or moving to a new
 // key).
 void RegisterLocalStatePrefsForMigration(PrefRegistrySimple* registry) {
-
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   registry->RegisterDictionaryPref(kRegisteredSupervisedUserAllowlists);
   registry->RegisterIntegerPref(kSupervisedUsersNextId, 0);
@@ -659,6 +657,13 @@
 #if !defined(OS_ANDROID)
   registry->RegisterBooleanPref(kCartModuleRemoved, false);
 #endif
+
+#if !defined(OS_ANDROID)
+  registry->RegisterStringPref(
+      enterprise_connectors::kDeviceTrustPrivateKeyPref, std::string());
+  registry->RegisterStringPref(enterprise_connectors::kDeviceTrustPublicKeyPref,
+                               std::string());
+#endif
 }
 
 }  // namespace
@@ -823,6 +828,13 @@
   RegisterNearbySharingLocalPrefs(registry);
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
+// TODO(crbug/1169547) Remove `BUILDFLAG(IS_CHROMEOS_LACROS)` once the
+// migration is complete.
+#if defined(OS_LINUX) || defined(OS_MAC) || defined(OS_WIN) || \
+    BUILDFLAG(IS_CHROMEOS_LACROS)
+  enterprise_connectors::RegisterLocalPrefs(registry);
+#endif  // defined(OS_LINUX) || defined(OS_MAC) || defined(OS_WIN)
+
 #if defined(OS_MAC)
   confirm_quit::RegisterLocalState(registry);
   QuitWithAppsController::RegisterPrefs(registry);
@@ -1330,6 +1342,12 @@
   // Added 03/2021
   profile_prefs->ClearPref(kLiteModeUserNeedsNotification);
 
+#if !defined(OS_ANDROID)
+  // Added 03/2021
+  profile_prefs->ClearPref(enterprise_connectors::kDeviceTrustPrivateKeyPref);
+  profile_prefs->ClearPref(enterprise_connectors::kDeviceTrustPublicKeyPref);
+#endif
+
   // Please don't delete the following line. It is used by PRESUBMIT.py.
   // END_MIGRATE_OBSOLETE_PROFILE_PREFS
 }
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
index d5db103d..d9fa748 100644
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -321,7 +321,7 @@
     "$root_gen_dir/chrome/usb_internals_resources.pak",
     "$root_gen_dir/chrome/webrtc_logs_resources.pak",
     "$root_gen_dir/components/dev_ui_components_resources.pak",
-    "$root_gen_dir/components/sync_driver_resources.pak",
+    "$root_gen_dir/components/sync_driver_sync_internals_resources.pak",
     "$root_gen_dir/content/browser/resources/media/media_internals_resources.pak",
     "$root_gen_dir/content/browser/webrtc/resources/webrtc_internals_resources.pak",
     "$root_gen_dir/content/dev_ui_content_resources.pak",
@@ -336,7 +336,7 @@
     "//chrome/browser/resources/quota_internals:resources",
     "//chrome/browser/resources/usb_internals:resources",
     "//components/resources:dev_ui_components_resources",
-    "//components/sync/driver:resources",
+    "//components/sync/driver/resources",
     "//content:dev_ui_content_resources",
     "//content/browser/resources/media:resources",
     "//content/browser/webrtc/resources",
diff --git a/chrome/browser/resources/about_sys/about_sys.html b/chrome/browser/resources/about_sys/about_sys.html
index 66f7960..12b961a 100644
--- a/chrome/browser/resources/about_sys/about_sys.html
+++ b/chrome/browser/resources/about_sys/about_sys.html
@@ -5,11 +5,7 @@
     <title>$i18n{title}</title>
     <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
     <link rel="stylesheet" href="about_sys.css">
-    <script src="chrome://resources/js/assert.js"></script>
-    <script src="chrome://resources/js/util.js"></script>
-    <script src="chrome://resources/js/load_time_data.js"></script>
-    <script src="about_sys.js"></script>
-    <script src="strings.js"></script>
+    <script type="module" src="about_sys.js"></script>
   </head>
   <body>
     <div id="header">
diff --git a/chrome/browser/resources/about_sys/about_sys.js b/chrome/browser/resources/about_sys/about_sys.js
index 4edba9ba..e5ecf9b3 100644
--- a/chrome/browser/resources/about_sys/about_sys.js
+++ b/chrome/browser/resources/about_sys/about_sys.js
@@ -2,6 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import './strings.m.js';
+
+import {sendWithPromise} from 'chrome://resources/js/cr.m.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
+import {$} from 'chrome://resources/js/util.m.js';
+
 // Contents of lines that act as delimiters for multi-line values.
 const DELIM_START = '---------- START ----------';
 const DELIM_END = '---------- END ----------';
@@ -169,9 +175,8 @@
 }
 
 /**
- * Callback called by system_info_ui.cc when it has finished fetching
- * system info. The log entries are passed as a list of dictionaries containing
- * the keys statName and statValue.
+ * Callback called when system info has been fetched. The log entries are passed
+ * as a list of dictionaries containing the keys statName and statValue.
  * @param {systemInfo} The fetched log entries.
  */
 function returnSystemInfo(systemInfo) {
@@ -243,7 +248,7 @@
 }
 
 document.addEventListener('DOMContentLoaded', function() {
-  chrome.send('requestSystemInfo');
+  sendWithPromise('requestSystemInfo').then(returnSystemInfo);
 
   $('collapseAll').onclick = collapseAll;
   $('expandAll').onclick = expandAll;
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
index 587a6f2..a2049668 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
@@ -4,6 +4,7 @@
 
 import("//build/config/chromeos/ui_mode.gni")
 import("//build/config/features.gni")
+import("//build/config/python.gni")
 import(
     "//chrome/browser/resources/chromeos/accessibility/common/run_jsbundler.gni")
 import("//chrome/common/features.gni")
@@ -323,7 +324,8 @@
     data += js2gtest_js_libraries
   }
 
-  action("chromevox_test_messages_js") {
+  # TODO(crbug.com/1112471): Get this to run under Python3.
+  python2_action("chromevox_test_messages_js") {
     script = "tools/generate_test_messages.py"
     sources = [ "$root_out_dir/resources/chromeos/accessibility/_locales/en/messages.json.gz" ]
     output_file = "$root_out_dir/test_data/chrome/browser/resources/chromeos/accessibility/chromevox/host/testing/test_messages.js"
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox_manifest.json.jinja2 b/chrome/browser/resources/chromeos/accessibility/chromevox_manifest.json.jinja2
index f2ace0f..8dda133 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox_manifest.json.jinja2
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox_manifest.json.jinja2
@@ -69,14 +69,8 @@
   "content_security_policy": "default-src 'none'; script-src 'self' chrome://resources; style-src 'unsafe-inline' chrome://resources;",
   "externally_connectable": {
     "ids": [
-       // Braille IME.
-      "jddehjeebkoimngcbdkaahpobgicbffp",
-
-       // Allow connections with js2at (name may change) project, which allows
-       // web pages and ChromeVox to exchange messages that conform to
-       // a set of approved schemas. Note: js2at is currently built as an
-       // extension. If it is ever built into the browser the connection
-       // mechanism may change, and this line may no longer be necessary.
-      "jpgoldinadnmhfknenolkgbnockemnid"
+      // Braille IME.
+      "jddehjeebkoimngcbdkaahpobgicbffp"
     ]
-}}
+  }
+}
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_loading.html b/chrome/browser/resources/chromeos/assistant_optin/assistant_loading.html
index cc7f4cf..8c5ee1d 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_loading.html
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_loading.html
@@ -11,6 +11,7 @@
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_content_dialog.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <dom-module id="assistant-loading">
   <template>
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_optin_flow.html b/chrome/browser/resources/chromeos/assistant_optin/assistant_optin_flow.html
index 066a220..84c5b265 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_optin_flow.html
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_optin_flow.html
@@ -18,6 +18,7 @@
 <link rel="import" href="/components/common_styles.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <dom-module id="assistant-optin-flow-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.js b/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.js
index d62bab0b..0ba4c1a 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.js
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.js
@@ -103,13 +103,6 @@
   headerReceived_: false,
 
   /**
-   * Whether the webview has been successfully loaded.
-   * @type {boolean}
-   * @private
-   */
-  webViewLoaded_: false,
-
-  /**
    * Whether all the setting zippy has been successfully loaded.
    * @type {boolean}
    * @private
@@ -198,7 +191,7 @@
   },
 
   /**
-   * Reloads value prop webview.
+   * Reloads value prop page by fetching setting zippy and consent string.
    */
   reloadPage() {
     this.fire('loading');
@@ -209,14 +202,19 @@
       this.consentStringLoaded_ = false;
     }
 
+    this.buttonsDisabled = true;
+  },
+
+  /**
+   * Reloads value prop animation webview.
+   */
+  reloadWebView() {
     this.loadingError_ = false;
     this.headerReceived_ = false;
     let locale = this.locale.replace('-', '_').toLowerCase();
     for (let webviewObj of this.valuePropViewElements_) {
       webviewObj.src = this.urlTemplate_.replace('$', locale);
     }
-
-    this.buttonsDisabled = true;
   },
 
   /**
@@ -246,7 +244,6 @@
       return;
     }
 
-    this.webViewLoaded_ = true;
     if (this.settingZippyLoaded_ && this.consentStringLoaded_) {
       this.onPageLoaded();
     }
@@ -291,8 +288,8 @@
         this.sanitizer_.sanitizeHtml(data['valuePropFooter']);
 
     this.consentStringLoaded_ = true;
-    if (this.webViewLoaded_ && this.settingZippyLoaded_) {
-      this.onPageLoaded();
+    if (this.settingZippyLoaded_) {
+      this.reloadWebView();
     }
   },
 
@@ -301,8 +298,8 @@
    */
   addSettingZippy(zippy_data) {
     if (this.settingZippyLoaded_) {
-      if (this.webViewLoaded_ && this.consentStringLoaded_) {
-        this.onPageLoaded();
+      if (this.consentStringLoaded_) {
+        this.reloadWebView();
       }
       return;
     }
@@ -345,8 +342,8 @@
     }
 
     this.settingZippyLoaded_ = true;
-    if (this.webViewLoaded_ && this.consentStringLoaded_) {
-      this.onPageLoaded();
+    if (this.consentStringLoaded_) {
+      this.reloadWebView();
     }
   },
 
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html
index 59ff641d..18250e6 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html
@@ -10,6 +10,7 @@
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <dom-module id="assistant-voice-match">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/BUILD.gn b/chrome/browser/resources/chromeos/login/BUILD.gn
index 09739a1..e17e776 100644
--- a/chrome/browser/resources/chromeos/login/BUILD.gn
+++ b/chrome/browser/resources/chromeos/login/BUILD.gn
@@ -28,6 +28,13 @@
   ]
 }
 
+js_type_check("closure_compile_module") {
+  is_polymer3 = true
+  deps = [
+    "components:closure_compile_module",
+  ]
+}
+
 js_type_check("closure_compile_local") {
   uses_legacy_modules = true
   deps = [
diff --git a/chrome/browser/resources/chromeos/login/app_downloading.html b/chrome/browser/resources/chromeos/login/app_downloading.html
index 9fdd50e..c21a488c 100644
--- a/chrome/browser/resources/chromeos/login/app_downloading.html
+++ b/chrome/browser/resources/chromeos/login/app_downloading.html
@@ -7,6 +7,7 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_lottie/cr_lottie.html">
 
+<link rel="import" href="/components/login_screen_behavior.html">
 <link rel="import" href="/components/common_styles.html">
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
diff --git a/chrome/browser/resources/chromeos/login/arc_terms_of_service.html b/chrome/browser/resources/chromeos/login/arc_terms_of_service.html
index 4b77d9f3f..180f111 100644
--- a/chrome/browser/resources/chromeos/login/arc_terms_of_service.html
+++ b/chrome/browser/resources/chromeos/login/arc_terms_of_service.html
@@ -12,6 +12,8 @@
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_loading_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <link rel="stylesheet" href="chrome://resources/css/overlay.css">
 
diff --git a/chrome/browser/resources/chromeos/login/components/BUILD.gn b/chrome/browser/resources/chromeos/login/components/BUILD.gn
index d4be8c8..6dfe374d 100644
--- a/chrome/browser/resources/chromeos/login/components/BUILD.gn
+++ b/chrome/browser/resources/chromeos/login/components/BUILD.gn
@@ -4,6 +4,8 @@
 
 import("//chrome/test/base/js2gtest.gni")
 import("//third_party/closure_compiler/compile_js.gni")
+import("//ui/webui/resources/tools/js_modulizer.gni")
+import("//tools/polymer/polymer.gni")
 
 group("closure_compile") {
   deps = [
@@ -38,6 +40,15 @@
   ]
 }
 
+js_type_check("closure_compile_module") {
+  is_polymer3 = true
+  deps = [
+    ":display_manager_types.m",
+    ":login_screen_behavior.m",
+    ":multi_step_behavior.m",
+  ]
+}
+
 ###############################
 # Closure compiler libraries below
 
@@ -105,3 +116,34 @@
 
 js_library("html-echo") {
 }
+
+#### Polymer3 / JS Modules
+
+js_library("display_manager_types.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/chromeos/login/components/display_manager_types.m.js" ]
+  deps = []
+  extra_deps = [ ":modulize" ]
+}
+
+js_library("login_screen_behavior.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/chromeos/login/components/login_screen_behavior.m.js" ]
+  deps = [
+    ":display_manager_types.m"
+  ]
+  extra_deps = [ ":modulize" ]
+}
+
+js_library("multi_step_behavior.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/chromeos/login/components/multi_step_behavior.m.js" ]
+  deps = []
+  extra_deps = [ ":modulize" ]
+}
+
+js_modulizer("modulize") {
+  input_files = [
+    "display_manager_types.js",
+    "login_screen_behavior.js",
+    "multi_step_behavior.js",
+  ]
+  namespace_rewrites = []
+}
\ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/login/components/display_manager_types.js b/chrome/browser/resources/chromeos/login/components/display_manager_types.js
index d7f8085..bcfe89e 100644
--- a/chrome/browser/resources/chromeos/login/components/display_manager_types.js
+++ b/chrome/browser/resources/chromeos/login/components/display_manager_types.js
@@ -40,7 +40,7 @@
  * Should be in sync with login_types.h
  * @enum {number}
  */
-var OOBE_UI_STATE = {
+/* #export */ var OOBE_UI_STATE = {
   HIDDEN: 0, /* Any OOBE screen without specific state */
   GAIA_SIGNIN: 1,
   ACCOUNT_PICKER: 2,
diff --git a/chrome/browser/resources/chromeos/login/components/login_screen_behavior.html b/chrome/browser/resources/chromeos/login/components/login_screen_behavior.html
new file mode 100644
index 0000000..461cefd
--- /dev/null
+++ b/chrome/browser/resources/chromeos/login/components/login_screen_behavior.html
@@ -0,0 +1 @@
+<script src="login_screen_behavior.js"></script>
\ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/login/components/login_screen_behavior.js b/chrome/browser/resources/chromeos/login/components/login_screen_behavior.js
index a320c3b4..ad0796bd 100644
--- a/chrome/browser/resources/chromeos/login/components/login_screen_behavior.js
+++ b/chrome/browser/resources/chromeos/login/components/login_screen_behavior.js
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// #import {OOBE_UI_STATE} from '/components/display_manager_types.m.js';
+
 /**
  * @fileoverview
  * 'LoginScreenBehavior' is login.Screen API implementation for Polymer objects.
diff --git a/chrome/browser/resources/chromeos/login/components/multi_step_behavior.html b/chrome/browser/resources/chromeos/login/components/multi_step_behavior.html
new file mode 100644
index 0000000..3dffa65
--- /dev/null
+++ b/chrome/browser/resources/chromeos/login/components/multi_step_behavior.html
@@ -0,0 +1 @@
+<script src="multi_step_behavior.js"></script>
\ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/login/device_disabled.html b/chrome/browser/resources/chromeos/login/device_disabled.html
index be426b07..df78006 100644
--- a/chrome/browser/resources/chromeos/login/device_disabled.html
+++ b/chrome/browser/resources/chromeos/login/device_disabled.html
@@ -9,6 +9,7 @@
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
 
 <dom-module id="device-disabled-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/enterprise_enrollment.html b/chrome/browser/resources/chromeos/login/enterprise_enrollment.html
index 4003f72..92415ea 100644
--- a/chrome/browser/resources/chromeos/login/enterprise_enrollment.html
+++ b/chrome/browser/resources/chromeos/login/enterprise_enrollment.html
@@ -11,6 +11,8 @@
 <link rel="import" href="/components/hd_iron_icon.html">
 <link rel="import" href="/components/oobe_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <dom-module id="enterprise-enrollment-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/family_link_notice.html b/chrome/browser/resources/chromeos/login/family_link_notice.html
index 2d7d48a..ef2b793 100644
--- a/chrome/browser/resources/chromeos/login/family_link_notice.html
+++ b/chrome/browser/resources/chromeos/login/family_link_notice.html
@@ -12,6 +12,7 @@
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
 
 <dom-module id="family-link-notice-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/fingerprint_setup.html b/chrome/browser/resources/chromeos/login/fingerprint_setup.html
index f90f5eb..f60aea72f 100644
--- a/chrome/browser/resources/chromeos/login/fingerprint_setup.html
+++ b/chrome/browser/resources/chromeos/login/fingerprint_setup.html
@@ -14,6 +14,8 @@
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <dom-module id="fingerprint-setup-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/gesture_navigation.html b/chrome/browser/resources/chromeos/login/gesture_navigation.html
index f4e0be7..e6043c7 100644
--- a/chrome/browser/resources/chromeos/login/gesture_navigation.html
+++ b/chrome/browser/resources/chromeos/login/gesture_navigation.html
@@ -9,6 +9,8 @@
 <link rel="import" href="/components/common_styles.html">
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <dom-module id="gesture-navigation-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/gesture_navigation.js b/chrome/browser/resources/chromeos/login/gesture_navigation.js
index 21c2811..e70eda29 100644
--- a/chrome/browser/resources/chromeos/login/gesture_navigation.js
+++ b/chrome/browser/resources/chromeos/login/gesture_navigation.js
@@ -18,7 +18,11 @@
 Polymer({
   is: 'gesture-navigation-element',
 
-  behaviors: [OobeI18nBehavior, LoginScreenBehavior, MultiStepBehavior],
+  behaviors: [
+    OobeI18nBehavior,
+    LoginScreenBehavior,
+    MultiStepBehavior
+  ],
 
   UI_STEPS: GesturePage,
 
diff --git a/chrome/browser/resources/chromeos/login/marketing_opt_in.html b/chrome/browser/resources/chromeos/login/marketing_opt_in.html
index ff480be..955147cf 100644
--- a/chrome/browser/resources/chromeos/login/marketing_opt_in.html
+++ b/chrome/browser/resources/chromeos/login/marketing_opt_in.html
@@ -11,6 +11,7 @@
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
 
 <iron-iconset-svg name="marketing-opt-in-32" size="32">
     <svg>
diff --git a/chrome/browser/resources/chromeos/login/offline_ad_login.html b/chrome/browser/resources/chromeos/login/offline_ad_login.html
index 40f2791..0cc60bd 100644
--- a/chrome/browser/resources/chromeos/login/offline_ad_login.html
+++ b/chrome/browser/resources/chromeos/login/offline_ad_login.html
@@ -11,6 +11,8 @@
 <link rel="import" href="/components/hd_iron_icon.html">
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <!--
   Offline UI for the AD Domain joining and User authentication.
diff --git a/chrome/browser/resources/chromeos/login/offline_ad_login.js b/chrome/browser/resources/chromeos/login/offline_ad_login.js
index d799b89..bb21e1e 100644
--- a/chrome/browser/resources/chromeos/login/offline_ad_login.js
+++ b/chrome/browser/resources/chromeos/login/offline_ad_login.js
@@ -40,7 +40,11 @@
 Polymer({
   is: 'offline-ad-login-element',
 
-  behaviors: [OobeI18nBehavior, LoginScreenBehavior, MultiStepBehavior],
+  behaviors: [
+    OobeI18nBehavior,
+    LoginScreenBehavior,
+    MultiStepBehavior
+  ],
 
   EXTERNAL_API: [
     'reset',
diff --git a/chrome/browser/resources/chromeos/login/oobe_adb_sideloading_screen.html b/chrome/browser/resources/chromeos/login/oobe_adb_sideloading_screen.html
index 828d555..3ab27af 100644
--- a/chrome/browser/resources/chromeos/login/oobe_adb_sideloading_screen.html
+++ b/chrome/browser/resources/chromeos/login/oobe_adb_sideloading_screen.html
@@ -8,6 +8,8 @@
 <link rel="import" href="/components/hd_iron_icon.html">
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <dom-module id="oobe-adb-sideloading-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/oobe_components_resources.grdp b/chrome/browser/resources/chromeos/login/oobe_components_resources.grdp
index 5bca1b10..a5997b1 100644
--- a/chrome/browser/resources/chromeos/login/oobe_components_resources.grdp
+++ b/chrome/browser/resources/chromeos/login/oobe_components_resources.grdp
@@ -11,6 +11,11 @@
   <include name="IDR_OOBE_COMPONENTS_SCROLLABLE_BEHAVIOR_HTML" file="components/oobe_scrollable_behavior/oobe_scrollable_behavior.html" resource_path="components/oobe_scrollable_behavior.html" type="chrome_html" />
   <include name="IDR_OOBE_COMPONENTS_SCROLLABLE_BEHAVIOR_JS" file="components/oobe_scrollable_behavior/oobe_scrollable_behavior.js" resource_path="components/oobe_scrollable_behavior.js" type="chrome_html" />
 
+  <include name="IDR_OOBE_COMPONENTS_LOGIN_SCREEN_BEHAVIOR_HTML" file="components/login_screen_behavior.html" type="chrome_html" />
+  <include name="IDR_OOBE_COMPONENTS_LOGIN_SCREEN_BEHAVIOR_JS" file="components/login_screen_behavior.js" type="chrome_html" />
+  <include name="IDR_OOBE_COMPONENTS_MULTI_STEP_BEHAVIOR_HTML" file="components/multi_step_behavior.html" type="chrome_html" />
+  <include name="IDR_OOBE_COMPONENTS_MULTI_STEP_BEHAVIOR_JS" file="components/multi_step_behavior.js" type="chrome_html" />
+
   <include name="IDR_OOBE_COMPONENTS_HD_IRON_ICON_HTML" file="components/hd_iron_icon/hd_iron_icon.html" resource_path="components/hd_iron_icon.html" type="chrome_html" />
   <include name="IDR_OOBE_COMPONENTS_HD_IRON_ICON_JS" file="components/hd_iron_icon/hd_iron_icon.js" resource_path="components/hd_iron_icon.js" type="chrome_html" />
 
diff --git a/chrome/browser/resources/chromeos/login/oobe_enable_kiosk.html b/chrome/browser/resources/chromeos/login/oobe_enable_kiosk.html
index 243da68..53c3be2 100644
--- a/chrome/browser/resources/chromeos/login/oobe_enable_kiosk.html
+++ b/chrome/browser/resources/chromeos/login/oobe_enable_kiosk.html
@@ -10,6 +10,7 @@
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
 
 <dom-module id="kiosk-enable-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/oobe_reset.html b/chrome/browser/resources/chromeos/login/oobe_reset.html
index be2048e2..83ba0aa 100644
--- a/chrome/browser/resources/chromeos/login/oobe_reset.html
+++ b/chrome/browser/resources/chromeos/login/oobe_reset.html
@@ -12,6 +12,7 @@
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
 
 <dom-module id="oobe-reset-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_assistant_optin_flow.html b/chrome/browser/resources/chromeos/login/oobe_screen_assistant_optin_flow.html
index 45c1d5f6..17b2309 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_assistant_optin_flow.html
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_assistant_optin_flow.html
@@ -4,6 +4,7 @@
 
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
 
 <include src="../assistant_optin/assistant_optin_flow.html">
 
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_autolaunch.html b/chrome/browser/resources/chromeos/login/oobe_screen_autolaunch.html
index 6350cd6..29dee63 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_autolaunch.html
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_autolaunch.html
@@ -5,6 +5,7 @@
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
 
 <dom-module id="autolaunch-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/oobe_update.html b/chrome/browser/resources/chromeos/login/oobe_update.html
index 3d2bea2..f3e6b920 100644
--- a/chrome/browser/resources/chromeos/login/oobe_update.html
+++ b/chrome/browser/resources/chromeos/login/oobe_update.html
@@ -14,6 +14,8 @@
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
 <link rel="import" href="/components/oobe_loading_dialog.html">
+<link rel="import" href="/components/login_screen_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <dom-module id="oobe-update-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/oobe_update.js b/chrome/browser/resources/chromeos/login/oobe_update.js
index 3aec64e..49b17fa 100644
--- a/chrome/browser/resources/chromeos/login/oobe_update.js
+++ b/chrome/browser/resources/chromeos/login/oobe_update.js
@@ -39,7 +39,11 @@
 Polymer({
   is: 'oobe-update-element',
 
-  behaviors: [OobeI18nBehavior, MultiStepBehavior, LoginScreenBehavior],
+  behaviors: [
+    OobeI18nBehavior,
+    MultiStepBehavior,
+    LoginScreenBehavior
+  ],
 
   EXTERNAL_API: [
     'setCancelUpdateShortcutEnabled',
diff --git a/chrome/browser/resources/chromeos/login/oobe_welcome.html b/chrome/browser/resources/chromeos/login/oobe_welcome.html
index 405ff0f..f4a2acef0 100644
--- a/chrome/browser/resources/chromeos/login/oobe_welcome.html
+++ b/chrome/browser/resources/chromeos/login/oobe_welcome.html
@@ -12,6 +12,8 @@
 <link rel="import" href="/components/hd_iron_icon.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
+<link rel="import" href="/components/login_screen_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <iron-iconset-svg name="oobe-welcome-32" size="32">
   <svg>
diff --git a/chrome/browser/resources/chromeos/login/parental_handoff.html b/chrome/browser/resources/chromeos/login/parental_handoff.html
index fedb1550..6f707d25 100644
--- a/chrome/browser/resources/chromeos/login/parental_handoff.html
+++ b/chrome/browser/resources/chromeos/login/parental_handoff.html
@@ -10,6 +10,7 @@
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
 
 <dom-module id="parental-handoff-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/pin_setup.html b/chrome/browser/resources/chromeos/login/pin_setup.html
index 0091e3d..4223d923 100644
--- a/chrome/browser/resources/chromeos/login/pin_setup.html
+++ b/chrome/browser/resources/chromeos/login/pin_setup.html
@@ -15,6 +15,8 @@
 <link rel="import" href="/components/hd_iron_icon.html">
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <dom-module id="pin-setup-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/recommend_apps.html b/chrome/browser/resources/chromeos/login/recommend_apps.html
index 2267072..a019778e 100644
--- a/chrome/browser/resources/chromeos/login/recommend_apps.html
+++ b/chrome/browser/resources/chromeos/login/recommend_apps.html
@@ -10,6 +10,8 @@
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/throbber_notice.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <dom-module id="recommend-apps-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/saml_confirm_password.html b/chrome/browser/resources/chromeos/login/saml_confirm_password.html
index 05224089..b57502b 100644
--- a/chrome/browser/resources/chromeos/login/saml_confirm_password.html
+++ b/chrome/browser/resources/chromeos/login/saml_confirm_password.html
@@ -13,6 +13,8 @@
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_loading_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <!--
   SAML password confirmation UI for the Gaia flow.
diff --git a/chrome/browser/resources/chromeos/login/screen_app_launch_splash.html b/chrome/browser/resources/chromeos/login/screen_app_launch_splash.html
index ab23559e..b867e60 100644
--- a/chrome/browser/resources/chromeos/login/screen_app_launch_splash.html
+++ b/chrome/browser/resources/chromeos/login/screen_app_launch_splash.html
@@ -6,6 +6,7 @@
 <link rel="import" href="chrome://resources/html/action_link.html">
 
 <link rel="import" href="/components/throbber_notice.html">
+<link rel="import" href="/components/login_screen_behavior.html">
 
 <dom-module id="app-launch-splash-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/screen_error_message.html b/chrome/browser/resources/chromeos/login/screen_error_message.html
index 78b77fa..c9e61079 100644
--- a/chrome/browser/resources/chromeos/login/screen_error_message.html
+++ b/chrome/browser/resources/chromeos/login/screen_error_message.html
@@ -5,6 +5,7 @@
 
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
 
 <dom-module id="error-message-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/screen_gaia_signin.html b/chrome/browser/resources/chromeos/login/screen_gaia_signin.html
index 5adf8bfa..24448e0 100644
--- a/chrome/browser/resources/chromeos/login/screen_gaia_signin.html
+++ b/chrome/browser/resources/chromeos/login/screen_gaia_signin.html
@@ -11,6 +11,8 @@
 <link rel="import" href="/components/oobe_loading_dialog.html">
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/throbber_notice.html">
+<link rel="import" href="/components/login_screen_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <dom-module id="gaia-signin-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/screen_multidevice_setup.html b/chrome/browser/resources/chromeos/login/screen_multidevice_setup.html
index 204b72c6..d7d1177ab 100644
--- a/chrome/browser/resources/chromeos/login/screen_multidevice_setup.html
+++ b/chrome/browser/resources/chromeos/login/screen_multidevice_setup.html
@@ -3,6 +3,7 @@
      found in the LICENSE file. -->
 <link rel="import" href="chrome://resources/html/polymer.html">
 <link rel="import" href="chrome://oobe/custom_elements.html">
+<link rel="import" href="/components/login_screen_behavior.html">
 
 <dom-module id="multidevice-setup-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/screen_signin_fatal_error.html b/chrome/browser/resources/chromeos/login/screen_signin_fatal_error.html
index 54e68a00..2196160 100644
--- a/chrome/browser/resources/chromeos/login/screen_signin_fatal_error.html
+++ b/chrome/browser/resources/chromeos/login/screen_signin_fatal_error.html
@@ -7,6 +7,7 @@
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
 
 <dom-module id="signin-fatal-error-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/screen_tpm_error.html b/chrome/browser/resources/chromeos/login/screen_tpm_error.html
index 4836e4e..66d6295 100644
--- a/chrome/browser/resources/chromeos/login/screen_tpm_error.html
+++ b/chrome/browser/resources/chromeos/login/screen_tpm_error.html
@@ -9,6 +9,7 @@
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
 
 <dom-module id="tpm-error-message-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/screen_wrong_hwid.html b/chrome/browser/resources/chromeos/login/screen_wrong_hwid.html
index 6c38cb0..c8dc191 100644
--- a/chrome/browser/resources/chromeos/login/screen_wrong_hwid.html
+++ b/chrome/browser/resources/chromeos/login/screen_wrong_hwid.html
@@ -7,6 +7,7 @@
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
 
 <dom-module id="wrong-hwid-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/screens/login/active_directory_password_change.html b/chrome/browser/resources/chromeos/login/screens/login/active_directory_password_change.html
index a582f27..cf55b4a 100644
--- a/chrome/browser/resources/chromeos/login/screens/login/active_directory_password_change.html
+++ b/chrome/browser/resources/chromeos/login/screens/login/active_directory_password_change.html
@@ -13,6 +13,8 @@
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
 <link rel="import" href="/components/oobe_loading_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <!--
   Offline UI for the Active Directory password change.
diff --git a/chrome/browser/resources/chromeos/login/screens/login/encryption_migration.html b/chrome/browser/resources/chromeos/login/screens/login/encryption_migration.html
index a578b43..7a0e44f 100644
--- a/chrome/browser/resources/chromeos/login/screens/login/encryption_migration.html
+++ b/chrome/browser/resources/chromeos/login/screens/login/encryption_migration.html
@@ -10,6 +10,8 @@
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <dom-module id="encryption-migration-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/screens/login/gaia_password_changed.html b/chrome/browser/resources/chromeos/login/screens/login/gaia_password_changed.html
index 5736612..058b8c6 100644
--- a/chrome/browser/resources/chromeos/login/screens/login/gaia_password_changed.html
+++ b/chrome/browser/resources/chromeos/login/screens/login/gaia_password_changed.html
@@ -11,6 +11,8 @@
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/oobe_loading_dialog.html">
+<link rel="import" href="/components/login_screen_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <!--
   Password changed UI for the Gaia flow.
diff --git a/chrome/browser/resources/chromeos/login/screens/login/offline_login.html b/chrome/browser/resources/chromeos/login/screens/login/offline_login.html
index 614a5896..0621628 100644
--- a/chrome/browser/resources/chromeos/login/screens/login/offline_login.html
+++ b/chrome/browser/resources/chromeos/login/screens/login/offline_login.html
@@ -12,6 +12,7 @@
 <link rel="import" href="/components/oobe_content_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
 
 <!--
   Offline UI for the Login flow.
diff --git a/chrome/browser/resources/chromeos/login/screens/login/public_session_terms_of_service.html b/chrome/browser/resources/chromeos/login/screens/login/public_session_terms_of_service.html
index b69dd1d..0eb4e7d4 100644
--- a/chrome/browser/resources/chromeos/login/screens/login/public_session_terms_of_service.html
+++ b/chrome/browser/resources/chromeos/login/screens/login/public_session_terms_of_service.html
@@ -13,6 +13,8 @@
 <link rel="import" href="/components/oobe_loading_dialog.html">
 <link rel="import" href="/components/throbber_notice.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <dom-module id="terms-of-service-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/screens/login/supervision_transition.html b/chrome/browser/resources/chromeos/login/screens/login/supervision_transition.html
index fd50576..4c2c7ab 100644
--- a/chrome/browser/resources/chromeos/login/screens/login/supervision_transition.html
+++ b/chrome/browser/resources/chromeos/login/screens/login/supervision_transition.html
@@ -6,6 +6,8 @@
 
 <link rel="import" href="/components/common_styles.html">
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
+<link rel="import" href="/components/login_screen_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <dom-module id="supervision-transition-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/screens/login/supervision_transition.js b/chrome/browser/resources/chromeos/login/screens/login/supervision_transition.js
index 86b3984d..1277486 100644
--- a/chrome/browser/resources/chromeos/login/screens/login/supervision_transition.js
+++ b/chrome/browser/resources/chromeos/login/screens/login/supervision_transition.js
@@ -17,7 +17,11 @@
 Polymer({
   is: 'supervision-transition-element',
 
-  behaviors: [OobeI18nBehavior, LoginScreenBehavior, MultiStepBehavior],
+  behaviors: [
+    OobeI18nBehavior,
+    LoginScreenBehavior,
+    MultiStepBehavior
+  ],
 
   properties: {
     /**
diff --git a/chrome/browser/resources/chromeos/login/screens/login/update_required_card.html b/chrome/browser/resources/chromeos/login/screens/login/update_required_card.html
index 6d5f6d18..016c3f72 100644
--- a/chrome/browser/resources/chromeos/login/screens/login/update_required_card.html
+++ b/chrome/browser/resources/chromeos/login/screens/login/update_required_card.html
@@ -9,6 +9,8 @@
 <link rel="import" href="/components/oobe_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <!--
   Update required card that informs user that current chromeos version does not
diff --git a/chrome/browser/resources/chromeos/login/screens/oobe/auto_enrollment_check.html b/chrome/browser/resources/chromeos/login/screens/oobe/auto_enrollment_check.html
index 9b3b34b..d935d83 100644
--- a/chrome/browser/resources/chromeos/login/screens/oobe/auto_enrollment_check.html
+++ b/chrome/browser/resources/chromeos/login/screens/oobe/auto_enrollment_check.html
@@ -4,6 +4,7 @@
 
 <link rel="import" href="/components/oobe_loading_dialog.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
 
 <dom-module id="auto-enrollment-check-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/screens/oobe/demo_preferences.html b/chrome/browser/resources/chromeos/login/screens/oobe/demo_preferences.html
index ec05b50d..b3fc5299 100644
--- a/chrome/browser/resources/chromeos/login/screens/oobe/demo_preferences.html
+++ b/chrome/browser/resources/chromeos/login/screens/oobe/demo_preferences.html
@@ -7,6 +7,7 @@
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
 
 <dom-module id="demo-preferences-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/screens/oobe/demo_setup.html b/chrome/browser/resources/chromeos/login/screens/oobe/demo_setup.html
index 84c112b..97b258c5 100644
--- a/chrome/browser/resources/chromeos/login/screens/oobe/demo_setup.html
+++ b/chrome/browser/resources/chromeos/login/screens/oobe/demo_setup.html
@@ -4,6 +4,8 @@
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/progress_list_item.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <dom-module id="demo-setup-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/screens/oobe/enable_debugging.html b/chrome/browser/resources/chromeos/login/screens/oobe/enable_debugging.html
index bbeac69..36e3d0c 100644
--- a/chrome/browser/resources/chromeos/login/screens/oobe/enable_debugging.html
+++ b/chrome/browser/resources/chromeos/login/screens/oobe/enable_debugging.html
@@ -11,6 +11,8 @@
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/oobe_loading_dialog.html">
+<link rel="import" href="/components/login_screen_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <dom-module id="oobe-debugging-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/screens/oobe/hid_detection.html b/chrome/browser/resources/chromeos/login/screens/oobe/hid_detection.html
index 1506448a..24c16713 100644
--- a/chrome/browser/resources/chromeos/login/screens/oobe/hid_detection.html
+++ b/chrome/browser/resources/chromeos/login/screens/oobe/hid_detection.html
@@ -7,6 +7,7 @@
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
 
 <iron-iconset-svg name="oobe-hid-detection-20" size="20">
   <svg>
diff --git a/chrome/browser/resources/chromeos/login/screens/oobe/oobe_eula.html b/chrome/browser/resources/chromeos/login/screens/oobe/oobe_eula.html
index a63d3a5..aa4c8240 100644
--- a/chrome/browser/resources/chromeos/login/screens/oobe/oobe_eula.html
+++ b/chrome/browser/resources/chromeos/login/screens/oobe/oobe_eula.html
@@ -12,6 +12,8 @@
 <link rel="import" href="/components/hd_iron_icon.html">
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <dom-module id="oobe-eula-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/screens/oobe/oobe_network.html b/chrome/browser/resources/chromeos/login/screens/oobe/oobe_network.html
index 1a9f4bf..52a6cf0 100644
--- a/chrome/browser/resources/chromeos/login/screens/oobe/oobe_network.html
+++ b/chrome/browser/resources/chromeos/login/screens/oobe/oobe_network.html
@@ -7,6 +7,7 @@
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
 
 <dom-module id="oobe-network-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/screens/oobe/packaged_license.html b/chrome/browser/resources/chromeos/login/screens/oobe/packaged_license.html
index 51635a5..1828f3b 100644
--- a/chrome/browser/resources/chromeos/login/screens/oobe/packaged_license.html
+++ b/chrome/browser/resources/chromeos/login/screens/oobe/packaged_license.html
@@ -11,6 +11,7 @@
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
 
 <dom-module id="packaged-license-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/structure/components_common.js b/chrome/browser/resources/chromeos/login/structure/components_common.js
index e83e83ea..53a848b1 100644
--- a/chrome/browser/resources/chromeos/login/structure/components_common.js
+++ b/chrome/browser/resources/chromeos/login/structure/components_common.js
@@ -9,8 +9,6 @@
 // This inclusion is types-only. No actual code to execute.
 // <include src="../components/oobe_types.js">
 
-// <include src="../components/login_screen_behavior.js">
-// <include src="../components/multi_step_behavior.js">
 // <include src="../components/oobe_buttons.js">
 // <include src="../components/oobe_modal_dialog.js">
 // <include src="../components/html-echo.js">
diff --git a/chrome/browser/resources/chromeos/login/sync_consent.html b/chrome/browser/resources/chromeos/login/sync_consent.html
index c1ff67f..a06a046 100644
--- a/chrome/browser/resources/chromeos/login/sync_consent.html
+++ b/chrome/browser/resources/chromeos/login/sync_consent.html
@@ -14,6 +14,8 @@
 <link rel="import" href="/components/oobe_loading_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <dom-module id="sync-consent-element">
   <template>
diff --git a/chrome/browser/resources/chromeos/login/user_creation.html b/chrome/browser/resources/chromeos/login/user_creation.html
index e02438b..d55e552 100644
--- a/chrome/browser/resources/chromeos/login/user_creation.html
+++ b/chrome/browser/resources/chromeos/login/user_creation.html
@@ -12,6 +12,8 @@
 <link rel="import" href="/components/oobe_adaptive_dialog.html">
 <link rel="import" href="/components/oobe_i18n_behavior.html">
 <link rel="import" href="/components/oobe_dialog_host_behavior.html">
+<link rel="import" href="/components/login_screen_behavior.html">
+<link rel="import" href="/components/multi_step_behavior.html">
 
 <dom-module id="user-creation-element">
   <template>
diff --git a/chrome/browser/resources/history/app.js b/chrome/browser/resources/history/app.js
index e92cda7..6308172 100644
--- a/chrome/browser/resources/history/app.js
+++ b/chrome/browser/resources/history/app.js
@@ -11,7 +11,7 @@
 import './query_manager.js';
 import './router.js';
 import './shared_style.js';
-import './strings.js';
+import './strings.m.js';
 
 import {FindShortcutBehavior} from 'chrome://resources/cr_elements/find_shortcut_behavior.m.js';
 import {assert} from 'chrome://resources/js/assert.m.js';
diff --git a/chrome/browser/resources/history/history_item.js b/chrome/browser/resources/history/history_item.js
index 9a651df9..a1e03d7 100644
--- a/chrome/browser/resources/history/history_item.js
+++ b/chrome/browser/resources/history/history_item.js
@@ -4,7 +4,7 @@
 
 import './searched_label.js';
 import './shared_style.js';
-import './strings.js';
+import './strings.m.js';
 import 'chrome://resources/cr_elements/cr_icons_css.m.js';
 import 'chrome://resources/cr_elements/shared_vars_css.m.js';
 import 'chrome://resources/js/icon.m.js';
diff --git a/chrome/browser/resources/history/history_toolbar.js b/chrome/browser/resources/history/history_toolbar.js
index b32eebcf..0e5a49f 100644
--- a/chrome/browser/resources/history/history_toolbar.js
+++ b/chrome/browser/resources/history/history_toolbar.js
@@ -5,7 +5,7 @@
 import 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.m.js';
 import 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.js';
 import './shared_style.js';
-import './strings.js';
+import './strings.m.js';
 
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/chrome/browser/resources/history/side_bar.js b/chrome/browser/resources/history/side_bar.js
index 26cea9c..1f1ef5f 100644
--- a/chrome/browser/resources/history/side_bar.js
+++ b/chrome/browser/resources/history/side_bar.js
@@ -12,7 +12,7 @@
 import 'chrome://resources/polymer/v3_0/paper-ripple/paper-ripple.js';
 import 'chrome://resources/polymer/v3_0/paper-styles/color.js';
 import './shared_style.js';
-import './strings.js';
+import './strings.m.js';
 
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {IronA11yKeysBehavior} from 'chrome://resources/polymer/v3_0/iron-a11y-keys-behavior/iron-a11y-keys-behavior.js';
diff --git a/chrome/browser/resources/history/synced_device_card.js b/chrome/browser/resources/history/synced_device_card.js
index a90addac..e0b1f0e 100644
--- a/chrome/browser/resources/history/synced_device_card.js
+++ b/chrome/browser/resources/history/synced_device_card.js
@@ -9,7 +9,7 @@
 import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
 import './searched_label.js';
 import './shared_style.js';
-import './strings.js';
+import './strings.m.js';
 
 import {FocusRow} from 'chrome://resources/js/cr/ui/focus_row.m.js';
 import {getFaviconForPageURL} from 'chrome://resources/js/icon.m.js';
diff --git a/chrome/browser/resources/history/synced_device_manager.js b/chrome/browser/resources/history/synced_device_manager.js
index 4f22ca5..1180309a 100644
--- a/chrome/browser/resources/history/synced_device_manager.js
+++ b/chrome/browser/resources/history/synced_device_manager.js
@@ -10,7 +10,7 @@
 import 'chrome://resources/cr_elements/shared_vars_css.m.js';
 import './shared_style.js';
 import './synced_device_card.js';
-import './strings.js';
+import './strings.m.js';
 
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {FocusGrid} from 'chrome://resources/js/cr/ui/focus_grid.m.js';
diff --git a/chrome/browser/resources/read_later/app.js b/chrome/browser/resources/read_later/app.js
index 7433b13..5dcf1a2 100644
--- a/chrome/browser/resources/read_later/app.js
+++ b/chrome/browser/resources/read_later/app.js
@@ -9,17 +9,16 @@
 import 'chrome://resources/cr_elements/mwb_shared_vars.js';
 import 'chrome://resources/polymer/v3_0/iron-selector/iron-selector.js';
 import './read_later_shared_style.js';
+import './strings.m.js';
 
 import {assertNotReached} from 'chrome://resources/js/assert.m.js';
-import {listenOnce} from 'chrome://resources/js/util.m.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
+import {listenOnce} from 'chrome://resources/js/util.m.js';
 import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {ReadLaterApiProxy, ReadLaterApiProxyImpl} from './read_later_api_proxy.js';
 import {ReadLaterItemElement} from './read_later_item.js';
 
-import './strings.js';
-
 /** @type {!Set<string>} */
 const navigationKeys = new Set(['ArrowDown', 'ArrowUp']);
 
diff --git a/chrome/browser/resources/signin/profile_picker/policy_helper.js b/chrome/browser/resources/signin/profile_picker/policy_helper.js
index 8630e2e..b70d6a2 100644
--- a/chrome/browser/resources/signin/profile_picker/policy_helper.js
+++ b/chrome/browser/resources/signin/profile_picker/policy_helper.js
@@ -2,8 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import './strings.m.js';
+
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
-import './strings.js';
 
 /** @return {boolean} */
 export function isGuestModeEnabled() {
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_app.js b/chrome/browser/resources/signin/profile_picker/profile_picker_app.js
index 09f8beb..4d56660 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_picker_app.js
+++ b/chrome/browser/resources/signin/profile_picker/profile_picker_app.js
@@ -6,7 +6,7 @@
 import 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.m.js';
 import './profile_picker_main_view.js';
 import './profile_picker_shared_css.js';
-import './strings.js';
+import './strings.m.js';
 
 import {assert, assertNotReached} from 'chrome://resources/js/assert.m.js';
 import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.js b/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.js
index f1c5345..2b0cc9a 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.js
+++ b/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.js
@@ -11,7 +11,7 @@
 import './icons.js';
 import './profile_card.js';
 import './profile_picker_shared_css.js';
-import './strings.js';
+import './strings.m.js';
 
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {WebUIListenerBehavior} from 'chrome://resources/js/web_ui_listener_behavior.m.js';
diff --git a/chrome/browser/resources/tab_search/app.js b/chrome/browser/resources/tab_search/app.js
index 3012a7e..ff46dd39 100644
--- a/chrome/browser/resources/tab_search/app.js
+++ b/chrome/browser/resources/tab_search/app.js
@@ -10,7 +10,7 @@
 import './infinite_list.js';
 import './tab_search_item.js';
 import './tab_search_search_field.js';
-import './strings.js';
+import './strings.m.js';
 
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
diff --git a/chrome/browser/resources/tab_search/tab_search_item.js b/chrome/browser/resources/tab_search/tab_search_item.js
index f9fa81d..c0f9b15 100644
--- a/chrome/browser/resources/tab_search/tab_search_item.js
+++ b/chrome/browser/resources/tab_search/tab_search_item.js
@@ -7,6 +7,7 @@
 import 'chrome://resources/cr_elements/mwb_shared_icons.js';
 import 'chrome://resources/cr_elements/mwb_shared_vars.js';
 import 'chrome://resources/cr_elements/shared_vars_css.m.js';
+import './strings.m.js';
 
 import {getFaviconForPageURL} from 'chrome://resources/js/icon.m.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
@@ -15,7 +16,6 @@
 
 import {TabData} from './tab_data.js';
 import {Tab} from './tab_search.mojom-webui.js';
-import './strings.js';
 
 export class TabSearchItem extends PolymerElement {
   static get is() {
diff --git a/chrome/browser/resources/tools/optimize_webui.gni b/chrome/browser/resources/tools/optimize_webui.gni
index 5bcdb42a7..88d4b6fd 100644
--- a/chrome/browser/resources/tools/optimize_webui.gni
+++ b/chrome/browser/resources/tools/optimize_webui.gni
@@ -38,11 +38,6 @@
 
     inputs = []
     outputs = []
-    if (defined(invoker.html_out_files)) {
-      foreach(_out, invoker.html_out_files) {
-        outputs += [ "$target_gen_dir/$_out" ]
-      }
-    }
     foreach(_out, invoker.js_out_files) {
       outputs += [ "$target_gen_dir/$_out" ]
     }
@@ -83,25 +78,8 @@
     }
     args += [ "--external_paths" ] + external_paths
 
-    if (defined(invoker.html_in_files)) {
-      args += [ "--html_in_files" ] + invoker.html_in_files
-    }
-
-    if (defined(invoker.html_out_files)) {
-      args += [ "--html_out_files" ] + invoker.html_out_files
-    }
-
-    if (defined(invoker.insert_in_head)) {
-      args += [
-        "--insert_in_head",
-        invoker.insert_in_head,
-      ]
-    }
-
-    if (defined(invoker.js_module_in_files)) {
-      inputs += [ "//chrome/browser/resources/tools/rollup_plugin.js" ]
-      args += [ "--js_module_in_files" ] + invoker.js_module_in_files
-    }
+    inputs += [ "//chrome/browser/resources/tools/rollup_plugin.js" ]
+    args += [ "--js_module_in_files" ] + invoker.js_module_in_files
 
     if (defined(invoker.out_manifest)) {
       args += [
diff --git a/chrome/browser/resources/tools/optimize_webui.py b/chrome/browser/resources/tools/optimize_webui.py
index ddada8e..f41a89b 100755
--- a/chrome/browser/resources/tools/optimize_webui.py
+++ b/chrome/browser/resources/tools/optimize_webui.py
@@ -24,49 +24,9 @@
 import node_modules
 
 
-_RESOURCES_PATH = os.path.join(
-    _SRC_PATH, 'ui', 'webui', 'resources', '').replace('\\', '/')
-
-
-_CR_ELEMENTS_PATH = os.path.join(
-    _RESOURCES_PATH, 'cr_elements', '').replace('\\', '/')
-
-
-_CR_COMPONENTS_PATH = os.path.join(
-    _RESOURCES_PATH, 'cr_components', '').replace('\\', '/')
-
-
-_CSS_RESOURCES_PATH = os.path.join(
-    _RESOURCES_PATH, 'css', '').replace('\\', '/')
-
-
-_HTML_RESOURCES_PATH = os.path.join(
-    _RESOURCES_PATH, 'html', '').replace('\\', '/')
-
-
-_JS_RESOURCES_PATH = os.path.join(_RESOURCES_PATH, 'js', '').replace('\\', '/')
-
-
-_IMAGES_RESOURCES_PATH = os.path.join(
-    _RESOURCES_PATH, 'images', '').replace('\\', '/')
-
-
-_POLYMER_PATH = os.path.join(
-    _SRC_PATH, 'third_party', 'polymer', 'v1_0', 'components-chromium',
-    '').replace('\\', '/')
-
-
 # These files are already combined and minified.
-_BASE_EXCLUDES = [
-  # Excludes applying only to Polymer 2.
-  'chrome://resources/html/polymer.html',
-  'chrome://resources/polymer/v1_0/polymer/polymer.html',
-  'chrome://resources/polymer/v1_0/polymer/polymer-micro.html',
-  'chrome://resources/polymer/v1_0/polymer/polymer-mini.html',
-  'chrome://resources/js/load_time_data.js'
-]
+_BASE_EXCLUDES = []
 for excluded_file in [
-  # Common excludes for both Polymer 2 and 3.
   'resources/polymer/v1_0/web-animations-js/web-animations-next-lite.min.js',
   'resources/css/roboto.css',
   'resources/css/text_defaults.css',
@@ -76,8 +36,6 @@
   'resources/mojo/mojo/public/mojom/base/time.mojom-lite.js',
   'resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom.html',
   'resources/mojo/services/network/public/mojom/ip_address.mojom.html',
-
-  # Excludes applying only to Polymer 3.
   'resources/polymer/v3_0/polymer/polymer_bundled.min.js',
   'resources/js/load_time_data.m.js',
 ]:
@@ -86,44 +44,19 @@
      _BASE_EXCLUDES.append("chrome://" + excluded_file)
      _BASE_EXCLUDES.append("//" + excluded_file)
 
-_VULCANIZE_BASE_ARGS = [
-  '--inline-css',
-  '--inline-scripts',
-  '--rewrite-urls-in-templates',
-  '--strip-comments',
-]
-
-_URL_MAPPINGS = []
-for (redirect_url, file_path) in [
-    ('resources/cr_components/', _CR_COMPONENTS_PATH),
-    ('resources/cr_elements/', _CR_ELEMENTS_PATH),
-    ('resources/css/', _CSS_RESOURCES_PATH),
-    ('resources/html/', _HTML_RESOURCES_PATH),
-    ('resources/js/', _JS_RESOURCES_PATH),
-    ('resources/polymer/v1_0/', _POLYMER_PATH),
-    ('resources/images/', _IMAGES_RESOURCES_PATH),
-]:
-  # Redirect both the chrome://resources form and the scheme-relative form.
-  _URL_MAPPINGS.append(('chrome://' + redirect_url, file_path))
-  _URL_MAPPINGS.append(('//' + redirect_url, file_path))
-
-
-_VULCANIZE_REDIRECT_ARGS = list(itertools.chain.from_iterable(map(
-    lambda m: ['--redirect', '%s|%s' % (m[0], m[1])], _URL_MAPPINGS)))
-
-
-def _undo_mapping(mappings, url):
-  for (redirect_url, file_path) in mappings:
-    if url.startswith(redirect_url):
-      return url.replace(redirect_url, file_path + os.sep, 1)
-  # TODO(dbeam): can we make this stricter?
-  return url
 
 def _request_list_path(out_path, host_url):
   host = host_url[host_url.find('://') + 3:-1]
   return os.path.join(out_path, host + '_requestlist.txt')
 
-# Get a list of all files that were bundled with polymer-bundler and update the
+def _get_dep_path(dep, host_url, in_path):
+  if dep.startswith(host_url):
+    return dep.replace(host_url, os.path.relpath(in_path, _CWD))
+  elif not (dep.startswith('chrome://') or dep.startswith('//')):
+    return os.path.relpath(in_path, _CWD) + '/' + dep
+  return dep
+
+# Get a list of all files that were bundled with rollup and update the
 # depfile accordingly such that Ninja knows when to re-trigger.
 def _update_dep_file(in_folder, args, manifest):
   in_path = os.path.join(_CWD, in_folder)
@@ -135,22 +68,12 @@
 
   # Add a slash in front of every dependency that is not a chrome:// URL, so
   # that we can map it to the correct source file path below.
-  request_list = map(
-      lambda dep: '/' + dep if not (dep.startswith('chrome://') or dep.startswith('//')) else dep,
-      request_list)
+  request_list = map(lambda dep: _get_dep_path(dep, args.host_url, in_path),
+                     request_list)
 
-  # Undo the URL mappings applied by vulcanize to get file paths relative to
-  # current working directory.
-  url_mappings = _URL_MAPPINGS + [
-      ('/', os.path.relpath(in_path, _CWD)),
-      (args.host_url, os.path.relpath(in_path, _CWD)),
-  ]
+  deps = map(os.path.normpath, request_list)
 
-  deps = [_undo_mapping(url_mappings, u) for u in request_list]
-  deps = map(os.path.normpath, deps)
-
-  out_file_name = args.html_out_files[0] if args.html_out_files else \
-                  args.js_out_files[0]
+  out_file_name = args.js_out_files[0]
 
   with open(os.path.join(_CWD, args.depfile), 'w') as f:
     deps_file_header = os.path.join(args.out_folder, out_file_name)
@@ -264,63 +187,6 @@
 
   return bundled_paths
 
-def _bundle_v2(tmp_out_dir, in_path, out_path, manifest_out_path, args,
-               excludes):
-  in_html_args = []
-  for f in args.html_in_files:
-    in_html_args.append(f)
-
-  exclude_args = []
-  for f in excludes:
-    exclude_args.append('--exclude')
-    exclude_args.append(f);
-
-  node.RunNode(
-      [node_modules.PathToBundler()] +
-      _VULCANIZE_BASE_ARGS + _VULCANIZE_REDIRECT_ARGS + exclude_args +
-      [
-       '--manifest-out', manifest_out_path,
-       '--root', in_path,
-       '--redirect', '%s|%s' % (args.host_url, in_path + '/'),
-       '--out-dir', os.path.relpath(tmp_out_dir, _CWD).replace('\\', '/'),
-       '--shell', args.html_in_files[0],
-      ] + in_html_args)
-
-  for index, html_file in enumerate(args.html_in_files):
-    with open(os.path.join(
-        os.path.relpath(tmp_out_dir, _CWD), html_file), 'r') as f:
-      output = f.read()
-
-      # Grit includes are not supported, use HTML imports instead.
-      output = output.replace('<include src="', '<include src-disabled="')
-
-      if args.insert_in_head:
-        assert '<head>' in output
-        # NOTE(dbeam): polymer-bundler eats <base> tags after processing.
-        # This undoes that by adding a <base> tag to the (post-processed)
-        # generated output.
-        output = output.replace('<head>', '<head>' + args.insert_in_head)
-
-    # Open file again with 'w' such that the previous contents are
-    # overwritten.
-    with open(os.path.join(
-        os.path.relpath(tmp_out_dir, _CWD), html_file), 'w') as f:
-      f.write(output)
-
-  bundled_paths = []
-  for index, html_in_file in enumerate(args.html_in_files):
-    bundled_paths.append(
-        os.path.join(tmp_out_dir, args.html_out_files[index]))
-    js_out_file = args.js_out_files[index]
-
-    # Run crisper to separate the JS from the HTML file.
-    node.RunNode([node_modules.PathToCrisper(),
-                 '--source', os.path.join(tmp_out_dir, html_in_file),
-                 '--script-in-head', 'false',
-                 '--html', bundled_paths[index],
-                 '--js', os.path.join(tmp_out_dir, js_out_file)])
-  return bundled_paths
-
 def _optimize(in_folder, args):
   in_path = os.path.normpath(os.path.join(_CWD, in_folder)).replace('\\', '/')
   out_path = os.path.join(_CWD, args.out_folder).replace('\\', '/')
@@ -330,27 +196,17 @@
   excludes = _BASE_EXCLUDES + [
     # This file is dynamically created by C++. Need to specify an exclusion
     # URL for both the relative URL and chrome:// URL syntax.
-    'strings.js',
     'strings.m.js',
-    '%s/strings.js' % args.host_url,
     '%s/strings.m.js' % args.host_url,
   ]
   excludes.extend(args.exclude or [])
   external_paths = args.external_paths or []
 
   try:
-    if args.js_module_in_files:
-      pcb_out_paths = [os.path.join(tmp_out_dir, f) for f in args.js_out_files]
-      bundled_paths = _bundle_v3(tmp_out_dir, in_path, out_path,
-                                 manifest_out_path, args, excludes,
-                                 external_paths)
-    else:
-      # Ensure Polymer 2 and Polymer 3 request lists don't collide.
-      manifest_out_path = _request_list_path(out_path,
-                                             args.host_url[:-1] + '-v2/')
-      pcb_out_paths = [os.path.join(out_path, f) for f in args.html_out_files]
-      bundled_paths = _bundle_v2(tmp_out_dir, in_path, out_path,
-                                 manifest_out_path, args, excludes)
+    pcb_out_paths = [os.path.join(tmp_out_dir, f) for f in args.js_out_files]
+    bundled_paths = _bundle_v3(tmp_out_dir, in_path, out_path,
+                               manifest_out_path, args, excludes,
+                               external_paths)
 
     # Run polymer-css-build.
     node.RunNode([node_modules.PathToPolymerCssBuild()] +
@@ -375,22 +231,13 @@
   parser.add_argument('--exclude', nargs='*')
   parser.add_argument('--external_paths', nargs='*')
   parser.add_argument('--host', required=True)
-  parser.add_argument('--html_in_files', nargs='*')
-  parser.add_argument('--html_out_files', nargs='*')
   parser.add_argument('--input', required=True)
-  parser.add_argument('--insert_in_head')
   parser.add_argument('--js_out_files', nargs='*', required=True)
   parser.add_argument('--out_folder', required=True)
-  parser.add_argument('--js_module_in_files', nargs='*')
+  parser.add_argument('--js_module_in_files', nargs='*', required=True)
   parser.add_argument('--out-manifest')
   args = parser.parse_args(argv)
 
-  # Either JS module input files (for Polymer 3) or HTML input and output files
-  # (for Polymer 2) should be provided.
-  is_polymer2 = bool(args.html_out_files) and bool(args.html_in_files)
-  is_polymer3 = bool(args.js_module_in_files)
-  assert(is_polymer2 != is_polymer3)
-
   # NOTE(dbeam): on Windows, GN can send dirs/like/this. When joined, you might
   # get dirs/like/this\file.txt. This looks odd to windows. Normalize to right
   # the slashes.
@@ -409,22 +256,11 @@
   # information about all files that were bundled. Grab it from there.
   manifest = json.loads(open(manifest_out_path, 'r').read())
 
-  # polymer-bundler reports any missing files in the output manifest, instead of
-  # directly failing. Ensure that no such files were encountered.
-  if '_missing' in manifest:
-    raise Exception(
-        'polymer-bundler could not find files for the following URLs:\n' +
-        '\n'.join(manifest['_missing']))
-
-
   # Output a manifest file that will be used to auto-generate a grd file later.
   if args.out_manifest:
     manifest_data = {}
     manifest_data['base_dir'] = '%s' % args.out_folder
-    if (is_polymer3):
-      manifest_data['files'] = manifest.keys()
-    else:
-      manifest_data['files'] = args.html_out_files + args.js_out_files
+    manifest_data['files'] = manifest.keys()
     manifest_file = open(
         os.path.normpath(os.path.join(_CWD, args.out_manifest)), 'wb')
     json.dump(manifest_data, manifest_file)
diff --git a/chrome/browser/resources/tools/optimize_webui_test.py b/chrome/browser/resources/tools/optimize_webui_test.py
index d6caab18..15b7a867 100755
--- a/chrome/browser/resources/tools/optimize_webui_test.py
+++ b/chrome/browser/resources/tools/optimize_webui_test.py
@@ -58,19 +58,6 @@
     ]
     optimize_webui.main(args)
 
-  def _write_files_to_src_dir(self):
-    self._write_file_to_src_dir('element.html', '<div>got here!</div>')
-    self._write_file_to_src_dir('element.js', "alert('yay');")
-    self._write_file_to_src_dir('element_in_dir/element_in_dir.html',
-                                '<script src="element_in_dir.js">')
-    self._write_file_to_src_dir('element_in_dir/element_in_dir.js',
-                                "alert('hello from element_in_dir');")
-    self._write_file_to_src_dir('ui.html', '''
-<link rel="import" href="element.html">
-<link rel="import" href="element_in_dir/element_in_dir.html">
-<script src="element.js"></script>
-''')
-
   def _write_v3_files_to_src_dir(self):
     self._write_file_to_src_dir('element.js', "alert('yay');")
     self._write_file_to_src_dir('element_in_dir/element_in_dir.js',
@@ -154,22 +141,6 @@
       self.assertIn(os.path.normpath('element_in_dir/element_in_dir.html'),
                     depfile_d)
 
-  def testSimpleOptimize(self):
-    self._write_files_to_src_dir()
-    args = [
-      '--host', 'fake-host',
-      '--html_in_files', 'ui.html',
-      '--html_out_files', 'fast.html',
-      '--js_out_files', 'fast.js',
-    ]
-    self._run_optimize(args)
-
-    fast_html = self._read_out_file('fast.html')
-    self._check_output_html(fast_html)
-    self.assertIn('<script src="fast.js"></script>', fast_html)
-    self._check_output_js('fast.js')
-    self._check_output_depfile(True)
-
   def testV3SimpleOptimize(self):
     self._write_v3_files_to_src_dir()
     args = [
diff --git a/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/ProfileDataCache.java b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/ProfileDataCache.java
index cef003d..b09b710 100644
--- a/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/ProfileDataCache.java
+++ b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/ProfileDataCache.java
@@ -225,17 +225,20 @@
         });
     }
 
-    private DisplayableProfileData createDisplayableProfileData(
-            ProfileDataSource.ProfileData profileData) {
-        return new DisplayableProfileData(profileData.getAccountEmail(),
-                prepareAvatar(profileData.getAvatar(), profileData.getAccountEmail()),
-                profileData.getFullName(), profileData.getGivenName());
-    }
-
     @Override
     public void onProfileDataUpdated(ProfileDataSource.ProfileData profileData) {
         ThreadUtils.assertOnUiThread();
-        updateCachedProfileDataAndNotifyObservers(createDisplayableProfileData(profileData));
+        final String email = profileData.getAccountEmail();
+        Bitmap avatar = profileData.getAvatar();
+        if (avatar == null) {
+            // If the avatar is null, try to fetch the monogram from IdentityManager
+            final AccountInfo accountInfo =
+                    mIdentityManager
+                            .findExtendedAccountInfoForAccountWithRefreshTokenByEmailAddress(email);
+            avatar = accountInfo != null ? accountInfo.getAccountImage() : null;
+        }
+        updateCacheAndNotifyObservers(
+                email, avatar, profileData.getFullName(), profileData.getGivenName());
     }
 
     @Override
@@ -250,28 +253,22 @@
     @Override
     public void onExtendedAccountInfoUpdated(AccountInfo accountInfo) {
         if (accountInfo.getAccountImage() != null) {
-            final String accountEmail = accountInfo.getEmail();
-            updateCachedProfileDataAndNotifyObservers(new DisplayableProfileData(accountEmail,
-                    prepareAvatar(accountInfo.getAccountImage(), accountEmail),
-                    accountInfo.getFullName(), accountInfo.getGivenName()));
+            updateCacheAndNotifyObservers(accountInfo.getEmail(), accountInfo.getAccountImage(),
+                    accountInfo.getFullName(), accountInfo.getGivenName());
         }
     }
 
-    private Drawable prepareAvatar(Bitmap bitmap, String accountEmail) {
-        if (bitmap == null) {
-            // If the given bitmap is null, try to fetch the account image which can be monogram
-            // from IdentityManager
-            bitmap = getAccountImageFromIdentityManager(accountEmail);
-        }
-        Drawable croppedAvatar = bitmap != null
-                ? AvatarGenerator.makeRoundAvatar(mContext.getResources(), bitmap, mImageSize)
+    private void updateCacheAndNotifyObservers(
+            String email, Bitmap avatar, String fullName, String givenName) {
+        Drawable croppedAvatar = avatar != null
+                ? AvatarGenerator.makeRoundAvatar(mContext.getResources(), avatar, mImageSize)
                 : mPlaceholderImage;
-        return mBadgeConfig == null ? croppedAvatar : overlayBadgeOnUserPicture(croppedAvatar);
-    }
-
-    private void updateCachedProfileDataAndNotifyObservers(DisplayableProfileData profileData) {
-        mCachedProfileData.put(profileData.getAccountEmail(), profileData);
-        notifyObservers(profileData.getAccountEmail());
+        if (mBadgeConfig != null) {
+            croppedAvatar = overlayBadgeOnUserPicture(croppedAvatar);
+        }
+        mCachedProfileData.put(
+                email, new DisplayableProfileData(email, croppedAvatar, fullName, givenName));
+        notifyObservers(email);
     }
 
     private void notifyObservers(String accountEmail) {
@@ -322,21 +319,4 @@
         drawable.draw(canvas);
         return new BitmapDrawable(context.getResources(), output);
     }
-
-    /**
-     * Fetches the account image stored in {@link AccountInfo}.
-     *
-     * If user is signed in and has a profile photo, the profile photo will be returned, otherwise,
-     * a monogram is returned.
-     * If the user is signed out, returns null.
-     *
-     * TODO(https://crbug.com/1130545): We should refactor the different sources for getting
-     *  the profile image.
-     */
-    private @Nullable Bitmap getAccountImageFromIdentityManager(String accountEmail) {
-        AccountInfo accountInfo =
-                mIdentityManager.findExtendedAccountInfoForAccountWithRefreshTokenByEmailAddress(
-                        accountEmail);
-        return accountInfo != null ? accountInfo.getAccountImage() : null;
-    }
 }
diff --git a/chrome/browser/startup_data.cc b/chrome/browser/startup_data.cc
index dd46f01..f55db44 100644
--- a/chrome/browser/startup_data.cc
+++ b/chrome/browser/startup_data.cc
@@ -73,6 +73,7 @@
   metrics::MetricsLog::RecordCoreSystemProfile(
       metrics::GetVersionString(),
       metrics::AsProtobufChannel(chrome::GetChannel()),
+      chrome::IsExtendedStableChannel(),
       chrome_feature_list_creator_->actual_locale(),
       metrics::GetAppPackageName(), &system_profile);
 
diff --git a/chrome/browser/subresource_filter/android_test_ruleset_publisher.cc b/chrome/browser/subresource_filter/android_test_ruleset_publisher.cc
index 8542cc1..aa86e1b 100644
--- a/chrome/browser/subresource_filter/android_test_ruleset_publisher.cc
+++ b/chrome/browser/subresource_filter/android_test_ruleset_publisher.cc
@@ -4,6 +4,7 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
@@ -55,7 +56,7 @@
   auto* ruleset_service =
       g_browser_process->subresource_filter_ruleset_service();
   ruleset_service->SetRulesetPublishedCallbackForTesting(base::BindOnce(
-      &OnRulesetPublished, base::Passed(&creator), ruleset_service, publisher));
+      &OnRulesetPublished, std::move(creator), ruleset_service, publisher));
   ruleset_service->IndexAndStoreAndPublishRulesetIfNeeded(
       unindexed_ruleset_info);
 
diff --git a/chrome/browser/sync/device_info_sync_service_factory.cc b/chrome/browser/sync/device_info_sync_service_factory.cc
index 56fcb64..a15ab94 100644
--- a/chrome/browser/sync/device_info_sync_service_factory.cc
+++ b/chrome/browser/sync/device_info_sync_service_factory.cc
@@ -154,7 +154,8 @@
       std::make_unique<DeviceInfoSyncClient>(profile);
   auto local_device_info_provider =
       std::make_unique<syncer::LocalDeviceInfoProviderImpl>(
-          chrome::GetChannel(), chrome::GetVersionString(),
+          chrome::GetChannel(),
+          chrome::GetVersionString(chrome::WithExtendedStable(false)),
           device_info_sync_client.get());
 
   auto device_prefs = std::make_unique<syncer::DeviceInfoPrefs>(
diff --git a/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc b/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc
index 53383aa..5157f44 100644
--- a/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc
@@ -1001,14 +1001,8 @@
   base::test::ScopedFeatureList features_;
 };
 
-// TODO(1185289): Fails under msan.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_ShouldNotDeleteLastClosedTab DISABLED_ShouldNotDeleteLastClosedTab
-#else
-#define MAYBE_ShouldNotDeleteLastClosedTab ShouldNotDeleteLastClosedTab
-#endif
 IN_PROC_BROWSER_TEST_F(SingleClientSessionsWithDestroyProfileSyncTest,
-                       MAYBE_ShouldNotDeleteLastClosedTab) {
+                       ShouldNotDeleteLastClosedTab) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(CheckInitialState(0));
 
diff --git a/chrome/browser/sync/test/integration/sync_errors_test.cc b/chrome/browser/sync/test/integration/sync_errors_test.cc
index c73ba2c0..b95325bf 100644
--- a/chrome/browser/sync/test/integration/sync_errors_test.cc
+++ b/chrome/browser/sync/test/integration/sync_errors_test.cc
@@ -37,6 +37,19 @@
 
 constexpr int64_t kUserEventTimeUsec = 123456;
 
+syncer::ModelTypeSet GetThrottledDataTypes(
+    syncer::ProfileSyncService* sync_service) {
+  base::RunLoop loop;
+  syncer::ModelTypeSet throttled_types;
+  sync_service->GetThrottledDataTypesForTest(
+      base::BindLambdaForTesting([&](syncer::ModelTypeSet result) {
+        throttled_types = result;
+        loop.Quit();
+      }));
+  loop.Run();
+  return throttled_types;
+}
+
 class SyncEngineStoppedChecker : public SingleClientStatusChangeChecker {
  public:
   explicit SyncEngineStoppedChecker(ProfileSyncService* service)
@@ -402,7 +415,7 @@
             "false");
 
   // PREFERENCES should now be throttled.
-  EXPECT_EQ(GetSyncService(0)->GetThrottledDataTypesForTest(),
+  EXPECT_EQ(GetThrottledDataTypes(GetSyncService(0)),
             syncer::ModelTypeSet{syncer::PREFERENCES});
 
   // Unthrottle PREFERENCES to verify that sync can resume.
@@ -413,8 +426,7 @@
   EXPECT_TRUE(
       FakeServerPrefMatchesValueChecker(prefs::kHomePageIsNewTabPage, "true")
           .Wait());
-  EXPECT_EQ(GetSyncService(0)->GetThrottledDataTypesForTest(),
-            syncer::ModelTypeSet());
+  EXPECT_EQ(GetThrottledDataTypes(GetSyncService(0)), syncer::ModelTypeSet());
 }
 
 }  // namespace
diff --git a/chrome/browser/sync/test/integration/two_client_sessions_sync_test.cc b/chrome/browser/sync/test/integration/two_client_sessions_sync_test.cc
index e4534cd..baeb699 100644
--- a/chrome/browser/sync/test/integration/two_client_sessions_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_sessions_sync_test.cc
@@ -269,14 +269,8 @@
   base::test::ScopedFeatureList features_;
 };
 
-// TODO(1185289): Fails under msan.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_ShouldNotSyncLastClosedTab DISABLED_ShouldNotSyncLastClosedTab
-#else
-#define MAYBE_ShouldNotSyncLastClosedTab ShouldNotSyncLastClosedTab
-#endif
 IN_PROC_BROWSER_TEST_F(TwoClientSessionsWithDestroyProfileSyncTest,
-                       MAYBE_ShouldNotSyncLastClosedTab) {
+                       ShouldNotSyncLastClosedTab) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
   ASSERT_TRUE(CheckInitialState(0));
diff --git a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorSupplier.java b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorSupplier.java
index 7dddfcb7..e3846add 100644
--- a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorSupplier.java
+++ b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorSupplier.java
@@ -4,8 +4,11 @@
 
 package org.chromium.chrome.browser.tabmodel;
 
+import androidx.annotation.VisibleForTesting;
+
 import org.chromium.base.UnownedUserDataKey;
 import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.supplier.UnownedUserDataSupplier;
 import org.chromium.ui.base.WindowAndroid;
 
@@ -16,9 +19,11 @@
 public class TabModelSelectorSupplier extends UnownedUserDataSupplier<TabModelSelector> {
     private static final UnownedUserDataKey<TabModelSelectorSupplier> KEY =
             new UnownedUserDataKey<TabModelSelectorSupplier>(TabModelSelectorSupplier.class);
+    private static ObservableSupplierImpl<TabModelSelector> sInstanceForTesting;
 
     /** Return {@link TabModelSelector} supplier associated with the given {@link WindowAndroid}. */
     public static ObservableSupplier<TabModelSelector> from(WindowAndroid windowAndroid) {
+        if (sInstanceForTesting != null) return sInstanceForTesting;
         return KEY.retrieveDataFromHost(windowAndroid.getUnownedUserDataHost());
     }
 
@@ -26,4 +31,11 @@
     public TabModelSelectorSupplier() {
         super(KEY);
     }
+
+    /** Sets an instance for testing. */
+    @VisibleForTesting
+    public static void setInstanceForTesting(TabModelSelector tabModelSelector) {
+        sInstanceForTesting = new ObservableSupplierImpl<>();
+        sInstanceForTesting.set(tabModelSelector);
+    }
 }
\ No newline at end of file
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 87fa30fa..a163850 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -523,7 +523,7 @@
     "//components/subresource_filter/content/browser",
     "//components/subresource_filter/core/browser",
     "//components/sync",
-    "//components/sync/driver:resources",
+    "//components/sync/driver/resources",
     "//components/sync_preferences",
     "//components/sync_sessions",
     "//components/tab_groups",
@@ -635,6 +635,7 @@
       "//components/feed/core/shared_prefs:feed_shared_prefs",
       "//components/feed/core/v2:feed_core_v2",
       "//components/infobars/content",
+      "//components/messages/android:feature_flags",
       "//components/query_tiles",
       "//components/resources:android_resources",
       "//components/security_state/content/android",
diff --git a/chrome/browser/ui/app_list/app_service/app_service_context_menu.cc b/chrome/browser/ui/app_list/app_service/app_service_context_menu.cc
index 4e99fc5..74588ae7 100644
--- a/chrome/browser/ui/app_list/app_service/app_service_context_menu.cc
+++ b/chrome/browser/ui/app_list/app_service/app_service_context_menu.cc
@@ -11,9 +11,6 @@
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
 #include "chrome/browser/apps/app_service/menu_util.h"
-#include "chrome/browser/ash/borealis/borealis_service.h"
-#include "chrome/browser/ash/borealis/borealis_shutdown_monitor.h"
-#include "chrome/browser/ash/borealis/borealis_util.h"
 #include "chrome/browser/ash/crosapi/browser_manager.h"
 #include "chrome/browser/ash/plugin_vm/plugin_vm_manager.h"
 #include "chrome/browser/ash/plugin_vm/plugin_vm_manager_factory.h"
@@ -141,10 +138,6 @@
       } else if (app_id() == plugin_vm::kPluginVmShelfAppId) {
         plugin_vm::PluginVmManagerFactory::GetForProfile(profile())
             ->StopPluginVm(plugin_vm::kPluginVmName, /*force=*/false);
-      } else if (app_id() == borealis::kBorealisAppId) {
-        borealis::BorealisService::GetForProfile(profile())
-            ->ShutdownMonitor()
-            .ShutdownNow();
       } else {
         LOG(ERROR) << "App " << app_id()
                    << " should not have a shutdown guest OS command.";
diff --git a/chrome/browser/ui/app_list/search/files/drive_file_provider.cc b/chrome/browser/ui/app_list/search/files/drive_file_provider.cc
index 7fd48d83..25ec417 100644
--- a/chrome/browser/ui/app_list/search/files/drive_file_provider.cc
+++ b/chrome/browser/ui/app_list/search/files/drive_file_provider.cc
@@ -10,44 +10,15 @@
 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/search/files/file_result.h"
-#include "chrome/browser/ui/app_list/search/search_controller.h"
 #include "chromeos/components/drivefs/mojom/drivefs.mojom.h"
-#include "chromeos/components/string_matching/fuzzy_tokenized_string_match.h"
 
 namespace app_list {
 namespace {
 
-using TokenizedString = chromeos::string_matching::TokenizedString;
-using FuzzyTokenizedStringMatch =
-    chromeos::string_matching::FuzzyTokenizedStringMatch;
+using chromeos::string_matching::TokenizedString;
 
 constexpr char kDriveFileSchema[] = "drive_file://";
 constexpr int kMaxResults = 10;
-// The default relevance should only be used as a fallback.
-// TODO(crbug.com/1154513): Log error histograms whenever this needs to be used.
-constexpr double kDefaultRelevance = 0.5;
-
-// Parameters for FuzzyTokenizedStringMatch. Note that the underlying file
-// search uses an exact substring match to retrieve file results, so using edit
-// distance here doesn't provide any benefit.
-constexpr bool kUsePrefixOnly = false;
-constexpr bool kUseWeightedRatio = true;
-constexpr bool kUseEditDistance = false;
-constexpr double kRelevanceThreshold = 0.0;
-constexpr double kPartialMatchPenaltyRate = 0.9;
-
-double FuzzyMatchRelevance(const TokenizedString& title,
-                           const TokenizedString& query) {
-  if (title.text().empty() || query.text().empty()) {
-    return kDefaultRelevance;
-  }
-
-  FuzzyTokenizedStringMatch match;
-  match.IsRelevant(query, title, kRelevanceThreshold, kUsePrefixOnly,
-                   kUseWeightedRatio, kUseEditDistance,
-                   kPartialMatchPenaltyRate);
-  return match.relevance();
-}
 
 }  // namespace
 
@@ -81,10 +52,8 @@
 
   last_tokenized_query_.emplace(query, TokenizedString::Mode::kWords);
 
-  // New scores will be assigned for sorting purposes so SortField and
-  // SortDirection are chosen arbitrarily.
-  // TODO(crbug.com/1154513): Double check that sorting doesn't affect the set
-  // of results from the backend.
+  // New scores will be assigned for sorting purposes so use the default
+  // SortField. The SortDirection does nothing in this case.
   drive_service_->SearchDriveByFileName(
       base::UTF16ToUTF8(query), kMaxResults,
       drivefs::mojom ::QueryParameters::SortField::kNone,
@@ -116,21 +85,13 @@
   const base::FilePath& reparented_path =
       drive_service_->GetMountPointPath().Append(path.value());
 
-  auto result = std::make_unique<FileResult>(
-      kDriveFileSchema, reparented_path,
-      ash::AppListSearchResultType::kDriveFile,
-      ash::SearchResultDisplayType::kList, kDefaultRelevance, profile_);
+  const double relevance =
+      CalculateFilenameRelevance(last_tokenized_query_, path);
 
-  // Calculate and set the fuzzy match relevance for the result.
-  if (last_tokenized_query_) {
-    const TokenizedString tokenized_title(result->title(),
-                                          TokenizedString::Mode::kWords);
-    const double relevance =
-        FuzzyMatchRelevance(tokenized_title, last_tokenized_query_.value());
-    result->set_relevance(relevance);
-  }
-
-  return result;
+  return std::make_unique<FileResult>(kDriveFileSchema, reparented_path,
+                                      ash::AppListSearchResultType::kDriveFile,
+                                      ash::SearchResultDisplayType::kList,
+                                      relevance, profile_);
 }
 
 }  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/files/file_result.cc b/chrome/browser/ui/app_list/search/files/file_result.cc
index e951836f..4ad1e6d 100644
--- a/chrome/browser/ui/app_list/search/files/file_result.cc
+++ b/chrome/browser/ui/app_list/search/files/file_result.cc
@@ -21,12 +21,16 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/platform_util.h"
 #include "chrome/grit/generated_resources.h"
+#include "chromeos/components/string_matching/tokenized_string_match.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace app_list {
 
 namespace {
 
+using chromeos::string_matching::TokenizedString;
+using chromeos::string_matching::TokenizedStringMatch;
+
 std::string StripHostedFileExtensions(const std::string& filename) {
   static const base::NoDestructor<std::vector<std::string>> hosted_extensions(
       {".GDOC", ".GSHEET", ".GSLIDES", ".GDRAW", ".GTABLE", ".GLINK", ".GFORM",
@@ -43,6 +47,23 @@
 
 }  // namespace
 
+double CalculateFilenameRelevance(const base::Optional<TokenizedString>& query,
+                                  const base::FilePath& path) {
+  const TokenizedString title(
+      base::UTF8ToUTF16(StripHostedFileExtensions(path.BaseName().value())),
+      TokenizedString::Mode::kWords);
+
+  if (!query || query.value().text().empty() || title.text().empty()) {
+    // TODO(crbug.com/1154513): Log error histogram.
+    static constexpr double kDefaultRelevance = 0.5;
+    return kDefaultRelevance;
+  }
+
+  TokenizedStringMatch match;
+  match.Calculate(query.value(), title);
+  return match.relevance();
+}
+
 FileResult::FileResult(const std::string& schema,
                        const base::FilePath& filepath,
                        ResultType result_type,
diff --git a/chrome/browser/ui/app_list/search/files/file_result.h b/chrome/browser/ui/app_list/search/files/file_result.h
index 7f4a3a45..c66a50a 100644
--- a/chrome/browser/ui/app_list/search/files/file_result.h
+++ b/chrome/browser/ui/app_list/search/files/file_result.h
@@ -8,12 +8,20 @@
 #include <iosfwd>
 
 #include "base/files/file_path.h"
+#include "base/optional.h"
 #include "chrome/browser/ui/app_list/search/chrome_search_result.h"
+#include "chromeos/components/string_matching/tokenized_string.h"
 
 class Profile;
 
 namespace app_list {
 
+// Helper function for calculating a file's relevance score. Will return a
+// default relevance score if the query is missing or the filename is empty.
+double CalculateFilenameRelevance(
+    const base::Optional<chromeos::string_matching::TokenizedString>& query,
+    const base::FilePath& path);
+
 class FileResult : public ChromeSearchResult {
  public:
   FileResult(const std::string& schema,
diff --git a/chrome/browser/ui/app_list/search/files/local_file_provider.cc b/chrome/browser/ui/app_list/search/files/local_file_provider.cc
index f6b5c77..b7be462 100644
--- a/chrome/browser/ui/app_list/search/files/local_file_provider.cc
+++ b/chrome/browser/ui/app_list/search/files/local_file_provider.cc
@@ -19,11 +19,10 @@
 namespace app_list {
 namespace {
 
+using chromeos::string_matching::TokenizedString;
+
 constexpr char kLocalFileSchema[] = "local_file://";
 constexpr int kMaxResults = 25;
-// The default relevance should only be used as a fallback.
-// TODO(crbug.com/1154513): Log error histograms whenever this needs to be used.
-constexpr double kDefaultRelevance = 0.5;
 
 // Construct a case-insensitive fnmatch query from |query|. E.g. for abc123, the
 // result would be *[aA][bB][cC]123*.
@@ -74,6 +73,8 @@
   if (query.empty())
     return;
 
+  last_tokenized_query_.emplace(query, TokenizedString::Mode::kWords);
+
   base::ThreadPool::PostTask(
       FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
       base::BindOnce(&LocalFileProvider::SearchFilesByPattern,
@@ -101,10 +102,11 @@
 
 std::unique_ptr<FileResult> LocalFileProvider::MakeResult(
     const base::FilePath& path) {
-  // TODO(crbug.com/1154513): Set the result's fuzzy match relevance.
+  const double relevance =
+      CalculateFilenameRelevance(last_tokenized_query_, path);
   return std::make_unique<FileResult>(
       kLocalFileSchema, path, ash::AppListSearchResultType::kLocalFile,
-      ash::SearchResultDisplayType::kList, kDefaultRelevance, profile_);
+      ash::SearchResultDisplayType::kList, relevance, profile_);
 }
 
 }  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/files/local_file_provider.h b/chrome/browser/ui/app_list/search/files/local_file_provider.h
index 2db03ac..2d1b6fe3 100644
--- a/chrome/browser/ui/app_list/search/files/local_file_provider.h
+++ b/chrome/browser/ui/app_list/search/files/local_file_provider.h
@@ -7,7 +7,9 @@
 
 #include "base/files/file_path.h"
 #include "base/memory/weak_ptr.h"
+#include "base/optional.h"
 #include "chrome/browser/ui/app_list/search/search_provider.h"
+#include "chromeos/components/string_matching/tokenized_string.h"
 
 class Profile;
 
@@ -31,6 +33,9 @@
   void SearchFilesByPattern(const std::string& query);
   std::unique_ptr<FileResult> MakeResult(const base::FilePath& path);
 
+  base::Optional<chromeos::string_matching::TokenizedString>
+      last_tokenized_query_;
+
   Profile* const profile_;
 
   base::WeakPtrFactory<LocalFileProvider> weak_factory_{this};
diff --git a/chrome/browser/ui/app_list/search/tests/app_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/tests/app_search_provider_unittest.cc
index 75cc8e5..9690a8ff 100644
--- a/chrome/browser/ui/app_list/search/tests/app_search_provider_unittest.cc
+++ b/chrome/browser/ui/app_list/search/tests/app_search_provider_unittest.cc
@@ -60,6 +60,8 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using extensions::mojom::ManifestLocation;
+
 namespace app_list {
 namespace test {
 
@@ -238,7 +240,7 @@
 
   void AddExtension(const std::string& id,
                     const std::string& name,
-                    extensions::Manifest::Location location,
+                    ManifestLocation location,
                     int init_from_value_flags) {
     scoped_refptr<const extensions::Extension> extension =
         extensions::ExtensionBuilder()
@@ -673,7 +675,7 @@
   ASSERT_TRUE(extension_prefs);
 
   AddExtension(extension_misc::kGmailAppId, kGmailExtensionName,
-               extensions::Manifest::EXTERNAL_PREF_DOWNLOAD,
+               ManifestLocation::kExternalPrefDownload,
                extensions::Extension::NO_FLAGS);
 
   const std::string arc_gmail_app_id =
@@ -897,7 +899,7 @@
   const std::string normal_app_id =
       crx_file::id_util::GenerateId(kRankingNormalAppName);
   AddExtension(normal_app_id, kRankingNormalAppName,
-               extensions::Manifest::EXTERNAL_PREF_DOWNLOAD,
+               ManifestLocation::kExternalPrefDownload,
                extensions::Extension::NO_FLAGS);
 
   // Wait a bit to make sure time is updated.
@@ -909,22 +911,22 @@
   switch (GetParam()) {
     case TestExtensionInstallType::CONTROLLED_BY_POLICY:
       AddExtension(internal_app_id, kRankingInternalAppName,
-                   extensions::Manifest::EXTERNAL_POLICY_DOWNLOAD,
+                   ManifestLocation::kExternalPolicyDownload,
                    extensions::Extension::NO_FLAGS);
       break;
     case TestExtensionInstallType::CHROME_COMPONENT:
       AddExtension(internal_app_id, kRankingInternalAppName,
-                   extensions::Manifest::COMPONENT,
+                   ManifestLocation::kComponent,
                    extensions::Extension::NO_FLAGS);
       break;
     case TestExtensionInstallType::INSTALLED_BY_DEFAULT:
       AddExtension(internal_app_id, kRankingInternalAppName,
-                   extensions::Manifest::EXTERNAL_PREF_DOWNLOAD,
+                   ManifestLocation::kExternalPrefDownload,
                    extensions::Extension::WAS_INSTALLED_BY_DEFAULT);
       break;
     case TestExtensionInstallType::INSTALLED_BY_OEM:
       AddExtension(internal_app_id, kRankingInternalAppName,
-                   extensions::Manifest::EXTERNAL_PREF_DOWNLOAD,
+                   ManifestLocation::kExternalPrefDownload,
                    extensions::Extension::WAS_INSTALLED_BY_OEM);
       break;
   }
@@ -982,7 +984,7 @@
     const std::string internal_app_id = crx_file::id_util::GenerateId(app_id);
 
     AddExtension(internal_app_id, app_id,
-                 extensions::Manifest::EXTERNAL_PREF_DOWNLOAD,
+                 ManifestLocation::kExternalPrefDownload,
                  extensions::Extension::WAS_INSTALLED_BY_OEM);
 
     service_->EnableExtension(internal_app_id);
diff --git a/chrome/browser/ui/ash/accessibility/fake_accessibility_controller.cc b/chrome/browser/ui/ash/accessibility/fake_accessibility_controller.cc
index fc54a03..4968e75a3 100644
--- a/chrome/browser/ui/ash/accessibility/fake_accessibility_controller.cc
+++ b/chrome/browser/ui/ash/accessibility/fake_accessibility_controller.cc
@@ -62,6 +62,9 @@
 
 void FakeAccessibilityController::StopPointScan() {}
 
+void FakeAccessibilityController::SetPointScanSpeedDipsPerSecond(
+    int point_scan_speed_dips_per_second) {}
+
 void FakeAccessibilityController::SetDictationActive(bool is_active) {}
 
 void FakeAccessibilityController::ToggleDictationFromSource(
diff --git a/chrome/browser/ui/ash/accessibility/fake_accessibility_controller.h b/chrome/browser/ui/ash/accessibility/fake_accessibility_controller.h
index e617359..8bee3cc 100644
--- a/chrome/browser/ui/ash/accessibility/fake_accessibility_controller.h
+++ b/chrome/browser/ui/ash/accessibility/fake_accessibility_controller.h
@@ -42,6 +42,8 @@
   void StartPointScan() override;
   void StopPointScan() override;
   void SetDictationActive(bool is_active) override;
+  void SetPointScanSpeedDipsPerSecond(
+      int point_scan_speed_dips_per_second) override;
   void ToggleDictationFromSource(ash::DictationToggleSource source) override;
   void HandleAutoclickScrollableBoundsFound(
       gfx::Rect& bounds_in_screen) override;
diff --git a/chrome/browser/ui/ash/launcher/app_service/app_service_shelf_context_menu.cc b/chrome/browser/ui/ash/launcher/app_service/app_service_shelf_context_menu.cc
index fcfdb34..cbde8e5 100644
--- a/chrome/browser/ui/ash/launcher/app_service/app_service_shelf_context_menu.cc
+++ b/chrome/browser/ui/ash/launcher/app_service/app_service_shelf_context_menu.cc
@@ -12,9 +12,6 @@
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
 #include "chrome/browser/apps/app_service/menu_util.h"
-#include "chrome/browser/ash/borealis/borealis_service.h"
-#include "chrome/browser/ash/borealis/borealis_shutdown_monitor.h"
-#include "chrome/browser/ash/borealis/borealis_util.h"
 #include "chrome/browser/ash/crosapi/browser_manager.h"
 #include "chrome/browser/ash/plugin_vm/plugin_vm_manager.h"
 #include "chrome/browser/ash/plugin_vm/plugin_vm_manager_factory.h"
@@ -153,10 +150,6 @@
         plugin_vm::PluginVmManagerFactory::GetForProfile(
             controller()->profile())
             ->StopPluginVm(plugin_vm::kPluginVmName, /*force=*/false);
-      } else if (item().id.app_id == borealis::kBorealisAppId) {
-        borealis::BorealisService::GetForProfile(controller()->profile())
-            ->ShutdownMonitor()
-            .ShutdownNow();
       } else {
         LOG(ERROR) << "App " << item().id.app_id
                    << " should not have a shutdown guest OS command.";
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index efad7ed..6329693 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -90,6 +90,7 @@
 #include "components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_view.h"
 #include "components/autofill/core/browser/ui/payments/card_name_fix_flow_view.h"
 #include "components/infobars/core/infobar.h"
+#include "components/messages/android/messages_feature.h"
 #include "ui/android/window_android.h"
 #else  // !OS_ANDROID
 #include "chrome/browser/ui/autofill/payments/offer_notification_bubble_controller_impl.h"
@@ -531,8 +532,16 @@
     const AutofillProfile& profile,
     AddressProfileSavePromptCallback callback) {
 #if defined(OS_ANDROID)
-  save_address_profile_message_delegate_.DisplaySavePrompt(
-      web_contents(), profile, std::move(callback));
+  if (base::FeatureList::IsEnabled(
+          messages::kMessagesForAndroidInfrastructure)) {
+    save_address_profile_message_delegate_.DisplaySavePrompt(
+        web_contents(), profile, std::move(callback));
+  } else {
+    // Fallback to the default behavior without the prompt.
+    std::move(callback).Run(
+        AutofillClient::SaveAddressProfileOfferUserDecision::kAccepted,
+        profile);
+  }
 #else
   SaveAddressProfileBubbleControllerImpl::CreateForWebContents(web_contents());
   SaveAddressProfileBubbleControllerImpl* controller =
diff --git a/chrome/browser/ui/blocked_content/popup_tracker_browsertest.cc b/chrome/browser/ui/blocked_content/popup_tracker_browsertest.cc
index f72e053..a821334 100644
--- a/chrome/browser/ui/blocked_content/popup_tracker_browsertest.cc
+++ b/chrome/browser/ui/blocked_content/popup_tracker_browsertest.cc
@@ -587,8 +587,8 @@
       static_cast<int>(WindowOpenDisposition::NEW_POPUP));
 }
 
-// TODO(crbug.com/1146598): Test is flaky on Lacros.
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
+// TODO(crbug.com/1146598): Test is flaky on Lacros, Linux Ozone Wayland.
+#if BUILDFLAG(IS_CHROMEOS_LACROS) || defined(OS_LINUX)
 #define MAYBE_PopupNoRedirect_RedirectCountZero DISABLED_PopupNoRedirect_RedirectCountZero
 #else
 #define MAYBE_PopupNoRedirect_RedirectCountZero PopupNoRedirect_RedirectCountZero
diff --git a/chrome/browser/ui/commander/tab_command_source.cc b/chrome/browser/ui/commander/tab_command_source.cc
index c97fe4d..b881c85 100644
--- a/chrome/browser/ui/commander/tab_command_source.cc
+++ b/chrome/browser/ui/commander/tab_command_source.cc
@@ -5,7 +5,9 @@
 #include "chrome/browser/ui/commander/tab_command_source.h"
 
 #include <numeric>
+#include <string>
 
+#include "base/bind.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/ui/accelerator_utils.h"
@@ -17,6 +19,7 @@
 #include "chrome/browser/ui/tabs/tab_group_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/sessions/content/session_tab_helper.h"
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/models/list_selection_model.h"
@@ -57,6 +60,21 @@
   return excluded_group;
 }
 
+// Returns true only if `browser` is alive, and the contents at `index` match
+// `tab_session_id`.
+bool DoesTabAtIndexMatchSessionId(base::WeakPtr<Browser> browser,
+                                  int index,
+                                  int tab_session_id) {
+  if (!browser.get())
+    return false;
+  if (browser->tab_strip_model()->count() <= index)
+    return false;
+  content::WebContents* contents =
+      browser->tab_strip_model()->GetWebContentsAt(index);
+  DCHECK(contents);
+  return sessions::SessionTabHelper::IdForTab(contents).id() == tab_session_id;
+}
+
 // Commands:
 
 // TODO(lgrey): If this command ships, upstream these to TabStripModel
@@ -85,12 +103,12 @@
   }
 }
 
-bool CanCloseUnpinnedTabs(const TabStripModel* model) {
-  for (int i = 0; i < model->count(); ++i) {
-    if (!model->IsTabPinned(i))
-      return true;
-  }
-  return false;
+bool HasUnpinnedTabs(const TabStripModel* model) {
+  return model->IndexOfFirstNonPinnedTab() < model->count();
+}
+
+bool HasPinnedTabs(const TabStripModel* model) {
+  return model->IndexOfFirstNonPinnedTab() > 0;
 }
 
 void CloseUnpinnedTabs(Browser* browser) {
@@ -139,8 +157,107 @@
   model->AddToNewGroup(std::vector<int>(sel.begin(), sel.end()));
 }
 
+void MuteAllTabs(Browser* browser, bool exclude_active) {
+  TabStripModel* model = browser->tab_strip_model();
+  for (int i = 0; i < model->count(); ++i) {
+    if (exclude_active && i == model->active_index())
+      return;
+    content::WebContents* contents = model->GetWebContentsAt(i);
+    if (contents->IsCurrentlyAudible())
+      contents->SetAudioMuted(true);
+  }
+}
+
+// TODO(lgrey): Precalculate tab strip properties like "has audible tabs", "has
+// pinned tabs" etc. in one iteration at search time.
+bool HasAudibleTabs(const TabStripModel* model) {
+  for (int i = 0; i < model->count(); ++i) {
+    content::WebContents* contents = model->GetWebContentsAt(i);
+    if (contents->IsCurrentlyAudible())
+      return true;
+  }
+  return false;
+}
+
+bool HasMutedTabs(const TabStripModel* model) {
+  for (int i = 0; i < model->count(); ++i) {
+    content::WebContents* contents = model->GetWebContentsAt(i);
+    if (contents->IsAudioMuted())
+      return true;
+  }
+  return false;
+}
+
 // Multiphase commands:
 
+void MuteUnmuteTab(base::WeakPtr<Browser> browser,
+                   int tab_index,
+                   int tab_session_id,
+                   bool mute) {
+  if (!DoesTabAtIndexMatchSessionId(browser, tab_index, tab_session_id))
+    return;
+  browser->tab_strip_model()->GetWebContentsAt(tab_index)->SetAudioMuted(mute);
+}
+
+std::unique_ptr<CommandItem> CreateMuteUnmuteTabItem(const TabMatch& match,
+                                                     Browser* browser,
+                                                     bool mute) {
+  auto item = match.ToCommandItem();
+  item->command = base::BindOnce(&MuteUnmuteTab, browser->AsWeakPtr(),
+                                 match.index, match.session_id, mute);
+  return item;
+}
+
+CommandSource::CommandResults MuteUnmuteTabItemsForTabsMatching(
+    Browser* browser,
+    bool mute,
+    const std::u16string& input) {
+  CommandSource::CommandResults results;
+  TabSearchOptions options;
+  if (mute)
+    options.only_audible = true;
+  else
+    options.only_muted = true;
+  for (auto& match : TabsMatchingInput(browser, input, options)) {
+    results.push_back(CreateMuteUnmuteTabItem(match, browser, mute));
+  }
+  return results;
+}
+
+void TogglePinTab(base::WeakPtr<Browser> browser,
+                  int tab_index,
+                  int tab_session_id,
+                  bool pin) {
+  if (!DoesTabAtIndexMatchSessionId(browser, tab_index, tab_session_id))
+    return;
+  browser->tab_strip_model()->SetTabPinned(tab_index, pin);
+}
+
+std::unique_ptr<CommandItem> CreatePinTabItem(const TabMatch& match,
+                                              Browser* browser,
+                                              bool pin) {
+  auto item = match.ToCommandItem();
+  item->command = base::BindOnce(&TogglePinTab, browser->AsWeakPtr(),
+                                 match.index, match.session_id, pin);
+  return item;
+}
+
+CommandSource::CommandResults TogglePinTabCommandsForTabsMatching(
+    Browser* browser,
+    bool pin,
+    const std::u16string& input) {
+  CommandSource::CommandResults results;
+  TabSearchOptions options;
+  if (pin)
+    options.only_unpinned = true;
+  else
+    options.only_pinned = true;
+  for (auto& match : TabsMatchingInput(browser, input, options)) {
+    results.push_back(CreatePinTabItem(match, browser, pin));
+  }
+  return results;
+}
+
 std::unique_ptr<CommandItem> CreateMoveTabsToWindowItem(
     Browser* source,
     const WindowMatch& match) {
@@ -257,7 +374,7 @@
     }
   }
 
-  if (CanCloseUnpinnedTabs(tab_strip_model)) {
+  if (HasUnpinnedTabs(tab_strip_model)) {
     if (auto item = ItemForTitle(base::ASCIIToUTF16("Close unpinned tabs"),
                                  finder, &ranges)) {
       item->command =
@@ -266,16 +383,6 @@
     }
   }
 
-  bool is_active_pinned =
-      tab_strip_model->IsTabPinned(tab_strip_model->active_index());
-  std::u16string active_title = is_active_pinned
-                                    ? base::ASCIIToUTF16("Unpin tab")
-                                    : base::ASCIIToUTF16("Pin tab");
-  if (auto item = ItemForTitle(active_title, finder, &ranges)) {
-    item->command = base::BindOnce(chrome::PinTab, base::Unretained(browser));
-    results.push_back(std::move(item));
-  }
-
   // TODO(https://crbug.com/1181879): This should handle all selected tabs.
   if (chrome::CanMoveActiveTabToNewWindow(browser)) {
     if (auto item =
@@ -321,6 +428,58 @@
                             base::Unretained(browser)));
     results.push_back(std::move(item));
   }
+  if (auto item = ItemForTitle(u"Mute all tabs", finder, &ranges)) {
+    item->command =
+        base::BindOnce(&MuteAllTabs, base::Unretained(browser), false);
+    results.push_back(std::move(item));
+  }
+
+  if (auto item = ItemForTitle(u"Mute other tabs", finder, &ranges)) {
+    item->command =
+        base::BindOnce(&MuteAllTabs, base::Unretained(browser), false);
+    results.push_back(std::move(item));
+  }
+
+  if (HasAudibleTabs(tab_strip_model)) {
+    if (auto item = ItemForTitle(u"Mute tab...", finder, &ranges)) {
+      item->command =
+          std::make_pair(u"Mute tab...",
+                         base::BindRepeating(&MuteUnmuteTabItemsForTabsMatching,
+                                             base::Unretained(browser), true));
+      results.push_back(std::move(item));
+    }
+  }
+
+  if (HasMutedTabs(tab_strip_model)) {
+    if (auto item = ItemForTitle(u"Unmute tab...", finder, &ranges)) {
+      item->command =
+          std::make_pair(u"Unmute tab...",
+                         base::BindRepeating(&MuteUnmuteTabItemsForTabsMatching,
+                                             base::Unretained(browser), false));
+      results.push_back(std::move(item));
+    }
+  }
+
+  if (HasUnpinnedTabs(tab_strip_model)) {
+    if (auto item = ItemForTitle(u"Pin tab...", finder, &ranges)) {
+      item->command = std::make_pair(
+          u"Pin tab...",
+          base::BindRepeating(&TogglePinTabCommandsForTabsMatching,
+                              base::Unretained(browser), true));
+      results.push_back((std::move(item)));
+    }
+  }
+
+  if (HasPinnedTabs(tab_strip_model)) {
+    if (auto item = ItemForTitle(u"Unpin tab...", finder, &ranges)) {
+      item->command = std::make_pair(
+          u"Unpin tab...",
+          base::BindRepeating(&TogglePinTabCommandsForTabsMatching,
+                              base::Unretained(browser), false));
+      results.push_back((std::move(item)));
+    }
+  }
+
   return results;
 }
 
diff --git a/chrome/browser/ui/extensions/extension_action_view_controller_unittest.cc b/chrome/browser/ui/extensions/extension_action_view_controller_unittest.cc
index 4128f20..d66dc34 100644
--- a/chrome/browser/ui/extensions/extension_action_view_controller_unittest.cc
+++ b/chrome/browser/ui/extensions/extension_action_view_controller_unittest.cc
@@ -40,6 +40,8 @@
 #include "extensions/test/test_extension_dir.h"
 #include "ui/base/l10n/l10n_util.h"
 
+using extensions::mojom::ManifestLocation;
+
 class ExtensionActionViewControllerUnitTest : public BrowserWithTestWindowTest {
  public:
   ExtensionActionViewControllerUnitTest() = default;
@@ -105,7 +107,7 @@
     scoped_refptr<const extensions::Extension> extension =
         extensions::ExtensionBuilder(name)
             .SetAction(action_type)
-            .SetLocation(extensions::Manifest::INTERNAL)
+            .SetLocation(ManifestLocation::kInternal)
             .Build();
     extension_service()->AddExtension(extension.get());
     return extension;
@@ -166,7 +168,7 @@
   scoped_refptr<const extensions::Extension> extension =
       extensions::ExtensionBuilder("browser action")
           .SetAction(extensions::ExtensionBuilder::ActionType::BROWSER_ACTION)
-          .SetLocation(extensions::Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .AddPermission("https://www.google.com/*")
           .Build();
 
@@ -217,7 +219,7 @@
   scoped_refptr<const extensions::Extension> extension =
       extensions::ExtensionBuilder("page action")
           .SetAction(extensions::ExtensionBuilder::ActionType::PAGE_ACTION)
-          .SetLocation(extensions::Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .AddPermission("https://www.google.com/*")
           .Build();
 
@@ -258,7 +260,7 @@
 TEST_F(ExtensionActionViewControllerUnitTest, OnlyHostPermissionsAppearance) {
   scoped_refptr<const extensions::Extension> extension =
       extensions::ExtensionBuilder("just hosts")
-          .SetLocation(extensions::Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .AddPermission("https://www.google.com/*")
           .Build();
 
@@ -530,7 +532,7 @@
     PermissionType permission_type) {
   extensions::ExtensionBuilder builder("extension");
   builder.SetAction(extensions::ExtensionBuilder::ActionType::BROWSER_ACTION)
-      .SetLocation(extensions::Manifest::INTERNAL);
+      .SetLocation(ManifestLocation::kInternal);
   constexpr char kHostGoogle[] = "https://www.google.com/*";
   switch (permission_type) {
     case PermissionType::kScriptableHost: {
@@ -578,7 +580,7 @@
   scoped_refptr<const extensions::Extension> extension =
       extensions::ExtensionBuilder("extension name")
           .SetAction(extensions::ExtensionBuilder::ActionType::BROWSER_ACTION)
-          .SetLocation(extensions::Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .AddPermission("https://www.google.com/*")
           .Build();
   extension_service()->GrantPermissions(extension.get());
diff --git a/chrome/browser/ui/extensions/extension_message_bubble_browsertest.cc b/chrome/browser/ui/extensions/extension_message_bubble_browsertest.cc
index 73f90d8..aa15fbd 100644
--- a/chrome/browser/ui/extensions/extension_message_bubble_browsertest.cc
+++ b/chrome/browser/ui/extensions/extension_message_bubble_browsertest.cc
@@ -114,7 +114,7 @@
   scoped_refptr<const extensions::Extension> action_extension =
       extensions::ExtensionBuilder("action_extension")
           .SetAction(extensions::ExtensionBuilder::ActionType::BROWSER_ACTION)
-          .SetLocation(extensions::Manifest::UNPACKED)
+          .SetLocation(extensions::mojom::ManifestLocation::kUnpacked)
           .Build();
   extension_service()->AddExtension(action_extension.get());
 
@@ -131,7 +131,7 @@
 void ExtensionMessageBubbleBrowserTest::TestBubbleAnchoredToAppMenu() {
   scoped_refptr<const extensions::Extension> no_action_extension =
       extensions::ExtensionBuilder("no_action_extension")
-          .SetLocation(extensions::Manifest::INTERNAL)
+          .SetLocation(extensions::mojom::ManifestLocation::kInternal)
           .Build();
   extension_service()->AddExtension(no_action_extension.get());
   // The 'suspicious extension' bubble warns the user about extensions that are
@@ -154,14 +154,14 @@
     TestBubbleAnchoredToAppMenuWithOtherAction() {
   scoped_refptr<const extensions::Extension> no_action_extension =
       extensions::ExtensionBuilder("no_action_extension")
-          .SetLocation(extensions::Manifest::INTERNAL)
+          .SetLocation(extensions::mojom::ManifestLocation::kInternal)
           .Build();
   extension_service()->AddExtension(no_action_extension.get());
 
   scoped_refptr<const extensions::Extension> action_extension =
       extensions::ExtensionBuilder("action_extension")
           .SetAction(extensions::ExtensionBuilder::ActionType::BROWSER_ACTION)
-          .SetLocation(extensions::Manifest::INTERNAL)
+          .SetLocation(extensions::mojom::ManifestLocation::kInternal)
           .Build();
   extension_service()->AddExtension(action_extension.get());
 
@@ -245,7 +245,7 @@
   scoped_refptr<const extensions::Extension> action_extension =
       extensions::ExtensionBuilder("action_extension")
           .SetAction(extensions::ExtensionBuilder::ActionType::BROWSER_ACTION)
-          .SetLocation(extensions::Manifest::UNPACKED)
+          .SetLocation(extensions::mojom::ManifestLocation::kUnpacked)
           .Build();
   extension_service()->AddExtension(action_extension.get());
 
@@ -384,7 +384,7 @@
   CheckBubbleIsNotPresent(browser(), false, false);
   scoped_refptr<const extensions::Extension> no_action_extension =
       extensions::ExtensionBuilder("no_action_extension")
-          .SetLocation(extensions::Manifest::INTERNAL)
+          .SetLocation(extensions::mojom::ManifestLocation::kInternal)
           .Build();
   extension_service()->AddExtension(no_action_extension.get());
 
diff --git a/chrome/browser/ui/extensions/extension_settings_overridden_dialog_unittest.cc b/chrome/browser/ui/extensions/extension_settings_overridden_dialog_unittest.cc
index d47501b..be6e17d 100644
--- a/chrome/browser/ui/extensions/extension_settings_overridden_dialog_unittest.cc
+++ b/chrome/browser/ui/extensions/extension_settings_overridden_dialog_unittest.cc
@@ -48,8 +48,8 @@
   // Adds a new extension with the given |name| and |location| to the profile.
   const extensions::Extension* AddExtension(
       const char* name = "alpha",
-      extensions::Manifest::Location location =
-          extensions::Manifest::INTERNAL) {
+      extensions::mojom::ManifestLocation location =
+          extensions::mojom::ManifestLocation::kInternal) {
     scoped_refptr<const extensions::Extension> extension =
         extensions::ExtensionBuilder(name).SetLocation(location).Build();
     service()->AddExtension(extension.get());
@@ -106,7 +106,8 @@
 TEST_F(ExtensionSettingsOverriddenDialogUnitTest,
        WontShowForAnExtensionThatCantBeDisabled) {
   const extensions::Extension* policy_extension = AddExtension(
-      "policy installed", extensions::Manifest::EXTERNAL_POLICY_DOWNLOAD);
+      "policy installed",
+      extensions::mojom::ManifestLocation::kExternalPolicyDownload);
 
   ExtensionSettingsOverriddenDialog controller(
       CreateTestDialogParams(policy_extension->id()), profile());
diff --git a/chrome/browser/ui/extensions/settings_overridden_params_providers_unittest.cc b/chrome/browser/ui/extensions/settings_overridden_params_providers_unittest.cc
index 96111113f..d6eb602f8 100644
--- a/chrome/browser/ui/extensions/settings_overridden_params_providers_unittest.cc
+++ b/chrome/browser/ui/extensions/settings_overridden_params_providers_unittest.cc
@@ -47,7 +47,7 @@
         extensions::DictionaryBuilder().Set("newtab", "newtab.html").Build();
     scoped_refptr<const extensions::Extension> extension =
         extensions::ExtensionBuilder(name)
-            .SetLocation(extensions::Manifest::INTERNAL)
+            .SetLocation(extensions::mojom::ManifestLocation::kInternal)
             .SetManifestKey("chrome_url_overrides",
                             std::move(chrome_url_overrides))
             .Build();
diff --git a/chrome/browser/ui/global_error/global_error_browsertest.cc b/chrome/browser/ui/global_error/global_error_browsertest.cc
index 46c8fb2..efbcf25 100644
--- a/chrome/browser/ui/global_error/global_error_browsertest.cc
+++ b/chrome/browser/ui/global_error/global_error_browsertest.cc
@@ -131,7 +131,7 @@
 
   extensions::ExtensionBuilder builder("Browser Action");
   builder.SetAction(extensions::ExtensionBuilder::ActionType::BROWSER_ACTION);
-  builder.SetLocation(extensions::Manifest::INTERNAL);
+  builder.SetLocation(extensions::mojom::ManifestLocation::kInternal);
   scoped_refptr<const extensions::Extension> test_extension = builder.Build();
   extension_service->AddExtension(test_extension.get());
 
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc b/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc
index f00d4e79..eef2c20 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc
@@ -195,7 +195,7 @@
   scoped_refptr<const extensions::Extension> extension =
       extensions::ExtensionBuilder(name)
           .SetAction(action_type)
-          .SetLocation(extensions::Manifest::INTERNAL)
+          .SetLocation(extensions::mojom::ManifestLocation::kInternal)
           .Build();
   extensions::ExtensionSystem::Get(profile())->extension_service()->
       AddExtension(extension.get());
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc b/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc
index a7d1a2dd..e9ada84 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc
@@ -55,6 +55,7 @@
 
 namespace {
 
+using extensions::mojom::ManifestLocation;
 using ActionType = extensions::ExtensionBuilder::ActionType;
 
 // A simple observer that tracks the number of times certain events occur.
@@ -287,14 +288,14 @@
 testing::AssertionResult ToolbarActionsModelUnitTest::AddActionExtensions() {
   browser_action_extension_ = extensions::ExtensionBuilder("browser_action")
                                   .SetAction(ActionType::BROWSER_ACTION)
-                                  .SetLocation(extensions::Manifest::INTERNAL)
+                                  .SetLocation(ManifestLocation::kInternal)
                                   .Build();
   page_action_extension_ = extensions::ExtensionBuilder("page_action")
                                .SetAction(ActionType::PAGE_ACTION)
-                               .SetLocation(extensions::Manifest::INTERNAL)
+                               .SetLocation(ManifestLocation::kInternal)
                                .Build();
   no_action_extension_ = extensions::ExtensionBuilder("no_action")
-                             .SetLocation(extensions::Manifest::INTERNAL)
+                             .SetLocation(ManifestLocation::kInternal)
                              .Build();
 
   extensions::ExtensionList extensions;
@@ -309,15 +310,15 @@
 ToolbarActionsModelUnitTest::AddBrowserActionExtensions() {
   browser_action_a_ = extensions::ExtensionBuilder("browser_actionA")
                           .SetAction(ActionType::BROWSER_ACTION)
-                          .SetLocation(extensions::Manifest::INTERNAL)
+                          .SetLocation(ManifestLocation::kInternal)
                           .Build();
   browser_action_b_ = extensions::ExtensionBuilder("browser_actionB")
                           .SetAction(ActionType::BROWSER_ACTION)
-                          .SetLocation(extensions::Manifest::INTERNAL)
+                          .SetLocation(ManifestLocation::kInternal)
                           .Build();
   browser_action_c_ = extensions::ExtensionBuilder("browser_actionC")
                           .SetAction(ActionType::BROWSER_ACTION)
-                          .SetLocation(extensions::Manifest::INTERNAL)
+                          .SetLocation(ManifestLocation::kInternal)
                           .Build();
 
   extensions::ExtensionList extensions;
@@ -368,7 +369,7 @@
   scoped_refptr<const extensions::Extension> extension =
       extensions::ExtensionBuilder("browser_action")
           .SetAction(ActionType::BROWSER_ACTION)
-          .SetLocation(extensions::Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .Build();
   ASSERT_TRUE(AddExtension(extension));
 
@@ -566,22 +567,22 @@
   scoped_refptr<const extensions::Extension> extension_a =
       extensions::ExtensionBuilder("a")
           .SetAction(ActionType::BROWSER_ACTION)
-          .SetLocation(extensions::Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .Build();
   scoped_refptr<const extensions::Extension> extension_b =
       extensions::ExtensionBuilder("b")
           .SetAction(ActionType::BROWSER_ACTION)
-          .SetLocation(extensions::Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .Build();
   scoped_refptr<const extensions::Extension> extension_c =
       extensions::ExtensionBuilder("c")
           .SetAction(ActionType::BROWSER_ACTION)
-          .SetLocation(extensions::Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .Build();
   scoped_refptr<const extensions::Extension> extension_d =
       extensions::ExtensionBuilder("d")
           .SetAction(ActionType::BROWSER_ACTION)
-          .SetLocation(extensions::Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .Build();
 
   // We should start off without any actions.
@@ -873,7 +874,7 @@
       extensions::ExtensionBuilder()
           .SetManifest(default_installed_manifest.Build())
           .SetID(crx_file::id_util::GenerateId("default"))
-          .SetLocation(extensions::Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .AddFlags(extensions::Extension::WAS_INSTALLED_BY_DEFAULT)
           .Build();
   EXPECT_TRUE(AddExtension(default_installed_extension.get()));
@@ -883,7 +884,7 @@
   // Component extensions shouldn't be given an icon.
   scoped_refptr<const extensions::Extension> component_extension_no_action =
       extensions::ExtensionBuilder("component ext no action")
-          .SetLocation(extensions::Manifest::COMPONENT)
+          .SetLocation(ManifestLocation::kComponent)
           .Build();
   EXPECT_TRUE(AddExtension(component_extension_no_action.get()));
   EXPECT_EQ(3u, num_actions());
@@ -893,7 +894,7 @@
   // have an icon.
   scoped_refptr<const extensions::Extension> internal_extension_no_action =
       extensions::ExtensionBuilder("internal ext no action")
-          .SetLocation(extensions::Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .Build();
   EXPECT_TRUE(AddExtension(internal_extension_no_action.get()));
   EXPECT_EQ(4u, num_actions());
@@ -1227,7 +1228,7 @@
 
   scoped_refptr<const extensions::Extension> extension =
       extensions::ExtensionBuilder("a")
-          .SetLocation(extensions::Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .MergeManifest(extensions::DictionaryBuilder()
                              .Set("converted_from_user_script", true)
                              .Build())
@@ -1484,7 +1485,7 @@
   scoped_refptr<const extensions::Extension> extension =
       extensions::ExtensionBuilder("extension")
           .SetAction(ActionType::BROWSER_ACTION)
-          .SetLocation(extensions::Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .Build();
 
   // Add and pin an extension.
@@ -1534,7 +1535,7 @@
   scoped_refptr<const extensions::Extension> extension =
       extensions::ExtensionBuilder("test")
           .SetAction(ActionType::BROWSER_ACTION)
-          .SetLocation(extensions::Manifest::INTERNAL)
+          .SetLocation(ManifestLocation::kInternal)
           .SetID(extension_id)
           .Build();
 
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.cc b/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.cc
index 3141a3f..63b4ac9d8 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.cc
@@ -186,9 +186,8 @@
 bool BookmarkMenuDelegate::ShouldExecuteCommandWithoutClosingMenu(
     int id,
     const ui::Event& event) {
-  if ((event.flags() & ui::EF_LEFT_MOUSE_BUTTON) &&
-      ui::DispositionFromEventFlags(event.flags()) ==
-          WindowOpenDisposition::NEW_BACKGROUND_TAB) {
+  if (ui::DispositionFromEventFlags(event.flags()) ==
+      WindowOpenDisposition::NEW_BACKGROUND_TAB) {
     DCHECK(menu_id_to_node_map_.find(id) != menu_id_to_node_map_.end());
     const BookmarkNode* node = menu_id_to_node_map_[id];
     // Close the menu before opening a folder since this may pop up a dialog
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
index 53166e6..0a89325 100644
--- a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
@@ -47,6 +47,10 @@
 #include "ui/aura/window_tree_host.h"
 #endif
 
+#if defined(OS_CHROMEOS)
+#include "ash/public/cpp/projector/projector_controller.h"
+#endif
+
 using content::DesktopMediaID;
 
 enum class DesktopMediaPickerDialogView::DialogSource : int {
@@ -178,6 +182,35 @@
   }
 }
 
+bool IsProjectorEnabled() {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  if (!ash::ProjectorController::Get())
+    return false;
+
+  // TODO(https://crbug.com/1184881): If there is a session ongoing we should
+  // disable the checkbox.
+  return ash::ProjectorController::Get()->IsEligible();
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+  return false;
+}
+
+void SetProjectorToolsVisible(bool is_visible) {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  ash::ProjectorController::Get()->SetProjectorToolsVisible(is_visible);
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+}
+
+void ProjectorCheckboxPressed(views::Checkbox* presenter_checkbox) {
+  DCHECK(presenter_checkbox);
+  SetProjectorToolsVisible(presenter_checkbox->GetChecked());
+}
+
+void StartProjectorSession() {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  ash::ProjectorController::Get()->StartProjectorSession();
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+}
+
 }  // namespace
 
 DesktopMediaPickerDialogView::DesktopMediaPickerDialogView(
@@ -190,12 +223,38 @@
                  l10n_util::GetStringUTF16(IDS_DESKTOP_MEDIA_PICKER_SHARE));
   const ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
 
-  std::unique_ptr<views::Checkbox> audio_share_checkbox;
-  if (params.request_audio) {
-    audio_share_checkbox = std::make_unique<views::Checkbox>(
-        l10n_util::GetStringUTF16(IDS_DESKTOP_MEDIA_PICKER_AUDIO_SHARE));
-    audio_share_checkbox->SetChecked(params.approve_audio_by_default);
-    audio_share_checkbox_ = SetExtraView(std::move(audio_share_checkbox));
+  std::unique_ptr<views::View> extra_views_container;
+  if (params.request_audio || IsProjectorEnabled()) {
+    extra_views_container = std::make_unique<views::View>();
+    // A simple horizontal layout manager.
+    extra_views_container->SetLayoutManager(
+        std::make_unique<views::BoxLayout>());
+
+    if (params.request_audio) {
+      std::unique_ptr<views::Checkbox> audio_share_checkbox =
+          std::make_unique<views::Checkbox>(
+              l10n_util::GetStringUTF16(IDS_DESKTOP_MEDIA_PICKER_AUDIO_SHARE));
+      audio_share_checkbox->SetChecked(params.approve_audio_by_default);
+      audio_share_checkbox_ =
+          extra_views_container->AddChildView(std::move(audio_share_checkbox));
+    }
+
+    if (IsProjectorEnabled()) {
+      std::unique_ptr<views::Checkbox> presenter_tools_checkbox =
+          std::make_unique<views::Checkbox>(
+              l10n_util::GetStringUTF16(IDS_DESKTOP_MEDIA_PRESENTER_TOOLS));
+
+      presenter_tools_checkbox_ = extra_views_container->AddChildView(
+          std::move(presenter_tools_checkbox));
+      presenter_tools_checked_subscription_ =
+          presenter_tools_checkbox_->AddCheckedChangedCallback(
+              base::BindRepeating(&ProjectorCheckboxPressed,
+                                  presenter_tools_checkbox_));
+      presenter_tools_checkbox_->SetChecked(true);
+    }
+
+    extra_views_container_ = SetExtraView(std::move(extra_views_container));
+    extra_views_container_->SetVisible(true);
   }
 
   SetLayoutManager(std::make_unique<views::BoxLayout>(
@@ -560,12 +619,24 @@
   if (parent_)
     parent_->NotifyDialogResult(source);
 
+  bool notify_projector_session_start =
+      presenter_tools_checkbox_ && presenter_tools_checkbox_->GetChecked() &&
+      IsProjectorEnabled();
+  if (notify_projector_session_start) {
+    StartProjectorSession();
+  }
+
   // Return true to close the window.
   return true;
 }
 
 bool DesktopMediaPickerDialogView::Cancel() {
   RecordUmaCancellation(dialog_source_);
+  bool hide_projector_tools =
+      presenter_tools_checkbox_ && presenter_tools_checkbox_->GetChecked();
+  // If the user cancels while the projector tools are visible, hide them.
+  if (hide_projector_tools)
+    SetProjectorToolsVisible(false);
   return views::DialogDelegateView::Cancel();
 }
 
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.h b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.h
index e50d916..3c03cf1e 100644
--- a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.h
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_DESKTOP_CAPTURE_DESKTOP_MEDIA_PICKER_VIEWS_H_
 #define CHROME_BROWSER_UI_VIEWS_DESKTOP_CAPTURE_DESKTOP_MEDIA_PICKER_VIEWS_H_
 
+#include "base/callback_list.h"
 #include "build/build_config.h"
 #include "chrome/browser/media/webrtc/desktop_media_picker.h"
 #include "chrome/browser/ui/views/desktop_capture/desktop_media_list_controller.h"
@@ -84,8 +85,16 @@
 
   views::Label* description_label_ = nullptr;
 
+  views::Checkbox* presenter_tools_checkbox_ = nullptr;
+
+  base::CallbackListSubscription presenter_tools_checked_subscription_;
+
   views::Checkbox* audio_share_checkbox_ = nullptr;
 
+  // Contains |presenter_tools_checkbox_| and |audio_share_checkbox_| if
+  // present.
+  views::View* extra_views_container_ = nullptr;
+
   views::TabbedPane* tabbed_pane_ = nullptr;
   std::vector<std::unique_ptr<DesktopMediaListController>> list_controllers_;
   std::vector<DesktopMediaList::Type> source_types_;
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_test_api.cc b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_test_api.cc
index 9f7664ec..c6a37efab 100644
--- a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_test_api.cc
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_test_api.cc
@@ -122,6 +122,10 @@
   return picker_->dialog_->audio_share_checkbox_;
 }
 
+views::Checkbox* DesktopMediaPickerViewsTestApi::GetPresenterToolsCheckbox() {
+  return picker_->dialog_->presenter_tools_checkbox_;
+}
+
 const views::View* DesktopMediaPickerViewsTestApi::GetSourceAtIndex(
     size_t index) const {
   views::View* list = picker_->dialog_->GetSelectedController()->view_;
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_test_api.h b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_test_api.h
index 1983125..e0abb87 100644
--- a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_test_api.h
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_test_api.h
@@ -36,6 +36,7 @@
   void PressKeyOnSourceAtIndex(size_t index, const ui::KeyEvent& event);
   void SelectTabForSourceType(DesktopMediaList::Type source_type);
   views::Checkbox* GetAudioShareCheckbox();
+  views::Checkbox* GetPresenterToolsCheckbox();
 
   bool HasSourceAtIndex(size_t index) const;
   void FocusSourceAtIndex(size_t index, bool select = true);
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_unittest.cc b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_unittest.cc
index 0e05d770..16986063 100644
--- a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_unittest.cc
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_unittest.cc
@@ -7,6 +7,7 @@
 #include <map>
 #include <string>
 #include <utility>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -24,6 +25,7 @@
 #include "chrome/test/views/chrome_test_views_delegate.h"
 #include "components/web_modal/test_web_contents_modal_dialog_host.h"
 #include "content/public/test/browser_task_environment.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/ui_base_switches.h"
 #include "ui/events/event_utils.h"
@@ -36,6 +38,10 @@
 #include "ui/views/widget/widget.h"
 #include "ui/views/window/dialog_delegate.h"
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/public/cpp/projector/projector_controller.h"
+#endif
+
 using content::DesktopMediaID;
 
 namespace views {
@@ -79,6 +85,19 @@
         switches::kDisableModalAnimations);
 #endif
     DesktopMediaPickerManager::Get()->AddObserver(&observer_);
+    CreatePickerViews();
+  }
+
+  void TearDown() override {
+    if (GetPickerDialogView())
+      GetPickerDialogView()->GetWidget()->CloseNow();
+    widget_destroyed_waiter_->Wait();
+    DesktopMediaPickerManager::Get()->RemoveObserver(&observer_);
+  }
+
+  void CreatePickerViews() {
+    widget_destroyed_waiter_.reset();
+    picker_views_.reset();
 
     picker_views_ = std::make_unique<DesktopMediaPickerViews>();
     test_api_.set_picker(picker_views_.get());
@@ -109,13 +128,6 @@
             waiter.WaitIfNeededAndGet());
   }
 
-  void TearDown() override {
-    if (GetPickerDialogView())
-      GetPickerDialogView()->GetWidget()->CloseNow();
-    widget_destroyed_waiter_->Wait();
-    DesktopMediaPickerManager::Get()->RemoveObserver(&observer_);
-  }
-
   DesktopMediaPickerDialogView* GetPickerDialogView() const {
     return picker_views_->GetDialogViewForTesting();
   }
@@ -375,6 +387,80 @@
   EXPECT_EQ(kFakeId, WaitForPickerDone());
 }
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+
+class ProjectorControllerMock : public ash::ProjectorController {
+ public:
+  ProjectorControllerMock() = default;
+  ~ProjectorControllerMock() = default;
+  MOCK_METHOD1(SetClient, void(ash::ProjectorClient*));
+  MOCK_METHOD1(OnSpeechRecognitionAvailable, void(bool));
+  MOCK_METHOD5(OnTranscription,
+               void(const std::u16string&,
+                    base::TimeDelta,
+                    base::TimeDelta,
+                    const std::vector<base::TimeDelta>&,
+                    bool));
+  MOCK_METHOD1(SetProjectorToolsVisible, void(bool));
+  MOCK_METHOD0(StartProjectorSession, void());
+  MOCK_CONST_METHOD0(IsEligible, bool());
+};
+
+TEST_F(DesktopMediaPickerViewsTest, ProjectorIneligible) {
+  ProjectorControllerMock mock;
+  ON_CALL(mock, IsEligible).WillByDefault(testing::Return(false));
+  EXPECT_EQ(test_api_.GetPresenterToolsCheckbox(), nullptr);
+}
+
+TEST_F(DesktopMediaPickerViewsTest, ProjectorEligible) {
+  ProjectorControllerMock mock;
+  ON_CALL(mock, IsEligible).WillByDefault(testing::Return(true));
+
+  EXPECT_CALL(mock, SetProjectorToolsVisible(true)).Times(1);
+  CreatePickerViews();
+
+  test_api_.SelectTabForSourceType(DesktopMediaList::Type::kScreen);
+  EXPECT_TRUE(test_api_.GetPresenterToolsCheckbox()->GetVisible());
+
+  test_api_.SelectTabForSourceType(DesktopMediaList::Type::kWindow);
+  EXPECT_TRUE(test_api_.GetPresenterToolsCheckbox()->GetVisible());
+
+  test_api_.SelectTabForSourceType(DesktopMediaList::Type::kWebContents);
+  EXPECT_TRUE(test_api_.GetPresenterToolsCheckbox()->GetVisible());
+
+  // Button is visible but unchecked.
+  test_api_.GetPresenterToolsCheckbox()->SetChecked(true);
+
+  // When the dialog is cancelled, we expect that ProjectorController to hide
+  // the toolbar.
+  EXPECT_CALL(mock, SetProjectorToolsVisible(false)).Times(1);
+
+  // Cancel and dismiss the Dialog
+  GetPickerDialogView()->Cancel();
+}
+
+TEST_F(DesktopMediaPickerViewsTest, ProjectorStartSession) {
+  constexpr DesktopMediaID kOriginId(DesktopMediaID::TYPE_WEB_CONTENTS, 222);
+
+  ProjectorControllerMock mock;
+  ON_CALL(mock, IsEligible).WillByDefault(testing::Return(true));
+  CreatePickerViews();
+
+  media_lists_[DesktopMediaList::Type::kWebContents]->AddSourceByFullMediaID(
+      kOriginId);
+
+  test_api_.SelectTabForSourceType(DesktopMediaList::Type::kWebContents);
+  test_api_.GetPresenterToolsCheckbox()->SetChecked(true);
+  test_api_.FocusSourceAtIndex(0);
+
+  EXPECT_CALL(mock, StartProjectorSession()).Times(1);
+
+  GetPickerDialogView()->AcceptDialog();
+  WaitForPickerDone();
+}
+
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
 // Creates a single pane DesktopMediaPickerViews that only has a tab list.
 class DesktopMediaPickerViewsSingleTabPaneTest
     : public DesktopMediaPickerViewsTest {
diff --git a/chrome/browser/ui/views/extensions/extension_dialog.cc b/chrome/browser/ui/views/extensions/extension_dialog.cc
index fe91fe79..3329ac7 100644
--- a/chrome/browser/ui/views/extensions/extension_dialog.cc
+++ b/chrome/browser/ui/views/extensions/extension_dialog.cc
@@ -114,35 +114,33 @@
   return extension_view_;
 }
 
-void ExtensionDialog::Observe(int type,
-                              const content::NotificationSource& source,
-                              const content::NotificationDetails& details) {
-  switch (type) {
-    case extensions::NOTIFICATION_EXTENSION_HOST_DID_STOP_FIRST_LOAD:
-      // Avoid potential overdraw by removing the temporary background after
-      // the extension finishes loading.
-      extension_view_->SetBackground(nullptr);
-      // The render view is created during the LoadURL(), so we should
-      // set the focus to the view if nobody else takes the focus.
-      if (content::Details<extensions::ExtensionHost>(host()) == details)
-        MaybeFocusRenderer();
-      break;
-    case extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE:
-      // If we aren't the host of the popup, then disregard the notification.
-      if (content::Details<extensions::ExtensionHost>(host()) != details)
-        return;
-      GetWidget()->Close();
-      break;
-    case extensions::NOTIFICATION_EXTENSION_PROCESS_TERMINATED:
-      if (content::Details<extensions::ExtensionHost>(host()) != details)
-        return;
-      if (observer_)
-        observer_->ExtensionTerminated(this);
-      break;
-    default:
-      NOTREACHED() << "Received unexpected notification";
-      break;
-  }
+void ExtensionDialog::OnExtensionHostDidStopFirstLoad(
+    const extensions::ExtensionHost* host) {
+  DCHECK_EQ(host, host_.get());
+  // Avoid potential overdraw by removing the temporary background after
+  // the extension finishes loading.
+  extension_view_->SetBackground(nullptr);
+  // The render view is created during the LoadURL(), so we should
+  // set the focus to the view if nobody else takes the focus.
+  MaybeFocusRenderer();
+}
+
+void ExtensionDialog::OnExtensionHostShouldClose(
+    extensions::ExtensionHost* host) {
+  DCHECK_EQ(host, host_.get());
+  GetWidget()->Close();
+}
+
+void ExtensionDialog::OnExtensionProcessTerminated(
+    const extensions::Extension* extension) {
+  if (extension == host_->extension() && observer_)
+    observer_->ExtensionTerminated(this);
+}
+
+void ExtensionDialog::OnProcessManagerShutdown(
+    extensions::ProcessManager* manager) {
+  DCHECK(process_manager_observation_.IsObservingSource(manager));
+  process_manager_observation_.Reset();
 }
 
 ExtensionDialog::~ExtensionDialog() = default;
@@ -158,17 +156,10 @@
 
   AddRef();  // Balanced in DeleteDelegate();
 
-  const content::Source<content::BrowserContext> source =
-      host_->browser_context();
-  registrar_.Add(this,
-                 extensions::NOTIFICATION_EXTENSION_HOST_DID_STOP_FIRST_LOAD,
-                 source);
-  // Listen for the containing view calling window.close();
-  registrar_.Add(
-      this, extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE, source);
-  // Listen for a crash or other termination of the extension process.
-  registrar_.Add(this, extensions::NOTIFICATION_EXTENSION_PROCESS_TERMINATED,
-                 source);
+  extension_host_observation_.Observe(host_.get());
+  process_manager_observation_.Observe(
+      extensions::ProcessManager::Get(host_->browser_context()));
+
   chrome::RecordDialogCreation(chrome::DialogIdentifier::EXTENSION);
 
   SetModalType(ui::MODAL_TYPE_WINDOW);
diff --git a/chrome/browser/ui/views/extensions/extension_dialog.h b/chrome/browser/ui/views/extensions/extension_dialog.h
index 594e6bce..df46fc3 100644
--- a/chrome/browser/ui/views/extensions/extension_dialog.h
+++ b/chrome/browser/ui/views/extensions/extension_dialog.h
@@ -12,9 +12,12 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/optional.h"
+#include "base/scoped_observation.h"
 #include "build/chromeos_buildflags.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
+#include "extensions/browser/extension_host.h"
+#include "extensions/browser/extension_host_observer.h"
+#include "extensions/browser/process_manager.h"
+#include "extensions/browser/process_manager_observer.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/views/window/dialog_delegate.h"
@@ -36,7 +39,8 @@
 // Dialog is automatically centered in the owning window and has fixed size.
 // For example, used by the Chrome OS file browser.
 class ExtensionDialog : public views::DialogDelegate,
-                        public content::NotificationObserver,
+                        public extensions::ExtensionHostObserver,
+                        public extensions::ProcessManagerObserver,
                         public base::RefCounted<ExtensionDialog> {
  public:
   struct InitParams {
@@ -95,10 +99,15 @@
   const views::Widget* GetWidget() const override;
   views::View* GetContentsView() override;
 
-  // content::NotificationObserver:
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
+  // extensions::ExtensionHostObserver:
+  void OnExtensionHostDidStopFirstLoad(
+      const extensions::ExtensionHost* host) override;
+  void OnExtensionHostShouldClose(extensions::ExtensionHost* host) override;
+
+  // extensions::ProcessManagerObserver:
+  void OnExtensionProcessTerminated(
+      const extensions::Extension* extension) override;
+  void OnProcessManagerShutdown(extensions::ProcessManager* manager) override;
 
  protected:
   ~ExtensionDialog() override;
@@ -120,7 +129,13 @@
 
   ExtensionViewViews* extension_view_ = nullptr;
 
-  content::NotificationRegistrar registrar_;
+  base::ScopedObservation<extensions::ExtensionHost,
+                          extensions::ExtensionHostObserver>
+      extension_host_observation_{this};
+
+  base::ScopedObservation<extensions::ProcessManager,
+                          extensions::ProcessManagerObserver>
+      process_manager_observation_{this};
 
   // The observer of this popup.
   ExtensionDialogObserver* observer_;
diff --git a/chrome/browser/ui/views/extensions/extension_installed_bubble_view_browsertest.cc b/chrome/browser/ui/views/extensions/extension_installed_bubble_view_browsertest.cc
index cef203a..7c174918 100644
--- a/chrome/browser/ui/views/extensions/extension_installed_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/extensions/extension_installed_bubble_view_browsertest.cc
@@ -40,9 +40,9 @@
     }
 
     if (type == "SignInPromo" || type == "NoAction") {
-      builder.SetLocation(extensions::Manifest::INTERNAL);
+      builder.SetLocation(extensions::mojom::ManifestLocation::kInternal);
     } else {
-      builder.SetLocation(extensions::Manifest::COMPONENT);
+      builder.SetLocation(extensions::mojom::ManifestLocation::kComponent);
     }
 
     if (type == "Omnibox") {
diff --git a/chrome/browser/ui/views/location_bar/custom_tab_bar_view_browsertest.cc b/chrome/browser/ui/views/location_bar/custom_tab_bar_view_browsertest.cc
index 5088401c..56d8be3 100644
--- a/chrome/browser/ui/views/location_bar/custom_tab_bar_view_browsertest.cc
+++ b/chrome/browser/ui/views/location_bar/custom_tab_bar_view_browsertest.cc
@@ -256,12 +256,20 @@
 
 // Check the custom tab bar is not instantiated for a popup window.
 IN_PROC_BROWSER_TEST_F(CustomTabBarViewBrowserTest, IsNotCreatedInPopup) {
-  EXPECT_TRUE(NavigateToURL(browser_view_->GetActiveWebContents(),
-                            GURL(url::kAboutBlankURL)));
+#if defined(OS_LINUX)
+  {
+    auto* command_line = base::CommandLine::ForCurrentProcess();
+    if (command_line->HasSwitch(switches::kOzonePlatform) &&
+        command_line->GetSwitchValueASCII(switches::kOzonePlatform) ==
+            "wayland") {
+      // TODO(crbug.com/1179071): Test is flaky on Linux Wayland configuration.
+      GTEST_SKIP() << "Flaky on Linux Wayland";
+    }
+  }
+#endif
 
-  Browser* popup =
-      OpenPopup(browser_view_->GetActiveWebContents(),
-                https_server()->GetURL("app.com", "/ssl/google.html"));
+  Browser* popup = OpenPopup(browser_view_->GetActiveWebContents(),
+                             GURL("http://example.com"));
   EXPECT_TRUE(popup);
 
   BrowserView* popup_view = BrowserView::GetBrowserViewForBrowser(popup);
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index 219716c..3e72988 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -582,13 +582,11 @@
   if (mouse_hovered_ || !GetWidget()->IsMouseEventsEnabled())
     return;
 
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_MAC)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
   // Move the hit test area for hovering up so that it is not overlapped by tab
   // hover cards when they are shown.
   // TODO(crbug.com/978134): Once Linux/CrOS widget transparency is solved,
   // remove that case.
-  // TODO(crbug.com/1187189): Once Mac widget transparency is solved, remove
-  // that case.
   constexpr int kHoverCardOverlap = 6;
   if (event.location().y() >= height() - kHoverCardOverlap)
     return;
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index 8f155c7..3ab1370 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -16,6 +16,7 @@
 #include "base/callback.h"
 #include "base/callback_helpers.h"
 #include "base/command_line.h"
+#include "base/dcheck_is_on.h"
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
 #include "base/optional.h"
@@ -2507,7 +2508,9 @@
 
 // TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
 // complete.
-#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+// Disabling on macOS due to DCHECK crashes; see https://crbug.com/1183043.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) || \
+    (defined(OS_MAC) && DCHECK_IS_ON())
 #define MAYBE_DraggingRightExpandsTabStripSize \
   DISABLED_DraggingRightExpandsTabStripSize
 #else
diff --git a/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view.cc b/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view.cc
index 090b8e2..dbd410d 100644
--- a/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view.cc
+++ b/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view.cc
@@ -42,6 +42,7 @@
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/range/range.h"
 #include "ui/native_theme/native_theme.h"
+#include "ui/views/bubble/bubble_frame_view.h"
 #include "ui/views/controls/button/button.h"
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/label.h"
@@ -68,6 +69,9 @@
   views::Widget* const widget =
       BubbleDialogDelegateView::CreateBubble(tab_group_editor_bubble_view);
   tab_group_editor_bubble_view->set_adjust_if_offscreen(true);
+  tab_group_editor_bubble_view->GetBubbleFrameView()
+      ->SetPreferredArrowAdjustment(
+          views::BubbleFrameView::PreferredArrowAdjustment::kOffset);
   tab_group_editor_bubble_view->SizeToContents();
   widget->Show();
   return widget;
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
index d0b3cdb..786f930 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
@@ -158,6 +158,7 @@
   // not become active. Setting this to false creates the need to explicitly
   // hide the hovercard on press, touch, and keyboard events.
   SetCanActivate(false);
+  set_accept_events(false);
 
   // Set so that the tab hover card is not focus traversable when keyboard
   // navigating through the tab strip.
diff --git a/chrome/browser/ui/views/toolbar/app_menu.cc b/chrome/browser/ui/views/toolbar/app_menu.cc
index c5899cd..211aff0b 100644
--- a/chrome/browser/ui/views/toolbar/app_menu.cc
+++ b/chrome/browser/ui/views/toolbar/app_menu.cc
@@ -1018,9 +1018,12 @@
 
 bool AppMenu::ShouldExecuteCommandWithoutClosingMenu(int command_id,
                                                      const ui::Event& event) {
-  return IsRecentTabsCommand(command_id) && event.IsMouseEvent() &&
-         (ui::DispositionFromEventFlags(event.flags()) ==
-          WindowOpenDisposition::NEW_BACKGROUND_TAB);
+  return (IsRecentTabsCommand(command_id) && event.IsMouseEvent() &&
+          (ui::DispositionFromEventFlags(event.flags()) ==
+           WindowOpenDisposition::NEW_BACKGROUND_TAB)) ||
+         (IsBookmarkCommand(command_id) &&
+          bookmark_menu_delegate_->ShouldExecuteCommandWithoutClosingMenu(
+              command_id, event));
 }
 
 void AppMenu::BookmarkModelChanged() {
diff --git a/chrome/browser/ui/web_applications/web_app_metrics.cc b/chrome/browser/ui/web_applications/web_app_metrics.cc
index 53493b4..e488df6 100644
--- a/chrome/browser/ui/web_applications/web_app_metrics.cc
+++ b/chrome/browser/ui/web_applications/web_app_metrics.cc
@@ -85,7 +85,7 @@
       profile_(profile),
       browser_tab_strip_tracker_(this, nullptr) {
   browser_tab_strip_tracker_.Init();
-  base::PowerMonitor::AddObserver(this);
+  base::PowerMonitor::AddPowerSuspendObserver(this);
   BrowserList::AddObserver(this);
 
   WebAppProvider* provider = WebAppProvider::Get(profile_);
@@ -97,7 +97,7 @@
 
 WebAppMetrics::~WebAppMetrics() {
   BrowserList::RemoveObserver(this);
-  base::PowerMonitor::RemoveObserver(this);
+  base::PowerMonitor::RemovePowerSuspendObserver(this);
 }
 
 void WebAppMetrics::OnEngagementEvent(
diff --git a/chrome/browser/ui/web_applications/web_app_metrics.h b/chrome/browser/ui/web_applications/web_app_metrics.h
index b20e77a..21d9fa70 100644
--- a/chrome/browser/ui/web_applications/web_app_metrics.h
+++ b/chrome/browser/ui/web_applications/web_app_metrics.h
@@ -31,7 +31,7 @@
                       public site_engagement::SiteEngagementObserver,
                       public BrowserListObserver,
                       public TabStripModelObserver,
-                      public base::PowerObserver {
+                      public base::PowerSuspendObserver {
  public:
   static WebAppMetrics* Get(Profile* profile);
 
@@ -57,7 +57,7 @@
       const TabStripModelChange& change,
       const TabStripSelectionChange& selection) override;
 
-  // base::PowerObserver:
+  // base::PowerSuspendObserver:
   void OnSuspend() override;
 
   // Called when a web contents changes associated AppId (may be empty).
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
index a30de5e..3b2f176 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
@@ -149,6 +149,12 @@
 constexpr char kTestAPIJSPath[] = "test_api.js";
 constexpr char kWebviewSamlInjectedJSPath[] = "webview_saml_injected.js";
 
+// Public
+constexpr char kLoginScreenBehaviorHTML[] = "components/login_screen_behavior.html";
+constexpr char kLoginScreenBehaviorJS[] = "components/login_screen_behavior.js";
+constexpr char kMultiStepBehaviorHTML[] = "components/multi_step_behavior.html";
+constexpr char kMultiStepBehaviorJS[] = "components/multi_step_behavior.js";
+
 // Components
 constexpr char kOobeSharedVarsCssHTML[] =
     "components/oobe_shared_vars_css.html";
@@ -693,6 +699,15 @@
 
 void OobeUI::AddOobeComponents(content::WebUIDataSource* source,
                                const base::DictionaryValue& localized_strings) {
+  source->AddResourcePath(kLoginScreenBehaviorHTML,
+                          IDR_OOBE_COMPONENTS_LOGIN_SCREEN_BEHAVIOR_HTML);
+  source->AddResourcePath(kLoginScreenBehaviorJS,
+                          IDR_OOBE_COMPONENTS_LOGIN_SCREEN_BEHAVIOR_JS);
+  source->AddResourcePath(kMultiStepBehaviorHTML,
+                          IDR_OOBE_COMPONENTS_MULTI_STEP_BEHAVIOR_HTML);
+  source->AddResourcePath(kMultiStepBehaviorJS,
+                          IDR_OOBE_COMPONENTS_MULTI_STEP_BEHAVIOR_JS);
+
   source->AddResourcePath(kI18nBehaviorHTML,
                           IDR_OOBE_COMPONENTS_I18N_BEHAVIOR_HTML);
   source->AddResourcePath(kI18nBehaviorJS,
diff --git a/chrome/browser/ui/webui/policy/policy_ui_browsertest.cc b/chrome/browser/ui/webui/policy/policy_ui_browsertest.cc
index f0a9b89..4809079 100644
--- a/chrome/browser/ui/webui/policy/policy_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/policy/policy_ui_browsertest.cc
@@ -682,7 +682,8 @@
   extensions::ExtensionBuilder builder;
   builder.SetPath(temp_dir_.GetPath());
   builder.SetManifest(manifest.Build());
-  builder.SetLocation(extensions::Manifest::EXTERNAL_POLICY_DOWNLOAD);
+  builder.SetLocation(
+      extensions::mojom::ManifestLocation::kExternalPolicyDownload);
 
   // Install extension.
   extensions::ExtensionService* service =
diff --git a/chrome/browser/ui/webui/settings/chromeos/people_section.cc b/chrome/browser/ui/webui/settings/chromeos/people_section.cc
index 4a07631..4a22bb2 100644
--- a/chrome/browser/ui/webui/settings/chromeos/people_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/people_section.cc
@@ -15,6 +15,7 @@
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/account_manager_facade_factory.h"
 #include "chrome/browser/ash/account_manager/account_manager_util.h"
 #include "chrome/browser/ash/login/quick_unlock/quick_unlock_utils.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
@@ -41,6 +42,7 @@
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/account_manager_core/account_manager_facade.h"
 #include "components/google/core/common/google_util.h"
 #include "components/omnibox/common/omnibox_features.h"
 #include "components/prefs/pref_service.h"
@@ -739,8 +741,11 @@
         g_browser_process->platform_part()->GetAccountManagerFactory();
     account_manager_ = factory->GetAccountManager(profile->GetPath().value());
     DCHECK(account_manager_);
-
     account_manager_->AddObserver(this);
+
+    account_manager_facade_ =
+        ::GetAccountManagerFacade(profile->GetPath().value());
+    DCHECK(account_manager_facade_);
     FetchAccounts();
   }
 
@@ -1075,7 +1080,7 @@
 }
 
 void PeopleSection::FetchAccounts() {
-  account_manager_->GetAccounts(
+  account_manager_facade_->GetAccounts(
       base::BindOnce(&PeopleSection::UpdateAccountManagerSearchTags,
                      weak_factory_.GetWeakPtr()));
 }
diff --git a/chrome/browser/ui/webui/settings/chromeos/people_section.h b/chrome/browser/ui/webui/settings/chromeos/people_section.h
index 43fee276..d7d4bf8 100644
--- a/chrome/browser/ui/webui/settings/chromeos/people_section.h
+++ b/chrome/browser/ui/webui/settings/chromeos/people_section.h
@@ -18,6 +18,10 @@
 class Profile;
 class SupervisedUserService;
 
+namespace account_manager {
+class AccountManagerFacade;
+}
+
 namespace content {
 class WebUIDataSource;
 }  // namespace content
@@ -84,6 +88,7 @@
   void UpdateRemoveFingerprintSearchTags();
 
   AccountManager* account_manager_ = nullptr;
+  account_manager::AccountManagerFacade* account_manager_facade_ = nullptr;
   syncer::SyncService* sync_service_;
   SupervisedUserService* supervised_user_service_;
   KerberosCredentialsManager* kerberos_credentials_manager_;
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc b/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc
index d22510b..32daa1cc 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc
@@ -16,6 +16,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/values.h"
+#include "chrome/browser/account_manager_facade_factory.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/child_accounts/secondary_account_consent_logger.h"
@@ -30,6 +31,7 @@
 #include "chrome/browser/ui/webui/signin/signin_helper_chromeos.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/dbus/util/version_loader.h"
+#include "components/account_manager_core/account_manager_facade.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/public/identity_manager/account_info.h"
@@ -392,13 +394,9 @@
     const base::ListValue* args) {
   const std::string& callback_id = args->GetList()[0].GetString();
   const Profile* profile = Profile::FromWebUI(web_ui());
-  auto* account_manager = g_browser_process->platform_part()
-                              ->GetAccountManagerFactory()
-                              ->GetAccountManager(profile->GetPath().value());
-
-  account_manager->GetAccounts(
-      base::BindOnce(&InlineLoginHandlerChromeOS::OnGetAccounts,
-                     weak_factory_.GetWeakPtr(), callback_id));
+  ::GetAccountManagerFacade(profile->GetPath().value())
+      ->GetAccounts(base::BindOnce(&InlineLoginHandlerChromeOS::OnGetAccounts,
+                                   weak_factory_.GetWeakPtr(), callback_id));
 }
 
 void InlineLoginHandlerChromeOS::OnGetAccounts(
diff --git a/chrome/browser/ui/webui/sync_internals/sync_internals_ui.cc b/chrome/browser/ui/webui/sync_internals/sync_internals_ui.cc
index c8c52da..1ef0831 100644
--- a/chrome/browser/ui/webui/sync_internals/sync_internals_ui.cc
+++ b/chrome/browser/ui/webui/sync_internals/sync_internals_ui.cc
@@ -10,7 +10,8 @@
 #include "chrome/browser/ui/webui/sync_internals/sync_internals_message_handler.h"
 #include "chrome/browser/ui/webui/webui_util.h"
 #include "chrome/common/url_constants.h"
-#include "components/grit/sync_driver_resources.h"
+#include "components/grit/sync_driver_sync_internals_resources.h"
+#include "components/grit/sync_driver_sync_internals_resources_map.h"
 #include "components/sync/driver/sync_internals_util.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
@@ -29,32 +30,9 @@
       "trusted-types jstemplate cr-ui-tree-js-static;");
 
   source->UseStringsJs();
-
-  static constexpr webui::ResourcePath kResources[] = {
-      {syncer::sync_ui_util::kSyncIndexJS,
-       IDR_SYNC_DRIVER_SYNC_INTERNALS_INDEX_JS},
-      {syncer::sync_ui_util::kChromeSyncJS,
-       IDR_SYNC_DRIVER_SYNC_INTERNALS_CHROME_SYNC_JS},
-      {syncer::sync_ui_util::kSyncLogJS,
-       IDR_SYNC_DRIVER_SYNC_INTERNALS_SYNC_LOG_JS},
-      {syncer::sync_ui_util::kSyncNodeBrowserJS,
-       IDR_SYNC_DRIVER_SYNC_INTERNALS_SYNC_NODE_BROWSER_JS},
-      {syncer::sync_ui_util::kSyncSearchJS,
-       IDR_SYNC_DRIVER_SYNC_INTERNALS_SYNC_SEARCH_JS},
-      {syncer::sync_ui_util::kAboutJS, IDR_SYNC_DRIVER_SYNC_INTERNALS_ABOUT_JS},
-      {syncer::sync_ui_util::kDataJS, IDR_SYNC_DRIVER_SYNC_INTERNALS_DATA_JS},
-      {syncer::sync_ui_util::kEventsJS,
-       IDR_SYNC_DRIVER_SYNC_INTERNALS_EVENTS_JS},
-      {syncer::sync_ui_util::kSearchJS,
-       IDR_SYNC_DRIVER_SYNC_INTERNALS_SEARCH_JS},
-      {syncer::sync_ui_util::kUserEventsJS,
-       IDR_SYNC_DRIVER_SYNC_INTERNALS_USER_EVENTS_JS},
-      {syncer::sync_ui_util::kTrafficLogJS,
-       IDR_SYNC_DRIVER_SYNC_INTERNALS_TRAFFIC_LOG_JS},
-      {syncer::sync_ui_util::kInvalidationsJS,
-       IDR_SYNC_DRIVER_SYNC_INTERNALS_INVALIDATIONS_JS},
-  };
-  source->AddResourcePaths(kResources);
+  source->AddResourcePaths(
+      base::make_span(kSyncDriverSyncInternalsResources,
+                      kSyncDriverSyncInternalsResourcesSize));
 
   source->SetDefaultResource(IDR_SYNC_DRIVER_SYNC_INTERNALS_INDEX_HTML);
   return source;
diff --git a/chrome/browser/ui/webui/system_info_ui.cc b/chrome/browser/ui/webui/system_info_ui.cc
index a9d39ab..2aaa185 100644
--- a/chrome/browser/ui/webui/system_info_ui.cc
+++ b/chrome/browser/ui/webui/system_info_ui.cc
@@ -80,14 +80,16 @@
 
   // WebUIMessageHandler implementation.
   void RegisterMessages() override;
+  void OnJavascriptDisallowed() override;
 
   // Callback for the "requestSystemInfo" message. This asynchronously requests
   // system info and eventually returns it to the front end.
-  void HandleRequestSystemInfo(const base::ListValue*);
+  void HandleRequestSystemInfo(const base::ListValue* args);
 
   void OnSystemInfo(std::unique_ptr<SystemLogsResponse> sys_info);
 
  private:
+  std::string callback_id_;
   base::WeakPtrFactory<SystemInfoHandler> weak_ptr_factory_{this};
   DISALLOW_COPY_AND_ASSIGN(SystemInfoHandler);
 };
@@ -101,15 +103,22 @@
 
 SystemInfoHandler::~SystemInfoHandler() {}
 
+void SystemInfoHandler::OnJavascriptDisallowed() {
+  weak_ptr_factory_.InvalidateWeakPtrs();
+  callback_id_.clear();
+}
+
 void SystemInfoHandler::RegisterMessages() {
   web_ui()->RegisterMessageCallback(
       "requestSystemInfo",
       base::BindRepeating(&SystemInfoHandler::HandleRequestSystemInfo,
-                          weak_ptr_factory_.GetWeakPtr()));
+                          base::Unretained(this)));
 }
 
-void SystemInfoHandler::HandleRequestSystemInfo(const base::ListValue*) {
+void SystemInfoHandler::HandleRequestSystemInfo(const base::ListValue* args) {
   AllowJavascript();
+  callback_id_ = args->GetList()[0].GetString();
+
   system_logs::SystemLogsFetcher* fetcher =
       system_logs::BuildAboutSystemLogsFetcher();
   fetcher->Fetch(base::BindOnce(&SystemInfoHandler::OnSystemInfo,
@@ -129,7 +138,8 @@
     val->SetString("statValue", it->second);
     data.Append(std::move(val));
   }
-  CallJavascriptFunction("returnSystemInfo", data);
+  ResolveJavascriptCallback(base::Value(callback_id_), data);
+  callback_id_.clear();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/user_education/BUILD.gn b/chrome/browser/user_education/BUILD.gn
index 1ecb3fbc..bbbe46a1 100644
--- a/chrome/browser/user_education/BUILD.gn
+++ b/chrome/browser/user_education/BUILD.gn
@@ -16,6 +16,7 @@
   deps = [
     ":java_resources",
     "//base:base_java",
+    "//chrome/browser/feature_engagement:java",
     "//chrome/browser/profiles/android:java",
     "//chrome/browser/util:java",
     "//components/browser_ui/util/android:java",
diff --git a/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/UserEducationHelper.java b/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/UserEducationHelper.java
index 711e87a..44b569e3 100644
--- a/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/UserEducationHelper.java
+++ b/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/UserEducationHelper.java
@@ -8,7 +8,7 @@
 import android.os.Handler;
 import android.view.View;
 
-import org.chromium.base.Function;
+import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.util.ChromeAccessibilityUtil;
 import org.chromium.components.browser_ui.widget.highlight.ViewHighlighter;
@@ -40,13 +40,10 @@
 public class UserEducationHelper {
     private final Activity mActivity;
     private final Handler mHandler;
-    private final Function<Profile, Tracker> mTrackerFromProfileFactory;
 
-    public UserEducationHelper(Activity activity, Handler handler,
-            Function<Profile, Tracker> trackerFromProfileFactory) {
+    public UserEducationHelper(Activity activity, Handler handler) {
         mActivity = activity;
         mHandler = handler;
-        mTrackerFromProfileFactory = trackerFromProfileFactory;
     }
 
     /**
@@ -60,7 +57,7 @@
         // incognito profile) instead of always using regular profile. Currently always original
         // profile is used not to start popping IPH messages as soon as opening an incognito tab.
         Profile profile = Profile.getLastUsedRegularProfile();
-        final Tracker tracker = mTrackerFromProfileFactory.apply(profile);
+        final Tracker tracker = TrackerFactory.getTrackerForProfile(profile);
         tracker.addOnInitializedCallback(success -> showIPH(tracker, iphCommand));
     }
 
diff --git a/chrome/browser/web_applications/policy/web_app_policy_manager.cc b/chrome/browser/web_applications/policy/web_app_policy_manager.cc
index 2248069..f09f959 100644
--- a/chrome/browser/web_applications/policy/web_app_policy_manager.cc
+++ b/chrome/browser/web_applications/policy/web_app_policy_manager.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/web_applications/components/os_integration_manager.h"
 #include "chrome/browser/web_applications/components/policy/web_app_policy_constants.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
+#include "chrome/browser/web_applications/components/web_app_id_constants.h"
 #include "chrome/browser/web_applications/components/web_app_install_utils.h"
 #include "chrome/browser/web_applications/system_web_app_manager.h"
 #include "chrome/common/pref_names.h"
@@ -173,59 +174,21 @@
 
 void WebAppPolicyManager::OnDisableListPolicyChanged() {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  auto disabled_web_apps = GetDisabledWebAppsIds();
-  std::vector<AppId> app_ids = app_registrar_->GetAppIds();
+  PopulateDisabledWebAppsIdsLists();
+  std::vector<web_app::AppId> app_ids = app_registrar_->GetAppIds();
   for (const auto& id : app_ids) {
-    const bool is_disabled = base::Contains(disabled_web_apps, id);
+    const bool is_disabled = base::Contains(disabled_web_apps_, id);
     app_registry_controller_->SetAppIsDisabled(id, is_disabled);
   }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 std::set<SystemAppType> WebAppPolicyManager::GetDisabledSystemWebApps() const {
-  std::set<SystemAppType> disabled_system_apps;
-
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  PrefService* const local_state = g_browser_process->local_state();
-  if (!local_state)  // Sometimes it's not available in tests.
-    return disabled_system_apps;
-
-  const base::ListValue* disabled_system_features_pref =
-      local_state->GetList(policy::policy_prefs::kSystemFeaturesDisableList);
-  if (!disabled_system_features_pref)
-    return disabled_system_apps;
-
-  for (const auto& entry : *disabled_system_features_pref) {
-    switch (entry.GetInt()) {
-      case policy::SystemFeature::kCamera:
-        disabled_system_apps.insert(SystemAppType::CAMERA);
-        break;
-      case policy::SystemFeature::kOsSettings:
-        disabled_system_apps.insert(SystemAppType::SETTINGS);
-        break;
-      case policy::SystemFeature::kScanning:
-        disabled_system_apps.insert(SystemAppType::SCANNING);
-        break;
-    }
-  }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
-  return disabled_system_apps;
+  return disabled_system_apps_;
 }
 
 std::set<AppId> WebAppPolicyManager::GetDisabledWebAppsIds() const {
-  std::set<AppId> disabled_web_apps;
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  auto disabled_system_apps = GetDisabledSystemWebApps();
-  for (const auto& app_type : disabled_system_apps) {
-    base::Optional<AppId> app_id =
-        web_app_manager_->GetAppIdForSystemApp(app_type);
-    if (app_id.has_value()) {
-      disabled_web_apps.insert(app_id.value());
-    }
-  }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-  return disabled_web_apps;
+  return disabled_web_apps_;
 }
 
 bool WebAppPolicyManager::IsDisabledAppsModeHidden() const {
@@ -467,4 +430,44 @@
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
+void WebAppPolicyManager::PopulateDisabledWebAppsIdsLists() {
+  disabled_system_apps_.clear();
+  disabled_web_apps_.clear();
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  PrefService* const local_state = g_browser_process->local_state();
+  if (!local_state)  // Sometimes it's not available in tests.
+    return;
+
+  const base::ListValue* disabled_system_features_pref =
+      local_state->GetList(policy::policy_prefs::kSystemFeaturesDisableList);
+  if (!disabled_system_features_pref)
+    return;
+
+  for (const auto& entry : *disabled_system_features_pref) {
+    switch (entry.GetInt()) {
+      case policy::SystemFeature::kCamera:
+        disabled_system_apps_.insert(SystemAppType::CAMERA);
+        break;
+      case policy::SystemFeature::kOsSettings:
+        disabled_system_apps_.insert(SystemAppType::SETTINGS);
+        break;
+      case policy::SystemFeature::kScanning:
+        disabled_system_apps_.insert(SystemAppType::SCANNING);
+        break;
+      case policy::SystemFeature::kCanvas:
+        disabled_web_apps_.insert(web_app::kCanvasAppId);
+        break;
+    }
+  }
+
+  for (const auto& app_type : disabled_system_apps_) {
+    base::Optional<AppId> app_id =
+        web_app_manager_->GetAppIdForSystemApp(app_type);
+    if (app_id.has_value()) {
+      disabled_web_apps_.insert(app_id.value());
+    }
+  }
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+}
+
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/policy/web_app_policy_manager.h b/chrome/browser/web_applications/policy/web_app_policy_manager.h
index ad8679e..4e9c54d 100644
--- a/chrome/browser/web_applications/policy/web_app_policy_manager.h
+++ b/chrome/browser/web_applications/policy/web_app_policy_manager.h
@@ -112,6 +112,10 @@
 
   void OnDisableModePolicyChanged();
 
+  // Populates ids lists of web apps disabled by SystemFeaturesDisableList
+  // policy.
+  void PopulateDisabledWebAppsIdsLists();
+
   Profile* profile_;
   PrefService* pref_service_;
 
@@ -125,6 +129,10 @@
 
   PrefChangeRegistrar pref_change_registrar_;
   PrefChangeRegistrar local_state_pref_change_registrar_;
+  // List of disabled system web apps, containing app types.
+  std::set<SystemAppType> disabled_system_apps_;
+  // List of disabled system and progressive web apps, containing app ids.
+  std::set<AppId> disabled_web_apps_;
 
   // Testing callbacks
   base::OnceClosure refresh_policy_settings_completed_;
diff --git a/chrome/browser/webauthn/authenticator_extension_browsertest.cc b/chrome/browser/webauthn/authenticator_extension_browsertest.cc
index 282e17e..5233e07 100644
--- a/chrome/browser/webauthn/authenticator_extension_browsertest.cc
+++ b/chrome/browser/webauthn/authenticator_extension_browsertest.cc
@@ -61,7 +61,7 @@
   extensions::ExtensionBuilder builder("test");
   builder.SetPath(temp_dir.GetPath())
       .SetVersion("1.0")
-      .SetLocation(extensions::Manifest::EXTERNAL_POLICY_DOWNLOAD)
+      .SetLocation(extensions::mojom::ManifestLocation::kExternalPolicyDownload)
       .SetManifestKey("web_accessible_resources", std::move(resources));
 
   extensions::ExtensionService* service =
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 5af4599..81d65be 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-master-1615225267-9a1a41aa12e385127a2d8a58b527910aac2f3d0e.profdata
+chrome-mac-master-1615895772-90c2bf8c2781a73f4a574078d5f63a9efff1fc46.profdata
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 273116c3..f4f899c9f 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -101,13 +101,6 @@
 const base::Feature kBorealis{"Borealis", base::FEATURE_DISABLED_BY_DEFAULT};
 #endif
 
-#if BUILDFLAG(TRIAL_COMPARISON_CERT_VERIFIER_SUPPORTED)
-// Enables the dual certificate verification trial feature.
-// https://crbug.com/649026
-const base::Feature kCertDualVerificationTrialFeature{
-    "CertDualVerificationTrial", base::FEATURE_DISABLED_BY_DEFAULT};
-#endif
-
 // Enables change picture video mode.
 const base::Feature kChangePictureVideoMode{"ChangePictureVideoMode",
                                             base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 34af745..12783cb 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -16,7 +16,6 @@
 #include "build/chromeos_buildflags.h"
 #include "chrome/common/buildflags.h"
 #include "device/vr/buildflags/buildflags.h"
-#include "net/net_buildflags.h"
 #include "ppapi/buildflags/buildflags.h"
 #include "printing/buildflags/buildflags.h"
 #include "ui/base/buildflags.h"
@@ -84,11 +83,6 @@
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kBorealis;
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-#if BUILDFLAG(TRIAL_COMPARISON_CERT_VERIFIER_SUPPORTED)
-COMPONENT_EXPORT(CHROME_FEATURES)
-extern const base::Feature kCertDualVerificationTrialFeature;
-#endif
-
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kChangePictureVideoMode;
 
diff --git a/chrome/common/extensions/permissions/permissions_data_unittest.cc b/chrome/common/extensions/permissions/permissions_data_unittest.cc
index 6bda4e6..bd34935 100644
--- a/chrome/common/extensions/permissions/permissions_data_unittest.cc
+++ b/chrome/common/extensions/permissions/permissions_data_unittest.cc
@@ -38,8 +38,9 @@
 using base::UTF16ToUTF8;
 using content::SocketPermissionRequest;
 using extension_test_util::LoadManifest;
-using extension_test_util::LoadManifestUnchecked;
 using extension_test_util::LoadManifestStrict;
+using extension_test_util::LoadManifestUnchecked;
+using extensions::mojom::ManifestLocation;
 
 namespace extensions {
 
@@ -69,7 +70,7 @@
 scoped_refptr<const Extension> GetExtensionWithHostPermission(
     const std::string& id,
     const std::string& host_permissions,
-    Manifest::Location location) {
+    ManifestLocation location) {
   ListBuilder permissions;
   if (!host_permissions.empty())
     permissions.Append(host_permissions);
@@ -290,19 +291,15 @@
 }
 
 TEST(PermissionsDataTest, IsRestrictedUrl) {
-  scoped_refptr<const Extension> extension =
-      GetExtensionWithHostPermission("normal_extension",
-                                     kAllHostsPermission,
-                                     Manifest::INTERNAL);
+  scoped_refptr<const Extension> extension = GetExtensionWithHostPermission(
+      "normal_extension", kAllHostsPermission, ManifestLocation::kInternal);
   // Chrome and chrome-untrusted:// urls should be blocked for normal
   // extensions.
   CheckRestrictedUrls(extension.get(), /*block_chrome_urls=*/true,
                       /*block_chrome_untrusted_urls=*/true);
 
-  scoped_refptr<const Extension> component =
-      GetExtensionWithHostPermission("component",
-                                     kAllHostsPermission,
-                                     Manifest::COMPONENT);
+  scoped_refptr<const Extension> component = GetExtensionWithHostPermission(
+      "component", kAllHostsPermission, ManifestLocation::kComponent);
   // Chrome and chrome-untrusted:// urls should be accessible by component
   // extensions.
   CheckRestrictedUrls(component.get(), /*block_chrome_urls=*/false,
@@ -360,13 +357,13 @@
   // A regular extension shouldn't get access to chrome-extension: scheme URLs
   // even with <all_urls> specified.
   extension = GetExtensionWithHostPermission("regular_extension", "<all_urls>",
-                                             Manifest::UNPACKED);
+                                             ManifestLocation::kUnpacked);
   ASSERT_FALSE(extension->permissions_data()->HasHostPermission(external_file));
 
   // Component extensions should get access to chrome-extension: scheme URLs
   // when <all_urls> is specified.
-  extension = GetExtensionWithHostPermission("component_extension",
-                                             "<all_urls>", Manifest::COMPONENT);
+  extension = GetExtensionWithHostPermission(
+      "component_extension", "<all_urls>", ManifestLocation::kComponent);
   ASSERT_TRUE(extension->permissions_data()->HasHostPermission(external_file));
 }
 
@@ -914,14 +911,16 @@
 TEST(PermissionsDataTest, ChromeWebstoreUrl) {
   scoped_refptr<const Extension> normal_extension =
       GetExtensionWithHostPermission("all_hosts_normal_extension",
-                                     kAllHostsPermission, Manifest::INTERNAL);
+                                     kAllHostsPermission,
+                                     ManifestLocation::kInternal);
   scoped_refptr<const Extension> policy_extension =
       GetExtensionWithHostPermission("all_hosts_policy_extension",
                                      kAllHostsPermission,
-                                     Manifest::EXTERNAL_POLICY);
+                                     ManifestLocation::kExternalPolicy);
   scoped_refptr<const Extension> unpacked_extension =
       GetExtensionWithHostPermission("all_hosts_unpacked_extension",
-                                     kAllHostsPermission, Manifest::UNPACKED);
+                                     kAllHostsPermission,
+                                     ManifestLocation::kUnpacked);
   const Extension* extensions[] = {
       normal_extension.get(), policy_extension.get(), unpacked_extension.get(),
   };
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index 7db307e..972c400 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -121,9 +121,6 @@
 const char kCookiesSettingsHelpCenterURL[] =
     "https://support.google.com/chrome?p=cpn_cookies";
 
-const char kCpuX86Sse2ObsoleteURL[] =
-    "https://support.google.com/chrome/?p=chrome_update_sse3";
-
 const char kCrashReasonURL[] =
 #if BUILDFLAG(IS_CHROMEOS_ASH)
     "https://support.google.com/chromebook/?p=e_awsnap";
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h
index 2d36146a..d1cb631 100644
--- a/chrome/common/url_constants.h
+++ b/chrome/common/url_constants.h
@@ -131,9 +131,6 @@
 // "Learn more" URL for cookies.
 extern const char kCookiesSettingsHelpCenterURL[];
 
-// The URL for the "learn more" link on the SSE2 obsolescence infobar.
-extern const char kCpuX86Sse2ObsoleteURL[];
-
 // "Learn more" URL for "Aw snap" page when showing "Reload" button.
 extern const char kCrashReasonURL[];
 
diff --git a/chrome/renderer/extensions/accessibility_private_hooks_delegate_unittest.cc b/chrome/renderer/extensions/accessibility_private_hooks_delegate_unittest.cc
index b184aab..e3e6a1d 100644
--- a/chrome/renderer/extensions/accessibility_private_hooks_delegate_unittest.cc
+++ b/chrome/renderer/extensions/accessibility_private_hooks_delegate_unittest.cc
@@ -31,7 +31,7 @@
   scoped_refptr<const Extension> extension =
       ExtensionBuilder("testExtension")
           .AddPermission("accessibilityPrivate")
-          .SetLocation(Manifest::COMPONENT)
+          .SetLocation(mojom::ManifestLocation::kComponent)
           .Build();
   RegisterExtension(extension);
   v8::HandleScope handle_scope(isolate());
diff --git a/chrome/renderer/extensions/extension_hooks_delegate_unittest.cc b/chrome/renderer/extensions/extension_hooks_delegate_unittest.cc
index ec83360..46d550d2 100644
--- a/chrome/renderer/extensions/extension_hooks_delegate_unittest.cc
+++ b/chrome/renderer/extensions/extension_hooks_delegate_unittest.cc
@@ -117,7 +117,7 @@
   scoped_refptr<const Extension> extension =
       ExtensionBuilder("foo")
           .SetBackgroundContext(ExtensionBuilder::BackgroundContext::EVENT_PAGE)
-          .SetLocation(Manifest::UNPACKED)
+          .SetLocation(mojom::ManifestLocation::kUnpacked)
           .Build();
   RegisterExtension(extension);
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index a182b84..4f0238c7 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -4405,6 +4405,10 @@
     deps += [ "//chrome/services/speech/soda:unit_tests" ]
   }
 
+  if (is_win || is_linux || is_mac) {
+    sources += [ "../browser/enterprise/connectors/device_trust/device_trust_key_pair_unittest.cc" ]
+  }
+
   if (is_android) {
     sources += [
       "../browser/android/search_permissions/search_permissions_service_unittest.cc",
@@ -4502,7 +4506,6 @@
       "../browser/enterprise/connectors/analysis/analysis_service_settings_unittest.cc",
       "../browser/enterprise/connectors/connectors_manager_unittest.cc",
       "../browser/enterprise/connectors/connectors_service_unittest.cc",
-      "../browser/enterprise/connectors/device_trust/device_trust_key_pair_unittest.cc",
       "../browser/enterprise/connectors/enterprise_connectors_policy_handler_unittest.cc",
       "../browser/enterprise/connectors/file_system/rename_handler_unittest.cc",
       "../browser/enterprise/connectors/file_system/service_settings_unittest.cc",
@@ -5817,7 +5820,7 @@
     sources += [ "../browser/safe_browsing/telemetry/android/android_telemetry_service_unittest.cc" ]
   }
 
-  if (is_linux || is_chromeos || is_mac || is_win) {
+  if (is_linux || is_chromeos_lacros || is_mac || is_win) {
     sources += [
       "../browser/enterprise/connectors/device_trust/device_trust_service_unittest.cc",
       "../browser/enterprise/connectors/device_trust/mock_signal_reporter.cc",
diff --git a/chromecast/browser/cast_browser_main_parts.cc b/chromecast/browser/cast_browser_main_parts.cc
index 3afc66a..559be6fd 100644
--- a/chromecast/browser/cast_browser_main_parts.cc
+++ b/chromecast/browser/cast_browser_main_parts.cc
@@ -67,6 +67,7 @@
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/main_function_params.h"
+#include "content/public/common/result_codes.h"
 #include "gpu/command_buffer/service/gpu_switches.h"
 #include "media/base/media.h"
 #include "media/base/media_switches.h"
@@ -517,7 +518,7 @@
   return 0;
 }
 
-void CastBrowserMainParts::PreMainMessageLoopRun() {
+int CastBrowserMainParts::PreMainMessageLoopRun() {
 #if !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
   memory_pressure_monitor_.reset(new util::MultiSourceMemoryPressureMonitor());
   auto cast_system_memory_pressure_evaluator =
@@ -686,6 +687,8 @@
     delete parameters_.ui_task;
     run_message_loop_ = false;
   }
+
+  return content::RESULT_CODE_NORMAL_EXIT;
 }
 
 #if defined(OS_ANDROID)
@@ -708,24 +711,25 @@
 }
 #endif  // defined(OS_ANDROID)
 
-bool CastBrowserMainParts::MainMessageLoopRun(int* result_code) {
+void CastBrowserMainParts::WillRunMainMessageLoop(
+    std::unique_ptr<base::RunLoop>& run_loop) {
 #if defined(OS_ANDROID)
   // Android does not use native main MessageLoop.
   NOTREACHED();
-  return true;
 #else
   if (run_message_loop_) {
-    base::RunLoop run_loop;
-
 #if !defined(OS_FUCHSIA)
     // Fuchsia doesn't have signals.
-    RegisterClosureOnSignal(run_loop.QuitClosure());
+    RegisterClosureOnSignal(run_loop->QuitClosure());
 #endif  // !defined(OS_FUCHSIA)
-
-    run_loop.Run();
+  } else {
+    run_loop.reset();
   }
+#endif
+}
 
-#if !defined(OS_FUCHSIA)
+void CastBrowserMainParts::PostMainMessageLoopRun() {
+#if !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
   // Once the main loop has stopped running, we give the browser process a few
   // seconds to stop cast service and finalize all resources. If a hang occurs
   // and cast services refuse to terminate successfully, then we SIGKILL the
@@ -734,14 +738,10 @@
   // TODO(sergeyu): Fuchsia doesn't implement POSIX signals. Implement a
   // different shutdown watchdog mechanism.
   RegisterKillOnAlarm(kKillOnAlarmTimeoutSec);
-#endif  // !defined(OS_FUCHSIA)
+#endif  // !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
 
   cast_browser_process_->cast_service()->Stop();
-  return true;
-#endif
-}
 
-void CastBrowserMainParts::PostMainMessageLoopRun() {
 #if (defined(OS_LINUX) || defined(OS_CHROMEOS)) && defined(USE_OZONE)
   wayland_server_controller_.reset();
 #endif
diff --git a/chromecast/browser/cast_browser_main_parts.h b/chromecast/browser/cast_browser_main_parts.h
index 008f3f6..e4b7be6 100644
--- a/chromecast/browser/cast_browser_main_parts.h
+++ b/chromecast/browser/cast_browser_main_parts.h
@@ -83,8 +83,9 @@
   void PostMainMessageLoopStart() override;
   void ToolkitInitialized() override;
   int PreCreateThreads() override;
-  void PreMainMessageLoopRun() override;
-  bool MainMessageLoopRun(int* result_code) override;
+  int PreMainMessageLoopRun() override;
+  void WillRunMainMessageLoop(
+      std::unique_ptr<base::RunLoop>& run_loop) override;
   void PostMainMessageLoopRun() override;
   void PostCreateThreads() override;
   void PostDestroyThreads() override;
diff --git a/chromecast/metrics/cast_metrics_service_client.cc b/chromecast/metrics/cast_metrics_service_client.cc
index a95d851c..e213660 100644
--- a/chromecast/metrics/cast_metrics_service_client.cc
+++ b/chromecast/metrics/cast_metrics_service_client.cc
@@ -175,6 +175,10 @@
 #endif  // defined(OS_ANDROID) || defined(OS_FUCHSIA)
 }
 
+bool CastMetricsServiceClient::IsExtendedStableChannel() {
+  return false;  // Not supported on Chromecast.
+}
+
 std::string CastMetricsServiceClient::GetVersionString() {
   int build_number;
   if (!base::StringToInt(CAST_BUILD_INCREMENTAL, &build_number))
diff --git a/chromecast/metrics/cast_metrics_service_client.h b/chromecast/metrics/cast_metrics_service_client.h
index 8623b3e..c0b268e 100644
--- a/chromecast/metrics/cast_metrics_service_client.h
+++ b/chromecast/metrics/cast_metrics_service_client.h
@@ -90,6 +90,7 @@
   std::string GetApplicationLocale() override;
   bool GetBrand(std::string* brand_code) override;
   ::metrics::SystemProfileProto::Channel GetChannel() override;
+  bool IsExtendedStableChannel() override;
   std::string GetVersionString() override;
   void CollectFinalMetricsForLog(base::OnceClosure done_callback) override;
   GURL GetMetricsServerUrl() override;
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index d2d85f3..ccda08a 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-13853.0.0
\ No newline at end of file
+13854.0.0
\ No newline at end of file
diff --git a/chromeos/components/camera_app_ui/resources/js/device/constraints_preferrer.js b/chromeos/components/camera_app_ui/resources/js/device/constraints_preferrer.js
index 462678b..bd6f937 100644
--- a/chromeos/components/camera_app_ui/resources/js/device/constraints_preferrer.js
+++ b/chromeos/components/camera_app_ui/resources/js/device/constraints_preferrer.js
@@ -170,6 +170,118 @@
   setPreferredResolutionChangeListener(listener) {
     this.preferredResolutionChangeListener_ = listener;
   }
+
+  /**
+   * Sorts the preview resolution (Rp) according to the capture resolution
+   * (Rc) and the screen size (Rs) with the following orders:
+   * If |Rc| <= |Rs|:
+   *   1. All |Rp| <= |Rc|, and the larger, the better.
+   *   2. All |Rp| > |Rc|, and the smaller, the better.
+   *
+   * If |Rc| > |Rs|:
+   *   1. All |Rp| where |Rs| <= |Rp| <= |Rc|, and the smaller, the
+   *   better.
+   *   2. All |Rp| < |Rs|, and the larger, the better.
+   *   3. All |Rp| > |Rc|, and the smaller, the better.
+   *
+   * @param {!ResolutionList} previewResolutions
+   * @param {!Resolution} captureResolution
+   * @return {!ResolutionList}
+   * @protected
+   */
+  sortPreview_(previewResolutions, captureResolution) {
+    if (previewResolutions.length === 0) {
+      return [];
+    }
+
+    const Rs = Math.floor(window.screen.width * window.devicePixelRatio);
+    const Rc = captureResolution.width;
+    const cmpDescending = (r1, r2) => r2.width - r1.width;
+    const cmpAscending = (r1, r2) => r1.width - r2.width;
+
+    if (Rc <= Rs) {
+      const notLargerThanR =
+          previewResolutions.filter((r) => r.width <= Rc).sort(cmpDescending);
+      const largerThanR =
+          previewResolutions.filter((r) => r.width > Rc).sort(cmpAscending);
+      return notLargerThanR.concat(largerThanR);
+    } else {
+      const betweenRsR =
+          previewResolutions.filter((r) => Rs <= r.width && r.width <= Rc)
+              .sort(cmpAscending);
+      const smallerThanRs =
+          previewResolutions.filter((r) => r.width < Rs).sort(cmpDescending);
+      const largerThanR =
+          previewResolutions.filter((r) => r.width > Rc).sort(cmpAscending);
+      return betweenRsR.concat(smallerThanRs).concat(largerThanR);
+    }
+  }
+
+  /**
+   * Sorts prefer resolutions.
+   * @param {!Resolution} prefR Preferred resolution.
+   * @return {function(!CaptureCandidate, !CaptureCandidate): number} Return
+   *     compare function for comparing based on preferred resolution.
+   * @protected
+   */
+  getPreferResolutionSort_(prefR) {
+    /*
+     * @param {!CaptureCandidate} candidate
+     * @param {!CaptureCandidate} candidate2
+     * @return {number}
+     */
+    return ({resolution: r1}, {resolution: r2}) => {
+      if (r1.equals(r2)) {
+        return 0;
+      }
+      // Exactly the preferred resolution.
+      if (r1.equals(prefR)) {
+        return -1;
+      }
+      if (r2.equals(prefR)) {
+        return 1;
+      }
+
+      // Aspect ratio same as preferred resolution.
+      if (!r1.aspectRatioEquals(r2)) {
+        if (r1.aspectRatioEquals(prefR)) {
+          return -1;
+        }
+        if (r2.aspectRatioEquals(prefR)) {
+          return 1;
+        }
+      }
+      return r2.area - r1.area;
+    };
+  }
+
+  /**
+   * Groups resolutions with same ratio into same list.
+   * @param {!ResolutionList} rs
+   * @return {!Map<number, !ResolutionList>} Ratio as key, all resolutions
+   *     with that ratio as value.
+   */
+  groupResolutionRatio_(rs) {
+    /**
+     * @param {!Resolution} r
+     * @return {number}
+     */
+    const toSupportedPreviewRatio = (r) => {
+      // Special aspect ratio mapping rule, see http://b/147986763.
+      if (r.width === 848 && r.height === 480) {
+        return (new Resolution(16, 9)).aspectRatio;
+      }
+      return r.aspectRatio;
+    };
+
+    const result = new Map();
+    for (const r of rs) {
+      const ratio = toSupportedPreviewRatio(r);
+      result.set(ratio, result.get(ratio) || []);
+      result.get(ratio).push(r);
+    }
+    return result;
+  }
 }
 
 /**
@@ -223,6 +335,15 @@
     this.restoreResolutionPreference_('deviceVideoResolution');
     this.restoreFpsPreference_();
 
+    /**
+     * Maps from device id as key to video and preview resolutions of
+     * same aspect ratio supported by that video device as value.
+     * @type {!Map<string, !Array<{videoRs: !ResolutionList, previewRs:
+     *     !ResolutionList}>>}
+     * @private
+     */
+    this.deviceVideoPreviewResolutionMap_ = new Map();
+
     this.toggleFps_.addEventListener('click', (event) => {
       if (!state.get(state.State.STREAMING) || state.get(state.State.TAKING)) {
         event.preventDefault();
@@ -298,12 +419,33 @@
    * @override
    */
   updateDevicesInfo(devices) {
+    this.deviceVideoPreviewResolutionMap_ = new Map();
     this.supportedResolutions_ = new Map();
     this.constFpsInfo_ = {};
 
     devices.forEach(({deviceId, videoResols, videoMaxFps, fpsRanges}) => {
       this.supportedResolutions_.set(
           deviceId, [...videoResols].sort((r1, r2) => r2.area - r1.area));
+
+      // Filter out preview resolution greater than 1920x1080 and 1600x1200.
+      const previewRatios = this.groupResolutionRatio_(videoResols.filter(
+          ({width, height}) => width <= 1920 && height <= 1200));
+      const videoRatios = this.groupResolutionRatio_(videoResols);
+      /**
+       * @type {!Array<{videoRs: !ResolutionList, previewRs:
+       *     !ResolutionList}>}
+       */
+      const pairedResolutions = [];
+      for (const [ratio, videoRs] of videoRatios) {
+        const previewRs = previewRatios.get(/** @type {number} */ (ratio));
+        if (previewRs === undefined) {
+          continue;
+        }
+        pairedResolutions.push(
+            {videoRs: /** @type {!ResolutionList} */ (videoRs), previewRs});
+      }
+      this.deviceVideoPreviewResolutionMap_.set(deviceId, pairedResolutions);
+
       /**
        * @param {number} width
        * @param {number} height
@@ -360,40 +502,8 @@
    * @override
    */
   getSortedCandidates(deviceId) {
-    // Due to the limitation of MediaStream API, preview stream is used directly
-    // to do video recording.
-
     /** @type {!Resolution} */
     const prefR = this.getPrefResolution(deviceId) || new Resolution(0, -1);
-    /**
-     * @param {!Resolution} r1
-     * @param {!Resolution} r2
-     * @return {number}
-     */
-    const sortPrefResol = (r1, r2) => {
-      if (r1.equals(r2)) {
-        return 0;
-      }
-
-      // Exactly the preferred resolution.
-      if (r1.equals(prefR)) {
-        return -1;
-      }
-      if (r2.equals(prefR)) {
-        return 1;
-      }
-
-      // Aspect ratio same as preferred resolution.
-      if (!r1.aspectRatioEquals(r2)) {
-        if (r1.aspectRatioEquals(prefR)) {
-          return -1;
-        }
-        if (r2.aspectRatioEquals(prefR)) {
-          return 1;
-        }
-      }
-      return r2.area - r1.area;
-    };
 
     /**
      * Maps specified video resolution to object of resolution and all supported
@@ -420,27 +530,37 @@
     };
 
     /**
-     * @param {!Resolution} r
-     * @param {number} fps
-     * @return {!MediaStreamConstraints}
+     * @param {{videoRs: !ResolutionList, previewRs: !ResolutionList}} capture
+     * @return {!Array<!CaptureCandidate>}
      */
-    const toConstraints = ({width, height}, fps) => ({
-      audio: {echoCancellation: false},
-      video: {
-        deviceId: {exact: deviceId},
-        frameRate: fps ? {exact: fps} : {min: 20, ideal: 30},
-        width,
-        height,
-      },
-    });
+    const toVideoCandidate = ({videoRs, previewRs}) => {
+      let /** !Resolution */ videoR = prefR;
+      if (!videoRs.some((r) => r.equals(prefR))) {
+        videoR = videoRs.reduce(
+            (videoR, r) => (r.width > videoR.width ? r : videoR));
+      }
 
-    return [...this.supportedResolutions_.get(deviceId)]
-        .sort(sortPrefResol)
-        .flatMap(getFpses)
-        .map(({r, fps}) => ({
-               resolution: r,
-               previewCandidates: [toConstraints(r, fps)],
-             }));
+      return getFpses(videoR).map(
+          ({r, fps}) => ({
+            resolution: videoR,
+            previewCandidates:
+                this.sortPreview_(previewRs, videoR)
+                    .map(({width, height}) => ({
+                           audio: {echoCancellation: false},
+                           video: {
+                             deviceId: {exact: deviceId},
+                             frameRate: fps ? {exact: fps} :
+                                              {min: 20, ideal: 30},
+                             width,
+                             height,
+                           },
+                         })),
+          }));
+    };
+
+    return this.deviceVideoPreviewResolutionMap_.get(deviceId)
+        .flatMap(toVideoCandidate)
+        .sort(this.getPreferResolutionSort_(prefR));
   }
 }
 
@@ -488,36 +608,8 @@
     this.supportedResolutions_ = new Map();
 
     devices.forEach(({deviceId, photoResols, videoResols: previewResols}) => {
-      /**
-       * @param {!Resolution} r
-       * @return {number}
-       */
-      const toSupportedPreviewRatio = (r) => {
-        // Special aspect ratio mapping rule, see http://b/147986763.
-        if (r.width === 848 && r.height === 480) {
-          return (new Resolution(16, 9)).aspectRatio;
-        }
-        return r.aspectRatio;
-      };
-
-      /**
-       * Groups resolutions with same ratio into same list.
-       * @param {!ResolutionList} rs
-       * @return {!Map<number, !ResolutionList>} Ratio as key, all resolutions
-       *     with that ratio as value.
-       */
-      const groupResolutionRatio = (rs) => {
-        const result = new Map();
-        for (const r of rs) {
-          const ratio = toSupportedPreviewRatio(r);
-          result.set(ratio, result.get(ratio) || []);
-          result.get(ratio).push(r);
-        }
-        return result;
-      };
-
-      const previewRatios = groupResolutionRatio(previewResols);
-      const captureRatios = groupResolutionRatio(photoResols);
+      const previewRatios = this.groupResolutionRatio_(previewResols);
+      const captureRatios = this.groupResolutionRatio_(photoResols);
       /**
        * @type {!Array<{captureRs: !ResolutionList, previewRs:
        *     !ResolutionList}>}
@@ -569,25 +661,6 @@
     const prefR = this.getPrefResolution(deviceId) || new Resolution(0, -1);
 
     /**
-     * @param {!CaptureCandidate} candidate
-     * @param {!CaptureCandidate} candidate2
-     * @return {number}
-     */
-    const sortPrefResol = ({resolution: r1}, {resolution: r2}) => {
-      if (r1.equals(r2)) {
-        return 0;
-      }
-      // Exactly the preferred resolution.
-      if (r1.equals(prefR)) {
-        return -1;
-      }
-      if (r2.equals(prefR)) {
-        return 1;
-      }
-      return r2.area - r1.area;
-    };
-
-    /**
      * @param {{captureRs: !ResolutionList, previewRs: !ResolutionList}} capture
      * @return {!CaptureCandidate}
      */
@@ -598,64 +671,21 @@
             (captureR, r) => (r.width > captureR.width ? r : captureR));
       }
 
-      /**
-       * @param {!ResolutionList} resolutions
-       * @return {!ResolutionList}
-       */
-      const sortPreview = (resolutions) => {
-        if (resolutions.length === 0) {
-          return [];
-        }
-
-        // Sorts the preview resolution (Rp) according to the capture resolution
-        // (Rc) and the screen size (Rs) with the following orders:
-        // If |Rc| <= |Rs|:
-        //   1. All |Rp| <= |Rc|, and the larger, the better.
-        //   2. All |Rp| > |Rc|, and the smaller, the better.
-        //
-        // If |Rc| > |Rs|:
-        //   1. All |Rp| where |Rs| <= |Rp| <= |Rc|, and the smaller, the
-        //   better.
-        //   2. All |Rp| < |Rs|, and the larger, the better.
-        //   3. All |Rp| > |Rc|, and the smaller, the better.
-        //
-        const Rs = Math.floor(window.screen.width * window.devicePixelRatio);
-        const Rc = captureR.width;
-        const cmpDescending = (r1, r2) => r2.width - r1.width;
-        const cmpAscending = (r1, r2) => r1.width - r2.width;
-
-        if (Rc <= Rs) {
-          const notLargerThanRc =
-              resolutions.filter((r) => r.width <= Rc).sort(cmpDescending);
-          const largerThanRc =
-              resolutions.filter((r) => r.width > Rc).sort(cmpAscending);
-          return notLargerThanRc.concat(largerThanRc);
-        } else {
-          const betweenRsRc =
-              resolutions.filter((r) => Rs <= r.width && r.width <= Rc)
-                  .sort(cmpAscending);
-          const smallerThanRs =
-              resolutions.filter((r) => r.width < Rs).sort(cmpDescending);
-          const largerThanRc =
-              resolutions.filter((r) => r.width > Rc).sort(cmpAscending);
-          return betweenRsRc.concat(smallerThanRs).concat(largerThanRc);
-        }
-      };
-
       const /** !Array<!MediaStreamConstraints> */ previewCandidates =
-          sortPreview(previewRs).map(({width, height}) => ({
-                                       audio: false,
-                                       video: {
-                                         deviceId: {exact: deviceId},
-                                         width,
-                                         height,
-                                       },
-                                     }));
+          this.sortPreview_(previewRs, captureR).map(({width, height}) => ({
+                                                       audio: false,
+                                                       video: {
+                                                         deviceId:
+                                                             {exact: deviceId},
+                                                         width,
+                                                         height,
+                                                       },
+                                                     }));
       return {resolution: captureR, previewCandidates};
     };
 
     return this.deviceCapturePreviewResolutionMap_.get(deviceId)
         .map(toCaptureCandidate)
-        .sort(sortPrefResol);
+        .sort(this.getPreferResolutionSort_(prefR));
   }
 }
diff --git a/chromeos/components/camera_app_ui/resources/js/device/device_info_updater.js b/chromeos/components/camera_app_ui/resources/js/device/device_info_updater.js
index 88d2ff8..9f3da91 100644
--- a/chromeos/components/camera_app_ui/resources/js/device/device_info_updater.js
+++ b/chromeos/components/camera_app_ui/resources/js/device/device_info_updater.js
@@ -2,16 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import * as loadTimeData from '../models/load_time_data.js';
 import {DeviceOperator} from '../mojo/device_operator.js';
 // eslint-disable-next-line no-unused-vars
-import {ResolutionList, VideoConfig} from '../type.js';
-
 import {Camera3DeviceInfo} from './camera3_device_info.js';
 import {
   PhotoConstraintsPreferrer,  // eslint-disable-line no-unused-vars
   VideoConstraintsPreferrer,  // eslint-disable-line no-unused-vars
 } from './constraints_preferrer.js';
+import {
+  DeviceInfo,  // eslint-disable-line no-unused-vars
+  StreamManager,
+} from './stream_manager.js';
 
 /**
  * Contains information of all cameras on the device and will updates its value
@@ -59,37 +60,38 @@
 
     /**
      * MediaDeviceInfo of all available video devices.
-     * @type {!Promise<!Array<!MediaDeviceInfo>>}
+     * @type {!Array<!MediaDeviceInfo>}
      * @private
      */
-    this.devicesInfo_ = this.enumerateDevices_();
+    this.devicesInfo_ = [];
 
     /**
      * Camera3DeviceInfo of all available video devices. Is null on HALv1 device
      * without mojo api support.
-     * @type {!Promise<?Array<!Camera3DeviceInfo>>}
+     * @type {?Array<!Camera3DeviceInfo>}
      * @private
      */
-    this.camera3DevicesInfo_ = this.queryMojoDevicesInfo_();
+    this.camera3DevicesInfo_ = null;
 
     /**
-     * Filter out lagging 720p on grunt. See https://crbug.com/1122852.
-     * @const {!Promise<function(!VideoConfig): boolean>}
+     * Pending device Information.
+     * @type {!Array<!DeviceInfo>}
      * @private
      */
-    this.videoConfigFilter_ = (async () => {
-      const board = loadTimeData.getBoard();
-      return board === 'grunt' ? ({height}) => height < 720 : () => true;
-    })();
+    this.pendingDevicesInfo_ = [];
 
     /**
      * Promise of first update.
      * @type {!Promise}
+     * @private
      */
-    this.firstUpdate_ = this.update_();
+    this.firstUpdate_ = StreamManager.getInstance().deviceUpdate();
 
-    navigator.mediaDevices.addEventListener(
-        'devicechange', this.update_.bind(this));
+    StreamManager.getInstance().addRealDeviceChangeListener(
+        async (devicesInfo) => {
+          this.pendingDevicesInfo_ = devicesInfo;
+          await this.update_();
+        });
   }
 
   /**
@@ -127,56 +129,19 @@
    * @private
    */
   async doUpdate_() {
-    this.devicesInfo_ = this.enumerateDevices_();
-    this.camera3DevicesInfo_ = this.queryMojoDevicesInfo_();
-    try {
-      await this.devicesInfo_;
-      const devices = await this.camera3DevicesInfo_;
-      if (devices) {
-        this.photoPreferrer_.updateDevicesInfo(devices);
-        this.videoPreferrer_.updateDevicesInfo(devices);
-      }
+    this.devicesInfo_ = this.pendingDevicesInfo_.map((d) => d.v1Info);
+    this.camera3DevicesInfo_ = this.pendingDevicesInfo_.map((d) => d.v3Info);
+    // Update preferer if device supports HALv3.
+    if (await DeviceOperator.isSupported()) {
+      this.photoPreferrer_.updateDevicesInfo(this.camera3DevicesInfo_);
+      this.videoPreferrer_.updateDevicesInfo(this.camera3DevicesInfo_);
       await Promise.all(this.deviceChangeListeners_.map((l) => l(this)));
-    } catch (e) {
-      console.error(e);
+    } else {
+      this.camera3DevicesInfo_ = null;
     }
   }
 
   /**
-   * Enumerates all available devices and gets their MediaDeviceInfo.
-   * @return {!Promise<!Array<!MediaDeviceInfo>>}
-   * @throws {!Error}
-   * @private
-   */
-  async enumerateDevices_() {
-    const devices = (await navigator.mediaDevices.enumerateDevices())
-                        .filter((device) => device.kind === 'videoinput');
-    if (devices.length === 0) {
-      throw new Error('Device list empty.');
-    }
-    return devices;
-  }
-
-  /**
-   * Queries Camera3DeviceInfo of available devices through private mojo API.
-   * @return {!Promise<?Array<!Camera3DeviceInfo>>} Camera3DeviceInfo
-   *     of available devices. Maybe null on HALv1 devices without supporting
-   *     private mojo api.
-   * @throws {!Error} Thrown when camera unplugging happens between enumerating
-   *     devices and querying mojo APIs with current device info results.
-   * @private
-   */
-  async queryMojoDevicesInfo_() {
-    if (!await DeviceOperator.isSupported()) {
-      return null;
-    }
-    const deviceInfos = await this.devicesInfo_;
-    const videoConfigFilter = await this.videoConfigFilter_;
-    return Promise.all(
-        deviceInfos.map((d) => Camera3DeviceInfo.create(d, videoConfigFilter)));
-  }
-
-  /**
    * Registers listener to be called when state of available devices changes.
    * @param {function(!DeviceInfoUpdater): !Promise} listener
    */
diff --git a/chromeos/components/camera_app_ui/resources/js/device/stream_manager.js b/chromeos/components/camera_app_ui/resources/js/device/stream_manager.js
new file mode 100644
index 0000000..b1e947e4
--- /dev/null
+++ b/chromeos/components/camera_app_ui/resources/js/device/stream_manager.js
@@ -0,0 +1,339 @@
+// 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 {assert, assertString} from '../chrome_util.js';
+import {reportError} from '../error.js';
+import * as loadTimeData from '../models/load_time_data.js';
+import {DeviceOperator} from '../mojo/device_operator.js';
+// eslint-disable-next-line no-unused-vars
+import {ErrorLevel, ErrorType, Facing, VideoConfig} from '../type.js';
+import {WaitableEvent} from '../waitable_event.js';
+
+import {Camera3DeviceInfo} from './camera3_device_info.js';
+
+/**
+ * The singleton instance of StreamManager. Initialized by the first
+ * invocation of getInstance().
+ * @type {?StreamManager}
+ */
+let instance = null;
+
+/**
+ * Device information includs MediaDeviceInfo and Camera3DeviceInfo.
+ * @typedef {{
+ *   v1Info: !MediaDeviceInfo,
+ *   v3Info: ?Camera3DeviceInfo
+ * }}
+ */
+export let DeviceInfo;
+
+/**
+ * Real and virtual device mapping.
+ * @typedef {{
+ *   realId: string,
+ *   virtualId: string
+ * }}
+ */
+// eslint-disable-next-line no-unused-vars
+let VirtualMap;
+
+/**
+ * Creates extra stream for the current mode.
+ */
+export class CaptureStream {
+  /**
+   * @param {string} deviceId Device id of currently working video device
+   * @param {!MediaStream} stream Capture stream
+   * @private
+   */
+  constructor(deviceId, stream) {
+    /**
+     * Device id of currently working video device.
+     * @type {string}
+     * @private
+     */
+    this.deviceId_ = deviceId;
+
+    /**
+     * Capture stream
+     * @type {!MediaStream}
+     * @protected
+     */
+    this.stream_ = stream;
+  }
+
+  /**
+   * @return {!MediaStream}
+   * @public
+   */
+  get stream() {
+    return this.stream_;
+  }
+
+  /**
+   * Closes stream
+   * @public
+   */
+  async close() {
+    this.stream_.getVideoTracks()[0].stop();
+    if (await DeviceOperator.isSupported()) {
+      try {
+        await StreamManager.getInstance().setMultipleStreamsEnabled(
+            this.deviceId_, false);
+      } catch (e) {
+        reportError(ErrorType.MULTIPLE_STREAMS_FAILURE, ErrorLevel.ERROR, e);
+      }
+    }
+  }
+}
+
+/**
+ * Monitors device change and provides different listener callbacks for
+ * device changes. It also provides streams for different modes.
+ */
+export class StreamManager {
+  /**
+   * @private
+   */
+  constructor() {
+    /**
+     * MediaDeviceInfo of all available video devices.
+     * @type {?Promise<!Array<!MediaDeviceInfo>>}
+     * @private
+     */
+    this.devicesInfo_ = null;
+
+    /**
+     * Camera3DeviceInfo of all available video devices. Is null on HALv1 device
+     * without mojo api support.
+     * @type {?Promise<?Array<!DeviceInfo>>}
+     * @private
+     */
+    this.camera3DevicesInfo_ = null;
+
+    /**
+     * Listeners for real device change event.
+     * @type {!Array<function(!Array<!DeviceInfo>): !Promise>}
+     * @private
+     */
+    this.realListeners_ = [];
+
+    /**
+     * Latest result of Camera3DeviceInfo of all real video devices.
+     * @type {!Array<!DeviceInfo>}
+     * @private
+     */
+    this.realDevices_ = [];
+
+    /**
+     * real device id and corresponding virtual devices id mapping and it is
+     * only available on HALv3.
+     * @type {?VirtualMap}
+     * @private
+     */
+    this.virtualMap_ = null;
+
+    /**
+     * Signal it to indicate that the virtual device is ready.
+     * @type {?WaitableEvent<string>}
+     * @private
+     */
+    this.waitVirtual_ = null;
+
+    /**
+     * Filter out lagging 720p on grunt. See https://crbug.com/1122852.
+     * @const {!Promise<function(!VideoConfig): boolean>}
+     * @private
+     */
+    this.videoConfigFilter_ = (async () => {
+      const board = await loadTimeData.getBoard();
+      return board === 'grunt' ? ({height}) => height < 720 : () => true;
+    })();
+
+    navigator.mediaDevices.addEventListener(
+        'devicechange', this.deviceUpdate.bind(this));
+  }
+
+  /**
+   * Creates a new instance of StreamManager if it is not set. Returns the
+   *     exist instance.
+   * @return {!StreamManager} The singleton instance.
+   */
+  static getInstance() {
+    if (instance === null) {
+      instance = new StreamManager();
+    }
+    return instance;
+  }
+
+  /**
+   * Registers listener to be called when state of available real devices
+   * changes.
+   * @param {function(!Array<!DeviceInfo>)} listener
+   */
+  addRealDeviceChangeListener(listener) {
+    this.realListeners_.push(listener);
+  }
+
+  /**
+   * Creates extra stream according to the constraints.
+   * @param {!MediaStreamConstraints} constraints
+   * @return {!Promise<!CaptureStream>}
+   */
+  async openCaptureStream(constraints) {
+    const realDeviceId = assertString(constraints.video.deviceId.exact);
+    if (await DeviceOperator.isSupported()) {
+      try {
+        await this.setMultipleStreamsEnabled(realDeviceId, true);
+        constraints.video.deviceId.exact = this.virtualMap_.virtualId;
+      } catch (e) {
+        reportError(ErrorType.MULTIPLE_STREAMS_FAILURE, ErrorLevel.ERROR, e);
+      }
+    }
+
+    const stream = await navigator.mediaDevices.getUserMedia(constraints);
+    return new CaptureStream(realDeviceId, stream);
+  }
+
+  /**
+   * Handling function for device changing.
+   */
+  async deviceUpdate() {
+    const devices = await this.doDeviceInfoUpdate_();
+    if (devices === null) {
+      return;
+    }
+    await this.doDeviceNotify_(devices);
+  }
+
+  /**
+   * Gets devices information via mojo IPC.
+   * @return {?Promise<?Array<!DeviceInfo>>}
+   * @private
+   */
+  async doDeviceInfoUpdate_() {
+    this.devicesInfo_ = this.enumerateDevices_();
+    this.camera3DevicesInfo_ = this.queryMojoDevicesInfo_();
+    try {
+      return await this.camera3DevicesInfo_;
+    } catch (e) {
+      console.error(e);
+    }
+    return null;
+  }
+
+  /**
+   * Notifies device changes to listeners and create a mapping for real and
+   * virtual device.
+   * @param {!Array<!DeviceInfo>} devices
+   * @private
+   */
+  async doDeviceNotify_(devices) {
+    const isVirtual = (d) => d.v3Info !== null &&
+        (d.v3Info.facing === Facing.VIRTUAL_USER ||
+         d.v3Info.facing === Facing.VIRTUAL_ENV ||
+         d.v3Info.facing === Facing.VIRTUAL_EXT);
+    const realDevices = devices.filter((d) => !isVirtual(d));
+    const virtualDevices = devices.filter(isVirtual);
+    if (this.isRealDeviceChange_(realDevices)) {
+      this.realListeners_.map((l) => l(realDevices));
+    }
+    // We currently only support one virtual device.
+    assert(virtualDevices.length <= 1);
+
+    if (virtualDevices.length === 1 && this.waitVirtual_ !== null) {
+      this.waitVirtual_.signal(virtualDevices[0].v1Info.deviceId);
+      this.waitVirtual_ = null;
+    }
+    this.realDevices_ = realDevices;
+  }
+
+  /**
+   * Compares devices info to see whether there are only real devices change.
+   * @param {!Array<!DeviceInfo>} devices Real devices.
+   * @return {boolean}
+   * @private
+   */
+  isRealDeviceChange_(devices) {
+    if (this.realDevices_.length !== devices.length) {
+      return true;
+    }
+
+    for (const device of devices) {
+      const found = this.realDevices_.find(
+          (d2) => d2.v1Info.deviceId === device.v1Info.deviceId);
+      if (found === undefined) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /**
+   * Enumerates all available devices and gets their MediaDeviceInfo.
+   * @return {!Promise<!Array<!MediaDeviceInfo>>}
+   * @throws {!Error}
+   * @private
+   */
+  async enumerateDevices_() {
+    const devices = (await navigator.mediaDevices.enumerateDevices())
+                        .filter((device) => device.kind === 'videoinput');
+    if (devices.length === 0) {
+      throw new Error('Device list empty.');
+    }
+    return devices;
+  }
+
+  /**
+   * Queries Camera3DeviceInfo of available devices through private mojo API.
+   * @return {!Promise<?Array<!DeviceInfo>>} Camera3DeviceInfo of available
+   *     devices. Maybe null on HALv1 devices without supporting private mojo
+   *     api.
+   * @throws {!Error} Thrown when camera unplugging happens between enumerating
+   *     devices and querying mojo APIs with current device info results.
+   * @private
+   */
+  async queryMojoDevicesInfo_() {
+    const deviceInfos = await this.devicesInfo_;
+    const videoConfigFilter = await this.videoConfigFilter_;
+    const isV3Supported = await DeviceOperator.isSupported();
+    return Promise.all(deviceInfos.map(
+        async (d) => ({
+          v1Info: d,
+          v3Info: isV3Supported ?
+              (await Camera3DeviceInfo.create(d, videoConfigFilter)) :
+              null,
+        })));
+  }
+
+  /**
+   * Enables/Disables multiple streams on target camera device. The extra
+   * stream will be reported as virtual video device from
+   * navigator.mediaDevices.enumerateDevices().
+   * @param {string} deviceId The id of target camera device.
+   * @param {boolean} enabled True for eanbling multiple streams.
+   */
+  async setMultipleStreamsEnabled(deviceId, enabled) {
+    assert(await DeviceOperator.isSupported());
+    let waitEvent;
+    if (enabled) {
+      this.waitVirtual_ = new WaitableEvent();
+      waitEvent = this.waitVirtual_;
+    } else {
+      this.virtualMap_ = null;
+    }
+    const deviceOperator = await DeviceOperator.getInstance();
+    await deviceOperator.setMultipleStreamsEnabled(deviceId, enabled);
+    await this.deviceUpdate();
+    if (enabled) {
+      try {
+        const virtualId = await waitEvent.timedWait(3000);
+        this.virtualMap_ = {realId: deviceId, virtualId};
+      } catch (e) {
+        throw new Error(
+            `${deviceId} set multiple streams to ${enabled} failed`);
+      }
+    }
+  }
+}
diff --git a/chromeos/components/camera_app_ui/resources/js/js.gni b/chromeos/components/camera_app_ui/resources/js/js.gni
index 1b761bdd..d4f9565 100644
--- a/chromeos/components/camera_app_ui/resources/js/js.gni
+++ b/chromeos/components/camera_app_ui/resources/js/js.gni
@@ -11,6 +11,7 @@
   "device/camera3_device_info.js",
   "device/constraints_preferrer.js",
   "device/device_info_updater.js",
+  "device/stream_manager.js",
   "dom.js",
   "error.js",
   "face.js",
diff --git a/chromeos/components/camera_app_ui/resources/js/mojo/device_operator.js b/chromeos/components/camera_app_ui/resources/js/mojo/device_operator.js
index 2c5bb71a..4664a2a 100644
--- a/chromeos/components/camera_app_ui/resources/js/mojo/device_operator.js
+++ b/chromeos/components/camera_app_ui/resources/js/mojo/device_operator.js
@@ -270,6 +270,12 @@
         return Facing.USER;
       case cros.mojom.CameraFacing.CAMERA_FACING_EXTERNAL:
         return Facing.EXTERNAL;
+      case cros.mojom.CameraFacing.CAMERA_FACING_VIRTUAL_BACK:
+        return Facing.VIRTUAL_ENV;
+      case cros.mojom.CameraFacing.CAMERA_FACING_VIRTUAL_FRONT:
+        return Facing.VIRTUAL_USER;
+      case cros.mojom.CameraFacing.CAMERA_FACING_VIRTUAL_EXTERNAL:
+        return Facing.VIRTUAL_EXT;
       default:
         assertNotReached(`Unexpected facing value: ${facing}`);
     }
@@ -533,6 +539,19 @@
   }
 
   /**
+   * Enables/Disables multiple streams on target camera device. The extra
+   * stream will be reported as virtual video device from
+   * navigator.mediaDevices.enumerateDevices().
+   * @param {string} deviceId The id of target camera device.
+   * @param {boolean} enabled True for enabling multiple streams.
+   */
+  async setMultipleStreamsEnabled(deviceId, enabled) {
+    if (deviceId) {
+      await this.deviceProvider_.setMultipleStreamsEnabled(deviceId, enabled);
+    }
+  }
+
+  /**
    * Creates a new instance of DeviceOperator if it is not set. Returns the
    *     exist instance.
    * @return {!Promise<?DeviceOperator>} The singleton instance.
diff --git a/chromeos/components/camera_app_ui/resources/js/type.js b/chromeos/components/camera_app_ui/resources/js/type.js
index 6ce6f083..8dc00fb 100644
--- a/chromeos/components/camera_app_ui/resources/js/type.js
+++ b/chromeos/components/camera_app_ui/resources/js/type.js
@@ -96,6 +96,11 @@
   USER: 'user',
   ENVIRONMENT: 'environment',
   EXTERNAL: 'external',
+  // VIRTUAL_{facing} is for labeling video device for configuring extra stream
+  // from corresponding {facing} video device.
+  VIRTUAL_USER: 'virtual_user',
+  VIRTUAL_ENV: 'virtual_environment',
+  VIRTUAL_EXT: 'virtual_external',
   NOT_SET: '(not set)',
   UNKNOWN: 'unknown',
 };
@@ -216,6 +221,7 @@
   PRELOAD_IMAGE_FAILURE: 'preload-image-failure',
   SET_FPS_RANGE_FAILURE: 'set-fps-range-failure',
   UNCAUGHT_PROMISE: 'uncaught-promise',
+  MULTIPLE_STREAMS_FAILURE: 'multiple-streams-failure',
 };
 
 /**
diff --git a/chromeos/components/camera_app_ui/resources/js/views/camera.js b/chromeos/components/camera_app_ui/resources/js/views/camera.js
index 7c0c2616..a8487b1 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/camera.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/camera.js
@@ -596,7 +596,7 @@
           await this.endTake_();
         }
       } finally {
-        await this.preview_.close();
+        await this.stopStreams_();
       }
       return this.start_();
     })();
@@ -631,9 +631,8 @@
         }
         const factory = this.modes_.getModeFactory(mode);
         try {
-          factory.setCaptureResolution(captureR);
           if (deviceOperator !== null) {
-            factory.prepareDevice(deviceOperator, constraints);
+            factory.prepareDevice(deviceOperator, constraints, captureR);
           }
           const stream = await this.preview_.open(constraints);
           this.facingMode_ = await this.options_.updateValues(stream);
@@ -648,8 +647,8 @@
           nav.close(ViewName.WARNING, WarningType.NO_CAMERA);
           return true;
         } catch (e) {
-          factory.clear();
-          this.preview_.close();
+          await factory.clear();
+          await this.stopStreams_();
           console.error(e);
         }
       }
@@ -728,4 +727,15 @@
       return false;
     }
   }
+
+  /**
+   * Stop extra stream and preview stream.
+   * @private
+   */
+  async stopStreams_() {
+    // Stopping preview will wait device close. Therefore, we clear
+    // mode before stopping preview to close extra stream first.
+    await this.modes_.clear();
+    await this.preview_.close();
+  }
 }
diff --git a/chromeos/components/camera_app_ui/resources/js/views/camera/mode/index.js b/chromeos/components/camera_app_ui/resources/js/views/camera/mode/index.js
index 7ef142c3..e21055d2 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/camera/mode/index.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/camera/mode/index.js
@@ -366,7 +366,7 @@
   }
 
   /**
-   * Creates and updates new current mode object.
+   * Creates and updates current mode object.
    * @param {!Mode} mode Classname of mode to be updated.
    * @param {!ModeFactory} factory The factory ready for producing mode capture
    *     object.
@@ -392,6 +392,17 @@
   }
 
   /**
+   * Clears everything when mode is not needed anymore.
+   * @return {!Promise}
+   */
+  async clear() {
+    if (this.current !== null) {
+      await this.current.clear();
+    }
+    this.current = null;
+  }
+
+  /**
    * Checks whether to save image metadata or not.
    * @return {!Promise} Promise for the operation.
    * @private
diff --git a/chromeos/components/camera_app_ui/resources/js/views/camera/mode/mode_base.js b/chromeos/components/camera_app_ui/resources/js/views/camera/mode/mode_base.js
index ecf359b0..3c2fc93 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/camera/mode/mode_base.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/camera/mode/mode_base.js
@@ -79,12 +79,20 @@
   async addMetadataObserver() {}
 
   /**
-   * Remove the observer that saves metadata.
+   * Removes the observer that saves metadata.
    * @return {!Promise} Promise for the operation.
    */
   async removeMetadataObserver() {}
 
   /**
+   * Clears everything when mode is not needed anymore.
+   * @return {!Promise}
+   */
+  async clear() {
+    await this.stopCapture();
+  }
+
+  /**
    * Initiates video/photo capture operation under this mode.
    * @return {!Promise}
    * @protected
@@ -138,13 +146,6 @@
   }
 
   /**
-   * @param {!Resolution} resolution
-   */
-  setCaptureResolution(resolution) {
-    this.captureResolution_ = resolution;
-  }
-
-  /**
    * @param {!Facing} facing
    */
   setFacing(facing) {
@@ -164,10 +165,11 @@
    *     capture device.
    * @param {!MediaStreamConstraints} constraints Constraints for preview
    *     stream.
+   * @param {!Resolution} resolution Capture resolution
    * @return {!Promise}
    * @abstract
    */
-  prepareDevice(deviceOperator, constraints) {}
+  prepareDevice(deviceOperator, constraints, resolution) {}
 
   /**
    * @return {!ModeBase}
diff --git a/chromeos/components/camera_app_ui/resources/js/views/camera/mode/photo.js b/chromeos/components/camera_app_ui/resources/js/views/camera/mode/photo.js
index 8845bca4..b0b0df6 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/camera/mode/photo.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/camera/mode/photo.js
@@ -243,7 +243,8 @@
   /**
    * @override
    */
-  async prepareDevice(deviceOperator, constraints) {
+  async prepareDevice(deviceOperator, constraints, resolution) {
+    this.captureResolution_ = resolution;
     const deviceId = assertString(constraints.video.deviceId.exact);
     await deviceOperator.setCaptureIntent(
         deviceId, cros.mojom.CaptureIntent.STILL_CAPTURE);
diff --git a/chromeos/components/camera_app_ui/resources/js/views/camera/mode/video.js b/chromeos/components/camera_app_ui/resources/js/views/camera/mode/video.js
index fd3ebf8a..b10338c 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/camera/mode/video.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/camera/mode/video.js
@@ -3,7 +3,15 @@
 // found in the LICENSE file.
 
 import {AsyncJobQueue} from '../../../async_job_queue.js';
-import {assert, assertString} from '../../../chrome_util.js';
+import {
+  assert,
+  assertInstanceof,
+  assertString,
+} from '../../../chrome_util.js';
+import {
+  CaptureStream,
+  StreamManager,
+} from '../../../device/stream_manager.js';
 import * as dom from '../../../dom.js';
 // eslint-disable-next-line no-unused-vars
 import {EncoderParameters} from '../../../h264.js';
@@ -152,12 +160,12 @@
  */
 export class Video extends ModeBase {
   /**
-   * @param {!MediaStream} stream
+   * @param {!CaptureStream} stream
    * @param {!Facing} facing
    * @param {!VideoHandler} handler
    */
   constructor(stream, facing, handler) {
-    super(stream, facing, null);
+    super(stream.stream, facing, null);
 
     /**
      * @const {!VideoHandler}
@@ -198,6 +206,20 @@
      * Whether current recording ever paused/resumed before it ended.
      */
     this.everPaused_ = false;
+
+    /**
+     * @type {!CaptureStream}
+     * @private
+     */
+    this.captureStream_ = stream;
+  }
+
+  /**
+   * @override
+   */
+  async clear() {
+    await this.stopCapture();
+    await this.captureStream_.close();
   }
 
   /**
@@ -408,12 +430,20 @@
      * @private
      */
     this.handler_ = handler;
+
+    /**
+     * Stream for video capturing.
+     * @type {?CaptureStream}
+     * @private
+     */
+    this.captureStream_ = null;
   }
 
   /**
    * @override
    */
-  async prepareDevice(deviceOperator, constraints) {
+  async prepareDevice(deviceOperator, constraints, resolution) {
+    this.captureResolution_ = resolution;
     const deviceId = assertString(constraints.video.deviceId.exact);
     await deviceOperator.setCaptureIntent(
         deviceId, cros.mojom.CaptureIntent.VIDEO_RECORD);
@@ -434,12 +464,26 @@
       // range.
     }
     await deviceOperator.setFpsRange(deviceId, minFrameRate, maxFrameRate);
+
+    const captureConstraints = {
+      audio: constraints.audio,
+      video: {
+        deviceId: constraints.video.deviceId,
+        frameRate: constraints.video.frameRate,
+        width: resolution.width,
+        height: resolution.height,
+      },
+    };
+    this.captureStream_ =
+        await StreamManager.getInstance().openCaptureStream(captureConstraints);
   }
 
   /**
    * @override
    */
   produce_() {
-    return new Video(this.previewStream_, this.facing_, this.handler_);
+    return new Video(
+        assertInstanceof(this.captureStream_, CaptureStream), this.facing_,
+        this.handler_);
   }
 }
diff --git a/chromeos/components/camera_app_ui/resources/js/views/settings.js b/chromeos/components/camera_app_ui/resources/js/views/settings.js
index f9f4d1fb..c3e367c 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/settings.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/settings.js
@@ -262,7 +262,7 @@
     this.frontSetting_ = null;
 
     /**
-     * Device setting of back camera. Null if no front camera.
+     * Device setting of back camera. Null if no back camera.
      * @type {?DeviceSetting}
      * @private
      */
diff --git a/chromeos/crosapi/mojom/BUILD.gn b/chromeos/crosapi/mojom/BUILD.gn
index f3f4dc8..5df0b042 100644
--- a/chromeos/crosapi/mojom/BUILD.gn
+++ b/chromeos/crosapi/mojom/BUILD.gn
@@ -24,21 +24,16 @@
     "select_file.mojom",
     "test_controller.mojom",
     "url_handler.mojom",
-    "video_capture.mojom",
   ]
   disable_variants = true
 
   public_deps = [
     "//chromeos/components/sensors/mojom",
     "//chromeos/services/machine_learning/public/mojom",
-    "//media/capture/mojom:image_capture",
-    "//media/capture/mojom:video_capture_types",
     "//mojo/public/mojom/base",
     "//services/device/public/mojom:mojom",
     "//services/media_session/public/mojom:mojom",
-    "//ui/gfx/geometry/mojom",
     "//ui/gfx/image/mojom",
-    "//ui/gfx/mojom",
     "//url/mojom:url_mojom_gurl",
   ]
 }
diff --git a/chromeos/crosapi/mojom/crosapi.mojom b/chromeos/crosapi/mojom/crosapi.mojom
index e034a3e..317072e 100644
--- a/chromeos/crosapi/mojom/crosapi.mojom
+++ b/chromeos/crosapi/mojom/crosapi.mojom
@@ -21,7 +21,6 @@
 import "chromeos/crosapi/mojom/test_controller.mojom";
 import "chromeos/crosapi/mojom/url_handler.mojom";
 import "chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom";
-import "chromeos/crosapi/mojom/video_capture.mojom";
 import "mojo/public/mojom/base/big_string.mojom";
 import "mojo/public/mojom/base/file_path.mojom";
 import "mojo/public/mojom/base/token.mojom";
@@ -50,8 +49,8 @@
 // please note the milestone when you added it, to help us reason about
 // compatibility between the client applications and older ash-chrome binaries.
 //
-// Next version: 19
-// Next method id: 24
+// Next version: 18
+// Next method id: 23
 [Stable, Uuid="8b79c34f-2bf8-4499-979a-b17cac522c1e",
  RenamedFrom="crosapi.mojom.AshChromeService"]
 interface Crosapi {
@@ -168,11 +167,6 @@
   // Added in M90.
   [MinVersion=13] BindUrlHandler@18(pending_receiver<UrlHandler> receiver);
 
-  // Binds the device factory in video capture service.
-  // Added in M90.
-  [MinVersion=18] BindVideoCaptureDeviceFactory@23(
-      pending_receiver<crosapi.mojom.VideoCaptureDeviceFactory> receiver);
-
   // Passes generic browser information such as version, etc into ash in
   // |browser_info| during startup.
   // Added in M87.
diff --git a/chromeos/crosapi/mojom/video_capture.mojom b/chromeos/crosapi/mojom/video_capture.mojom
deleted file mode 100644
index 0719bc8..0000000
--- a/chromeos/crosapi/mojom/video_capture.mojom
+++ /dev/null
@@ -1,183 +0,0 @@
-// Copyright 2021 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.
-
-module crosapi.mojom;
-
-import "media/capture/mojom/image_capture.mojom";
-import "media/capture/mojom/video_capture_types.mojom";
-import "mojo/public/mojom/base/shared_memory.mojom";
-import "mojo/public/mojom/base/time.mojom";
-import "mojo/public/mojom/base/unguessable_token.mojom";
-import "ui/gfx/geometry/mojom/geometry.mojom";
-import "ui/gfx/mojom/native_handle_types.mojom";
-
-// This API is used to forward requests/respond of video_capture::DeviceFactory
-// and video_capture::Device from Lacros (Client) to the actual implementation
-// in Ash-Chrome.
-// In addition, to avoid affecting too much on non-Chrome OS components and
-// depends on components which will cause cyclic dependency, we used some
-// similar but simplified version of structures rather than directly depends on
-// the structures in other components.
-
-// Similar to |gfx.mojom.NativePixmapHandle| but does not contain fields which
-// are not available on Chrome OS.
-// Next min field ID: 2
-[Stable]
-struct NativePixmapHandle {
-  array<gfx.mojom.NativePixmapPlane> planes@0;
-
-  uint64 modifier@1;
-};
-
-// Similar to |gfx.mojom.GpuMemoryBufferPlatformHandle| but does not contain
-// fields which are not available on Chrome OS.
-// Next min field ID: 2
-[Stable]
-union GpuMemoryBufferPlatformHandle {
-  mojo_base.mojom.UnsafeSharedMemoryRegion shared_memory_handle@0;
-
-  NativePixmapHandle native_pixmap_handle@1;
-};
-
-// Similar to |gfx.mojom.GpuMemoryBufferHandle| but does not depend on
-// |gfx.mojom.GpuMemoryBufferPlatformHandle|.
-// Next min field ID: 4
-[Stable]
-struct GpuMemoryBufferHandle {
-  int32 id@0;
-
-  uint32 offset@1;
-
-  uint32 stride@2;
-
-  GpuMemoryBufferPlatformHandle? platform_handle@3;
-};
-
-// Similar to |media.mojom.VideoBufferHandle| but does not contain fields which
-// are not used in Chrome OS implementation.
-// Next min field ID: 2
-[Stable]
-union VideoBufferHandle {
-  handle<shared_buffer> shared_buffer_handle@0;
-
-  GpuMemoryBufferHandle gpu_memory_buffer_handle@1;
-};
-
-// Identical to |video_capture.mojom.DeviceAccessResultCode|.
-[Stable, Extensible]
-enum DeviceAccessResultCode {
-  NOT_INITIALIZED,
-  SUCCESS,
-  ERROR_DEVICE_NOT_FOUND
-};
-
-// Identical to |media.mojom.VideoRotation|.
-[Stable, Extensible]
-enum VideoRotation {
-  kVideoRotation0,
-  kVideoRotation90,
-  kVideoRotation180,
-  kVideoRotation270,
-};
-
-// Similar to |media.mojom.VideoFrameInfo| but without some fields which does
-// not implement on Chrome OS. In addition, since most of the fields in
-// |metadata| field is not used in Chrome OS implementation, we also simplify
-// the structure by only containing |rotation| and |reference_time|.
-// Next min field ID: 6
-[Stable]
-struct VideoFrameInfo {
-  mojo_base.mojom.TimeDelta timestamp@0;
-
-  media.mojom.VideoCapturePixelFormat pixel_format@1;
-
-  gfx.mojom.Size coded_size@2;
-
-  gfx.mojom.Rect visible_rect@3;
-
-  // The following fields are the fields we may use for constructing
-  // media::VideoFrameMetadata.
-  VideoRotation rotation@4;
-
-  mojo_base.mojom.TimeTicks reference_time@5;
-};
-
-// Similar to |video_capture.mojom.ReadyFrameInBuffer| but does not depend on
-// |media.mojom.VideoFrameInfo| and
-// |video_capture.mojom.ScopedAccessPermission|.
-// Next min field ID: 4
-[Stable]
-struct ReadyFrameInBuffer {
-  int32 buffer_id@0;
-
-  int32 frame_feedback_id@1;
-
-  pending_remote<ScopedAccessPermission> access_permission@2;
-
-  VideoFrameInfo frame_info@3;
-};
-
-// Identical to |video_capture.mojom.ScopedAccessPermission|.
-// Next min method ID: 0
-[Stable, Uuid="bf0f3239-26d2-45f8-9875-490563f5af97"]
-interface ScopedAccessPermission {};
-
-// Similar to |video_capture.mojom.VideoFrameHandler| but depends on simplified
-// structures.
-// Next min method ID: 9
-[Stable, Uuid="590ab36a-9162-4c9d-8429-1753108825ea"]
-interface VideoFrameHandler {
-  OnNewBuffer@0(int32 buffer_id, VideoBufferHandle buffer_handle);
-
-  OnFrameReadyInBuffer@1(ReadyFrameInBuffer buffer,
-                         array<ReadyFrameInBuffer> scaled_buffers);
-
-  OnBufferRetired@2(int32 buffer_id);
-
-  OnError@3(media.mojom.VideoCaptureError error);
-
-  OnFrameDropped@4(media.mojom.VideoCaptureFrameDropReason reason);
-
-  OnLog@5(string message);
-
-  OnStarted@6();
-
-  OnStartedUsingGpuDecode@7();
-
-  OnStopped@8();
-};
-
-// Similar to |video_capture.mojom.Device| but depends on simplified structures.
-// Next min method ID: 7
-[Stable, Uuid="f50f1672-d512-451e-9c70-998ed45ab596"]
-interface VideoCaptureDevice {
-  // It is assumed that it will be called only once.
-  Start@0(media.mojom.VideoCaptureParams requested_settings,
-          pending_remote<VideoFrameHandler> handler);
-
-  MaybeSuspend@1();
-
-  Resume@2();
-
-  GetPhotoState@3() => (media.mojom.PhotoState? capabilities);
-
-  SetPhotoOptions@4(media.mojom.PhotoSettings settings) => (bool success);
-
-  TakePhoto@5() => (media.mojom.Blob? blob);
-
-  ProcessFeedback@6(media.mojom.VideoFrameFeedback feedback);
-};
-
-// Similar to |video_capture.mojom.DeviceFactory| but depends on simplified
-// structures.
-// Next min method ID: 2
-[Stable, Uuid="b79ed8be-cf39-4d0d-a819-2d299022124a"]
-interface VideoCaptureDeviceFactory {
-  GetDeviceInfos@0()
-      => (array<media.mojom.VideoCaptureDeviceInfo> device_infos);
-
-  CreateDevice@1(string device_id,
-                 pending_receiver<VideoCaptureDevice> device_receiver)
-      => (DeviceAccessResultCode result_code);
-};
diff --git a/chromeos/dbus/power/power_manager_client.cc b/chromeos/dbus/power/power_manager_client.cc
index a5bc65c0..e5c48816 100644
--- a/chromeos/dbus/power/power_manager_client.cc
+++ b/chromeos/dbus/power/power_manager_client.cc
@@ -109,23 +109,23 @@
 }
 
 // Converts a ThermalState value from a power_manager::ThermalEvent proto to the
-// corresponding base::PowerObserver::DeviceThermalState value.
-base::PowerObserver::DeviceThermalState GetThermalStateFromProtoEnum(
+// corresponding base::PowerThermalObserver::DeviceThermalState value.
+base::PowerThermalObserver::DeviceThermalState GetThermalStateFromProtoEnum(
     power_manager::ThermalEvent::ThermalState state) {
   switch (state) {
     case power_manager::ThermalEvent_ThermalState_UNKNOWN:
-      return base::PowerObserver::DeviceThermalState::kUnknown;
+      return base::PowerThermalObserver::DeviceThermalState::kUnknown;
     case power_manager::ThermalEvent_ThermalState_NOMINAL:
-      return base::PowerObserver::DeviceThermalState::kNominal;
+      return base::PowerThermalObserver::DeviceThermalState::kNominal;
     case power_manager::ThermalEvent_ThermalState_FAIR:
-      return base::PowerObserver::DeviceThermalState::kFair;
+      return base::PowerThermalObserver::DeviceThermalState::kFair;
     case power_manager::ThermalEvent_ThermalState_SERIOUS:
-      return base::PowerObserver::DeviceThermalState::kSerious;
+      return base::PowerThermalObserver::DeviceThermalState::kSerious;
     case power_manager::ThermalEvent_ThermalState_CRITICAL:
-      return base::PowerObserver::DeviceThermalState::kCritical;
+      return base::PowerThermalObserver::DeviceThermalState::kCritical;
   }
   NOTREACHED() << "Unhandled thermal state " << state;
-  return base::PowerObserver::DeviceThermalState::kUnknown;
+  return base::PowerThermalObserver::DeviceThermalState::kUnknown;
 }
 
 // Callback for D-Bus call made in |CreateArcTimers|.
diff --git a/chromeos/dbus/power/power_manager_client_unittest.cc b/chromeos/dbus/power/power_manager_client_unittest.cc
index 8edc9da..70090da4 100644
--- a/chromeos/dbus/power/power_manager_client_unittest.cc
+++ b/chromeos/dbus/power/power_manager_client_unittest.cc
@@ -203,7 +203,7 @@
   using base::PowerMonitorTestObserver::PowerMonitorTestObserver;
 
   void OnThermalStateChange(
-      PowerObserver::DeviceThermalState new_state) override {
+      PowerThermalObserver::DeviceThermalState new_state) override {
     ASSERT_TRUE(cb);
     base::PowerMonitorTestObserver::OnThermalStateChange(new_state);
     std::move(cb).Run();
@@ -646,26 +646,30 @@
 // Tests that base::PowerMonitor observers are notified about thermal event.
 TEST_F(PowerManagerClientTest, ChangeThermalState) {
   PowerMonitorTestObserverLocal observer;
-  base::PowerMonitor::AddObserver(&observer);
+  base::PowerMonitor::AddPowerThermalObserver(&observer);
 
   base::PowerMonitor::Initialize(
       std::make_unique<base::PowerMonitorTestSource>());
 
   typedef struct {
     power_manager::ThermalEvent::ThermalState dbus_state;
-    base::PowerObserver::DeviceThermalState expected_state;
+    base::PowerThermalObserver::DeviceThermalState expected_state;
   } ThermalDBusTestType;
   ThermalDBusTestType thermal_states[] = {
       {.dbus_state = power_manager::ThermalEvent_ThermalState_UNKNOWN,
-       .expected_state = base::PowerObserver::DeviceThermalState::kUnknown},
+       .expected_state =
+           base::PowerThermalObserver::DeviceThermalState::kUnknown},
       {.dbus_state = power_manager::ThermalEvent_ThermalState_NOMINAL,
-       .expected_state = base::PowerObserver::DeviceThermalState::kNominal},
+       .expected_state =
+           base::PowerThermalObserver::DeviceThermalState::kNominal},
       {.dbus_state = power_manager::ThermalEvent_ThermalState_FAIR,
-       .expected_state = base::PowerObserver::DeviceThermalState::kFair},
+       .expected_state = base::PowerThermalObserver::DeviceThermalState::kFair},
       {.dbus_state = power_manager::ThermalEvent_ThermalState_SERIOUS,
-       .expected_state = base::PowerObserver::DeviceThermalState::kSerious},
+       .expected_state =
+           base::PowerThermalObserver::DeviceThermalState::kSerious},
       {.dbus_state = power_manager::ThermalEvent_ThermalState_CRITICAL,
-       .expected_state = base::PowerObserver::DeviceThermalState::kCritical},
+       .expected_state =
+           base::PowerThermalObserver::DeviceThermalState::kCritical},
   };
 
   for (const auto& p : thermal_states) {
@@ -686,7 +690,7 @@
     run_loop.Run();
   }
 
-  base::PowerMonitor::RemoveObserver(&observer);
+  base::PowerMonitor::RemovePowerThermalObserver(&observer);
   base::PowerMonitor::ShutdownForTesting();
 }
 
diff --git a/chromeos/dbus/userdataauth/fake_userdataauth_client.cc b/chromeos/dbus/userdataauth/fake_userdataauth_client.cc
index cc6fe75..da0bf22 100644
--- a/chromeos/dbus/userdataauth/fake_userdataauth_client.cc
+++ b/chromeos/dbus/userdataauth/fake_userdataauth_client.cc
@@ -12,10 +12,23 @@
 
 FakeUserDataAuthClient::~FakeUserDataAuthClient() = default;
 
+void FakeUserDataAuthClient::AddObserver(Observer* observer) {
+  NOTIMPLEMENTED();
+}
+
+void FakeUserDataAuthClient::RemoveObserver(Observer* observer) {
+  NOTIMPLEMENTED();
+}
+
 void FakeUserDataAuthClient::IsMounted(
     const ::user_data_auth::IsMountedRequest& request,
     IsMountedCallback callback) {
   NOTIMPLEMENTED();
 }
 
+void FakeUserDataAuthClient::WaitForServiceToBeAvailable(
+    chromeos::WaitForServiceToBeAvailableCallback callback) {
+  NOTIMPLEMENTED();
+}
+
 }  // namespace chromeos
diff --git a/chromeos/dbus/userdataauth/fake_userdataauth_client.h b/chromeos/dbus/userdataauth/fake_userdataauth_client.h
index 844c398..dc49dea 100644
--- a/chromeos/dbus/userdataauth/fake_userdataauth_client.h
+++ b/chromeos/dbus/userdataauth/fake_userdataauth_client.h
@@ -23,6 +23,10 @@
   FakeUserDataAuthClient& operator=(const FakeUserDataAuthClient&) = delete;
 
   // UserDataAuthClient override:
+  void AddObserver(Observer* observer) override;
+  void RemoveObserver(Observer* observer) override;
+  void WaitForServiceToBeAvailable(
+      chromeos::WaitForServiceToBeAvailableCallback callback) override;
   void IsMounted(const ::user_data_auth::IsMountedRequest& request,
                  IsMountedCallback callback) override;
 };
diff --git a/chromeos/dbus/userdataauth/userdataauth_client.cc b/chromeos/dbus/userdataauth/userdataauth_client.cc
index c920357..97b8756 100644
--- a/chromeos/dbus/userdataauth/userdataauth_client.cc
+++ b/chromeos/dbus/userdataauth/userdataauth_client.cc
@@ -49,6 +49,14 @@
   return true;
 }
 
+void OnSignalConnected(const std::string& interface_name,
+                       const std::string& signal_name,
+                       bool success) {
+  DCHECK_EQ(interface_name, ::user_data_auth::kUserDataAuthInterface);
+  LOG_IF(DFATAL, !success) << "Failed to connect to D-Bus signal; interface: "
+                           << interface_name << "; signal: " << signal_name;
+}
+
 // "Real" implementation of UserDataAuthClient talking to the cryptohomed's
 // UserDataAuth interface on the Chrome OS side.
 class UserDataAuthClientImpl : public UserDataAuthClient {
@@ -64,9 +72,24 @@
     proxy_ = bus->GetObjectProxy(
         ::user_data_auth::kUserDataAuthServiceName,
         dbus::ObjectPath(::user_data_auth::kUserDataAuthServicePath));
+    ConnectToSignals();
   }
 
   // UserDataAuthClient override:
+
+  void AddObserver(Observer* observer) override {
+    observer_list_.AddObserver(observer);
+  }
+
+  void RemoveObserver(Observer* observer) override {
+    observer_list_.RemoveObserver(observer);
+  }
+
+  void WaitForServiceToBeAvailable(
+      chromeos::WaitForServiceToBeAvailableCallback callback) override {
+    proxy_->WaitForServiceToBeAvailable(std::move(callback));
+  }
+
   void IsMounted(const ::user_data_auth::IsMountedRequest& request,
                  IsMountedCallback callback) override {
     CallProtoMethod(::user_data_auth::kIsMounted,
@@ -131,9 +154,55 @@
     std::move(callback).Run(reply_proto);
   }
 
+  void OnDircryptoMigrationProgress(dbus::Signal* signal) {
+    dbus::MessageReader reader(signal);
+    ::user_data_auth::DircryptoMigrationProgress proto;
+    if (!reader.PopArrayOfBytesAsProto(&proto)) {
+      LOG(ERROR) << "Failed to parse DircryptoMigrationProgress protobuf from "
+                    "UserDataAuth signal";
+      return;
+    }
+    for (auto& observer : observer_list_) {
+      observer.DircryptoMigrationProgress(proto);
+    }
+  }
+
+  void OnLowDiskSpace(dbus::Signal* signal) {
+    dbus::MessageReader reader(signal);
+    ::user_data_auth::LowDiskSpace proto;
+    if (!reader.PopArrayOfBytesAsProto(&proto)) {
+      LOG(ERROR)
+          << "Failed to parse LowDiskSpace protobuf from UserDataAuth signal";
+      return;
+    }
+    for (auto& observer : observer_list_) {
+      observer.LowDiskSpace(proto);
+    }
+  }
+
+  // Connects the dbus signals.
+  void ConnectToSignals() {
+    proxy_->ConnectToSignal(
+        ::user_data_auth::kUserDataAuthInterface,
+        ::user_data_auth::kDircryptoMigrationProgress,
+        base::BindRepeating(
+            &UserDataAuthClientImpl::OnDircryptoMigrationProgress,
+            weak_factory_.GetWeakPtr()),
+        base::BindOnce(&OnSignalConnected));
+    proxy_->ConnectToSignal(
+        ::user_data_auth::kUserDataAuthInterface,
+        ::user_data_auth::kLowDiskSpace,
+        base::BindRepeating(&UserDataAuthClientImpl::OnLowDiskSpace,
+                            weak_factory_.GetWeakPtr()),
+        base::BindOnce(&OnSignalConnected));
+  }
+
   // D-Bus proxy for cryptohomed, not owned.
   dbus::ObjectProxy* proxy_ = nullptr;
 
+  // List of observers for dbus signals.
+  base::ObserverList<Observer> observer_list_;
+
   base::WeakPtrFactory<UserDataAuthClientImpl> weak_factory_{this};
 };
 
diff --git a/chromeos/dbus/userdataauth/userdataauth_client.h b/chromeos/dbus/userdataauth/userdataauth_client.h
index fd5770d0..b1338b6 100644
--- a/chromeos/dbus/userdataauth/userdataauth_client.h
+++ b/chromeos/dbus/userdataauth/userdataauth_client.h
@@ -7,6 +7,7 @@
 
 #include "base/callback.h"
 #include "base/component_export.h"
+#include "base/observer_list_types.h"
 #include "chromeos/dbus/cryptohome/UserDataAuth.pb.h"
 #include "chromeos/dbus/dbus_method_call_status.h"
 
@@ -21,6 +22,19 @@
 // thread (UI thread) which initializes the DBusThreadManager instance.
 class COMPONENT_EXPORT(USERDATAAUTH_CLIENT) UserDataAuthClient {
  public:
+  class Observer : public base::CheckedObserver {
+   public:
+    // Called when LowDiskSpace signal is received, when the cryptohome
+    // partition is running out of disk space.
+    virtual void LowDiskSpace(const ::user_data_auth::LowDiskSpace& status) {}
+
+    // Called when DircryptoMigrationProgress signal is received.
+    // Typically, called periodically during a migration is performed by
+    // cryptohomed, as well as to notify the completion of migration.
+    virtual void DircryptoMigrationProgress(
+        const ::user_data_auth::DircryptoMigrationProgress& progress) {}
+  };
+
   using IsMountedCallback =
       DBusMethodCallback<::user_data_auth::IsMountedReply>;
 
@@ -40,8 +54,18 @@
   // Returns the global instance which may be null if not initialized.
   static UserDataAuthClient* Get();
 
+  // Adds an observer.
+  virtual void AddObserver(Observer* observer) = 0;
+
+  // Removes an observer if added.
+  virtual void RemoveObserver(Observer* observer) = 0;
+
   // Actual DBus Methods:
 
+  // Runs the callback as soon as the service becomes available.
+  virtual void WaitForServiceToBeAvailable(
+      WaitForServiceToBeAvailableCallback callback) = 0;
+
   // Queries if user's vault is mounted.
   virtual void IsMounted(const ::user_data_auth::IsMountedRequest& request,
                          IsMountedCallback callback) = 0;
diff --git a/chromeos/dbus/userdataauth/userdataauth_client_unittest.cc b/chromeos/dbus/userdataauth/userdataauth_client_unittest.cc
index cc258e7..1df1af74 100644
--- a/chromeos/dbus/userdataauth/userdataauth_client_unittest.cc
+++ b/chromeos/dbus/userdataauth/userdataauth_client_unittest.cc
@@ -19,6 +19,7 @@
 using ::testing::_;
 using ::testing::Invoke;
 using ::testing::Return;
+using ::testing::SaveArg;
 
 namespace chromeos {
 
@@ -31,6 +32,57 @@
   std::move(callback).Run(response.get());
 }
 
+bool ProtobufEquals(const google::protobuf::MessageLite& a,
+                    const google::protobuf::MessageLite& b) {
+  std::string a_serialized, b_serialized;
+  a.SerializeToString(&a_serialized);
+  b.SerializeToString(&b_serialized);
+  return a_serialized == b_serialized;
+}
+
+class TestObserver : public UserDataAuthClient::Observer {
+ public:
+  // UserDataAuthClient::Observer overrides
+  void LowDiskSpace(const ::user_data_auth::LowDiskSpace& status) override {
+    last_low_disk_space_.CopyFrom(status);
+    low_disk_space_count_++;
+  }
+
+  void DircryptoMigrationProgress(
+      const ::user_data_auth::DircryptoMigrationProgress& progress) override {
+    last_dircrypto_progress_.CopyFrom(progress);
+    dircrypto_progress_count_++;
+  }
+
+  const ::user_data_auth::LowDiskSpace& last_low_disk_space() const {
+    return last_low_disk_space_;
+  }
+
+  int low_disk_space_count() const { return low_disk_space_count_; }
+
+  const ::user_data_auth::DircryptoMigrationProgress& last_dircrypto_progress()
+      const {
+    return last_dircrypto_progress_;
+  }
+
+  int dircrypto_progress_count() const { return dircrypto_progress_count_; }
+
+ private:
+  // The protobuf that came with the signal when the last low disk space_ event
+  // came.
+  ::user_data_auth::LowDiskSpace last_low_disk_space_;
+
+  // The number of times the LowDiskSpace signal is triggered.
+  int low_disk_space_count_ = 0;
+
+  // The protobuf that came with the signal when the last dircrypto migration
+  // progress event came.
+  ::user_data_auth::DircryptoMigrationProgress last_dircrypto_progress_;
+
+  // The number of times the DircryptoMigrationProgress signal is triggered.
+  int dircrypto_progress_count_ = 0;
+};
+
 }  // namespace
 
 class UserDataAuthClientTest : public testing::Test {
@@ -59,6 +111,16 @@
     EXPECT_CALL(*proxy_.get(), DoCallMethod(_, _, _))
         .WillRepeatedly(Invoke(this, &UserDataAuthClientTest::OnCallMethod));
 
+    EXPECT_CALL(
+        *proxy_,
+        DoConnectToSignal(::user_data_auth::kUserDataAuthInterface,
+                          ::user_data_auth::kDircryptoMigrationProgress, _, _))
+        .WillOnce(SaveArg<2>(&dircrypto_progress_callback_));
+    EXPECT_CALL(*proxy_,
+                DoConnectToSignal(::user_data_auth::kUserDataAuthInterface,
+                                  ::user_data_auth::kLowDiskSpace, _, _))
+        .WillOnce(SaveArg<2>(&low_disk_space_callback_));
+
     UserDataAuthClient::Initialize(bus_.get());
 
     // Execute callbacks posted by `client_->Init()`.
@@ -70,6 +132,27 @@
   void TearDown() override { UserDataAuthClient::Shutdown(); }
 
  protected:
+  void EmitLowDiskSpaceSignal(const ::user_data_auth::LowDiskSpace& status) {
+    dbus::Signal signal(::user_data_auth::kUserDataAuthInterface,
+                        ::user_data_auth::kLowDiskSpace);
+    dbus::MessageWriter writer(&signal);
+    writer.AppendProtoAsArrayOfBytes(status);
+    // Emit the signal.
+    ASSERT_FALSE(low_disk_space_callback_.is_null());
+    low_disk_space_callback_.Run(&signal);
+  }
+
+  void EmitDircryptoMigrationProgressSignal(
+      const ::user_data_auth::DircryptoMigrationProgress& status) {
+    dbus::Signal signal(::user_data_auth::kUserDataAuthInterface,
+                        ::user_data_auth::kDircryptoMigrationProgress);
+    dbus::MessageWriter writer(&signal);
+    writer.AppendProtoAsArrayOfBytes(status);
+    // Emit the signal.
+    ASSERT_FALSE(dircrypto_progress_callback_.is_null());
+    dircrypto_progress_callback_.Run(&signal);
+  }
+
   base::test::SingleThreadTaskEnvironment task_environment_;
 
   // Mock bus and proxy for simulating calls.
@@ -109,6 +192,13 @@
         FROM_HERE, base::BindOnce(RunResponseCallback, std::move(*callback),
                                   std::move(response)));
   }
+
+  // Callback that delivers the Low Disk Space signal to the client when called.
+  dbus::ObjectProxy::SignalCallback low_disk_space_callback_;
+
+  // Callback that delivers the dircrypto Migration Progress signal to the
+  // client when called.
+  dbus::ObjectProxy::SignalCallback dircrypto_progress_callback_;
 };
 
 TEST_F(UserDataAuthClientTest, IsMounted) {
@@ -145,4 +235,63 @@
   ASSERT_EQ(result_reply, base::nullopt);
 }
 
+TEST_F(UserDataAuthClientTest, LowDiskSpaceSignal) {
+  constexpr uint64_t kFreeSpace1 = 0x1234567890123ULL;
+  constexpr uint64_t kFreeSpace2 = 0xFFFF9876ULL;
+
+  TestObserver observer;
+  client_->AddObserver(&observer);
+
+  ::user_data_auth::LowDiskSpace status;
+  status.set_disk_free_bytes(kFreeSpace1);
+
+  // Basic validity check, emit a signal and check.
+  EmitLowDiskSpaceSignal(status);
+  EXPECT_EQ(observer.low_disk_space_count(), 1);
+  EXPECT_EQ(observer.last_low_disk_space().disk_free_bytes(), kFreeSpace1);
+
+  // Try again to see nothing is stuck.
+  status.set_disk_free_bytes(kFreeSpace2);
+  EmitLowDiskSpaceSignal(status);
+  EXPECT_EQ(observer.low_disk_space_count(), 2);
+  EXPECT_EQ(observer.last_low_disk_space().disk_free_bytes(), kFreeSpace2);
+
+  // Remove the observer to check that it no longer gets triggered.
+  client_->RemoveObserver(&observer);
+  EmitLowDiskSpaceSignal(status);
+  EXPECT_EQ(observer.low_disk_space_count(), 2);
+}
+
+TEST_F(UserDataAuthClientTest, DircryptoMigrationProgressSignal) {
+  // Prepare the test constants.
+  constexpr uint64_t kTotalBytes = 0x1234567890123ULL;
+  ::user_data_auth::DircryptoMigrationProgress progress1, progress2;
+  progress1.set_status(::user_data_auth::DircryptoMigrationStatus::
+                           DIRCRYPTO_MIGRATION_IN_PROGRESS);
+  progress1.set_current_bytes(12345);
+  progress1.set_total_bytes(kTotalBytes);
+  progress2.set_status(
+      ::user_data_auth::DircryptoMigrationStatus::DIRCRYPTO_MIGRATION_SUCCESS);
+  progress2.set_current_bytes(kTotalBytes);
+  progress2.set_total_bytes(kTotalBytes);
+
+  TestObserver observer;
+  client_->AddObserver(&observer);
+
+  // Basic validity check, emit a signal and check.
+  EmitDircryptoMigrationProgressSignal(progress1);
+  EXPECT_EQ(observer.dircrypto_progress_count(), 1);
+  EXPECT_TRUE(ProtobufEquals(observer.last_dircrypto_progress(), progress1));
+
+  // Try again to see nothing is stuck.
+  EmitDircryptoMigrationProgressSignal(progress2);
+  EXPECT_EQ(observer.dircrypto_progress_count(), 2);
+  EXPECT_TRUE(ProtobufEquals(observer.last_dircrypto_progress(), progress2));
+
+  // Remove the observer to check that it no longer gets triggered.
+  client_->RemoveObserver(&observer);
+  EmitDircryptoMigrationProgressSignal(progress1);
+  EXPECT_EQ(observer.dircrypto_progress_count(), 2);
+}
+
 }  // namespace chromeos
diff --git a/chromeos/lacros/lacros_chrome_service_impl.cc b/chromeos/lacros/lacros_chrome_service_impl.cc
index 5a9ce0e3..b5dfbbf 100644
--- a/chromeos/lacros/lacros_chrome_service_impl.cc
+++ b/chromeos/lacros/lacros_chrome_service_impl.cc
@@ -309,13 +309,6 @@
     crosapi_->BindUrlHandler(std::move(pending_receiver));
   }
 
-  void BindVideoCaptureDeviceFactoryReceiver(
-      mojo::PendingReceiver<crosapi::mojom::VideoCaptureDeviceFactory>
-          pending_receiver) {
-    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-    crosapi_->BindVideoCaptureDeviceFactory(std::move(pending_receiver));
-  }
-
   base::WeakPtr<LacrosChromeServiceNeverBlockingState> GetWeakPtr() {
     return weak_factory_.GetWeakPtr();
   }
@@ -857,25 +850,6 @@
                         Crosapi::MethodMinVersions::kOnBrowserStartupMinVersion;
 }
 
-void LacrosChromeServiceImpl::BindVideoCaptureDeviceFactory(
-    mojo::PendingReceiver<crosapi::mojom::VideoCaptureDeviceFactory>
-        pending_receiver) {
-  DCHECK(IsVideoCaptureDeviceFactoryAvailable());
-
-  never_blocking_sequence_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&LacrosChromeServiceNeverBlockingState::
-                         BindVideoCaptureDeviceFactoryReceiver,
-                     weak_sequenced_state_, std::move(pending_receiver)));
-}
-
-bool LacrosChromeServiceImpl::IsVideoCaptureDeviceFactoryAvailable() const {
-  base::Optional<uint32_t> version = CrosapiVersion();
-  return version && version.value() >=
-                        Crosapi::MethodMinVersions::
-                            kBindVideoCaptureDeviceFactoryMinVersion;
-}
-
 int LacrosChromeServiceImpl::GetInterfaceVersion(
     base::Token interface_uuid) const {
   if (g_disable_all_crosapi_for_tests)
diff --git a/chromeos/lacros/lacros_chrome_service_impl.h b/chromeos/lacros/lacros_chrome_service_impl.h
index a93173a..7f90cfd 100644
--- a/chromeos/lacros/lacros_chrome_service_impl.h
+++ b/chromeos/lacros/lacros_chrome_service_impl.h
@@ -32,7 +32,6 @@
 #include "chromeos/crosapi/mojom/select_file.mojom.h"
 #include "chromeos/crosapi/mojom/test_controller.mojom.h"
 #include "chromeos/crosapi/mojom/url_handler.mojom.h"
-#include "chromeos/crosapi/mojom/video_capture.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
@@ -274,15 +273,6 @@
   // returns true.
   bool IsOnBrowserStartupAvailable() const;
 
-  // Binds video capture host.
-  void BindVideoCaptureDeviceFactory(
-      mojo::PendingReceiver<crosapi::mojom::VideoCaptureDeviceFactory>
-          pending_receiver);
-
-  // BindVideoCaptureDeviceFactory() can only be used if this method returns
-  // true.
-  bool IsVideoCaptureDeviceFactoryAvailable() const;
-
   // Returns BrowserInitParams which is passed from ash-chrome. On launching
   // lacros-chrome from ash-chrome, ash-chrome creates a memory backed file
   // serializes the BrowserInitParams to it, and the forked/executed
diff --git a/chromeos/services/ime/ime_decoder.cc b/chromeos/services/ime/ime_decoder.cc
index 110a8b33..2fbaa30e 100644
--- a/chromeos/services/ime/ime_decoder.cc
+++ b/chromeos/services/ime/ime_decoder.cc
@@ -72,10 +72,6 @@
     return;
   }
 
-  // TODO(b/172527471): Remove it when decoder DSO is uprevved.
-  createMainEntry_ = reinterpret_cast<ImeMainEntryCreateFn>(
-      library.GetFunctionPointer(IME_MAIN_ENTRY_CREATE_FN_NAME));
-
   // TODO(b/172527471): Create a macro to fetch function pointers.
   entry_points_.init_once = reinterpret_cast<ImeDecoderInitOnceFn>(
       library.GetFunctionPointer("ImeDecoderInitOnce"));
@@ -118,12 +114,6 @@
   return status_;
 }
 
-// TODO(b/172527471): Remove it when decoder DSO is uprevved.
-ImeEngineMainEntry* ImeDecoder::CreateMainEntry(ImeCrosPlatform* platform) {
-  DCHECK(createMainEntry_);
-  return createMainEntry_(platform);
-}
-
 ImeDecoder::EntryPoints ImeDecoder::GetEntryPoints() {
   DCHECK(status_ == Status::kSuccess);
   return entry_points_;
diff --git a/chromeos/services/ime/ime_decoder.h b/chromeos/services/ime/ime_decoder.h
index 1331d226..558357b 100644
--- a/chromeos/services/ime/ime_decoder.h
+++ b/chromeos/services/ime/ime_decoder.h
@@ -48,10 +48,6 @@
   // Return `Status::kSuccess` if the lib is successfully initialized.
   Status GetStatus() const;
 
-  // Returns an instance of ImeEngineMainEntry from the IME shared library.
-  // TODO(b/172527471): Remove it when decoder DSO is uprevved.
-  ImeEngineMainEntry* CreateMainEntry(ImeCrosPlatform* platform);
-
   // Returns entry points of the loaded decoder shared library.
   EntryPoints GetEntryPoints();
 
@@ -67,10 +63,6 @@
   // Result of IME decoder DSO initialization.
   base::Optional<base::ScopedNativeLibrary> library_;
 
-  // Function pointors from decoder DSO.
-  // TODO(b/172527471): Remove it when decoder DSO is uprevved.
-  ImeMainEntryCreateFn createMainEntry_;
-
   EntryPoints entry_points_;
 
   DISALLOW_COPY_AND_ASSIGN(ImeDecoder);
diff --git a/chromeos/services/ime/public/cpp/shared_lib/interfaces.h b/chromeos/services/ime/public/cpp/shared_lib/interfaces.h
index 694a6cb..415252a5 100644
--- a/chromeos/services/ime/public/cpp/shared_lib/interfaces.h
+++ b/chromeos/services/ime/public/cpp/shared_lib/interfaces.h
@@ -204,63 +204,39 @@
   virtual void Destroy() = 0;
 };
 
-// The main entry point of an IME shared library.
-//
-// This class is implemented in the shared library and processes messages from
-// clients of the IME service. The shared library will exposes its create
-// function to the IME service.
-// DEPRECATED: Will be removed soon.
-class ImeEngineMainEntry {
- protected:
-  virtual ~ImeEngineMainEntry() = default;
-
- public:
-  // Returns whether a specific IME is supported by this IME shared library.
-  // The argument is the specfiation name of an IME, and the caller should
-  // explicitly know the IME engine's naming rules.
-  virtual bool IsImeSupported(const char*) = 0;
-
-  // Activate an engine instance in the shared library with an IME specfiation
-  // name and a bound `ImeClientDelegate` which is used to create a channel from
-  // the engine instance to the IME client. The ownership of `ImeClientDelegate`
-  // will be passed to the Main Entry.
-  virtual bool ActivateIme(const char*, ImeClientDelegate*) = 0;
-
-  // Process data from an IME service in `ImeEngineMainEntry`.
-  // The data will be invalidated by IME service soon after this call.
-  virtual void Process(const uint8_t* data, size_t size) = 0;
-
-  // Destroy the `ImeEngineMainEntry` instance, which is called in IME service
-  // on demand.
-  virtual void Destroy() = 0;
-};
-
-// Create ImeEngineMainEntry instance from the IME engine shared library.
-//
-// Applications using IME engines must call this function before any others.
-// The caller will take ownership of the returned pointer and is responsible for
-// deleting the ImeEngineMainEntry by calling `Destroy` on it when it's done.
-//
-// The provided `Platform` must remain valid until the `ImeEngineMainEntry`
-// is destroyed.
-//
-// IME engine shared library must implement this function and export it with the
-// name defined in IME_MAIN_ENTRY_CREATE_FN_NAME.
-//
-// Returns an instance of ImeEngineMainEntry from the IME shared library.
-typedef ImeEngineMainEntry* (*ImeMainEntryCreateFn)(ImeCrosPlatform*);
-
 // For use when bridging logs logged in IME shared library to Chrome logging.
 typedef void (*ImeEngineLoggerSetterFn)(ChromeLoggerFunc);
 
-typedef void (*ImeDecoderInitOnceFn)(ImeCrosPlatform*);
-typedef bool (*ImeDecoderSupportsFn)(const char*);
-typedef bool (*ImeDecoderActivateImeFn)(const char*, ImeClientDelegate*);
-typedef void (*ImeDecoderProcessFn)(const uint8_t*, size_t);
-typedef void (*ImeDecoderCloseFn)();
+// Functions blow are exported by the IME decoder shared library that we expose
+// through a loader.
 
-// Defined name of ImeMainEntryCreateFn exported from shared library.
-#define IME_MAIN_ENTRY_CREATE_FN_NAME "CreateImeMainEntry"
+// Initialize the IME decoder.
+//
+// Any user of IME decoder must make a call on this function before any others.
+//
+// The provided `ImeCrosPlatform` must remain valid during the whole life of
+// shared libraray
+typedef void (*ImeDecoderInitOnceFn)(ImeCrosPlatform*);
+
+// Returns whether a specific IME is supported by this IME shared library.
+// The argument is the specfiation name of an IME, and the caller should
+// explicitly know the IME engine's naming rules.
+typedef bool (*ImeDecoderSupportsFn)(const char*);
+
+// Activate an IME instance in the shared library with an IME specfiation name
+// and a bound `ImeClientDelegate` which is a channel from the IME instance to
+// its client.
+//
+// The ownership of `ImeClientDelegate` will be passed to the IME instance.
+typedef bool (*ImeDecoderActivateImeFn)(const char*, ImeClientDelegate*);
+
+// Process IME events by the activated IME instance.
+// The data passed in  should be invalidated by the IME instance soon after it's
+// consumed.
+typedef void (*ImeDecoderProcessFn)(const uint8_t*, size_t);
+
+// Release resources used by the IME decoder.
+typedef void (*ImeDecoderCloseFn)();
 
 }  // namespace ime
 }  // namespace chromeos
diff --git a/chromeos/services/multidevice_setup/wifi_sync_feature_manager_impl.cc b/chromeos/services/multidevice_setup/wifi_sync_feature_manager_impl.cc
index e9d7de7..42cd31e6 100644
--- a/chromeos/services/multidevice_setup/wifi_sync_feature_manager_impl.cc
+++ b/chromeos/services/multidevice_setup/wifi_sync_feature_manager_impl.cc
@@ -95,7 +95,7 @@
 
   if (pref_service_->GetBoolean(kCanShowAnnouncementPrefName)) {
     session_manager::SessionManager::Get()->AddObserver(this);
-    base::PowerMonitor::AddObserver(this);
+    base::PowerMonitor::AddPowerSuspendObserver(this);
     did_register_session_observers_ = true;
   }
 
@@ -113,7 +113,7 @@
   device_sync_client_->RemoveObserver(this);
   if (did_register_session_observers_) {
     session_manager::SessionManager::Get()->RemoveObserver(this);
-    base::PowerMonitor::RemoveObserver(this);
+    base::PowerMonitor::RemovePowerSuspendObserver(this);
   }
 }
 
diff --git a/chromeos/services/multidevice_setup/wifi_sync_feature_manager_impl.h b/chromeos/services/multidevice_setup/wifi_sync_feature_manager_impl.h
index c2f4eb7..e36c0f6 100644
--- a/chromeos/services/multidevice_setup/wifi_sync_feature_manager_impl.h
+++ b/chromeos/services/multidevice_setup/wifi_sync_feature_manager_impl.h
@@ -36,7 +36,7 @@
     : public WifiSyncFeatureManager,
       public HostStatusProvider::Observer,
       public device_sync::DeviceSyncClient::Observer,
-      public base::PowerObserver,
+      public base::PowerSuspendObserver,
       public session_manager::SessionManagerObserver {
  public:
   class Factory {
@@ -88,7 +88,7 @@
   // SessionManagerObserver:
   void OnSessionStateChanged() override;
 
-  // PowerObserver:
+  // PowerSuspendObserver:
   void OnResume() override;
 
   // WifiSyncFeatureManager:
diff --git a/chromeos/timezone/timezone_resolver.cc b/chromeos/timezone/timezone_resolver.cc
index 15b5183..d4caab5 100644
--- a/chromeos/timezone/timezone_resolver.cc
+++ b/chromeos/timezone/timezone_resolver.cc
@@ -82,7 +82,8 @@
 
 // This class periodically refreshes location and timezone.
 // It should be destroyed to stop refresh.
-class TimeZoneResolver::TimeZoneResolverImpl : public base::PowerObserver {
+class TimeZoneResolver::TimeZoneResolverImpl
+    : public base::PowerSuspendObserver {
  public:
   explicit TimeZoneResolverImpl(const TimeZoneResolver* resolver);
 
@@ -91,7 +92,7 @@
   // This is called once after the object is created.
   void Start();
 
-  // PowerObserver implementation.
+  // PowerSuspendObserver implementation.
   void OnResume() override;
 
   // (Re)Starts timer.
@@ -269,7 +270,7 @@
   DCHECK(!resolver_->apply_timezone().is_null());
   DCHECK(!resolver_->delay_network_call().is_null());
 
-  base::PowerMonitor::AddObserver(this);
+  base::PowerMonitor::AddPowerSuspendObserver(this);
 
   const int64_t last_refresh_at_raw =
       resolver_->local_state()->GetInt64(kLastTimeZoneRefreshTime);
@@ -286,7 +287,7 @@
 }
 
 TimeZoneResolver::TimeZoneResolverImpl::~TimeZoneResolverImpl() {
-  base::PowerMonitor::RemoveObserver(this);
+  base::PowerMonitor::RemovePowerSuspendObserver(this);
 }
 
 void TimeZoneResolver::TimeZoneResolverImpl::Start() {
diff --git a/components/account_manager_core/account_manager_facade.h b/components/account_manager_core/account_manager_facade.h
index 6e3a4fc8..d770905 100644
--- a/components/account_manager_core/account_manager_facade.h
+++ b/components/account_manager_core/account_manager_facade.h
@@ -34,9 +34,9 @@
     ~Observer() override;
 
     // Invoked when an account is added or updated.
-    virtual void OnAccountUpserted(const AccountKey& account) = 0;
+    virtual void OnAccountUpserted(const Account& account) = 0;
     // Invoked when an account is removed.
-    virtual void OnAccountRemoved(const AccountKey& account) = 0;
+    virtual void OnAccountRemoved(const Account& account) = 0;
   };
 
   // The source UI surface used for launching the account addition /
diff --git a/components/account_manager_core/account_manager_facade_impl.cc b/components/account_manager_core/account_manager_facade_impl.cc
index 872a9e3..30bbae3 100644
--- a/components/account_manager_core/account_manager_facade_impl.cc
+++ b/components/account_manager_core/account_manager_facade_impl.cc
@@ -249,7 +249,7 @@
     return;
   }
   for (auto& observer : observer_list_) {
-    observer.OnAccountUpserted(maybe_account->key);
+    observer.OnAccountUpserted(maybe_account.value());
   }
 }
 
@@ -262,7 +262,7 @@
     return;
   }
   for (auto& observer : observer_list_) {
-    observer.OnAccountRemoved(maybe_account->key);
+    observer.OnAccountRemoved(maybe_account.value());
   }
 }
 
diff --git a/components/account_manager_core/account_manager_facade_impl_unittest.cc b/components/account_manager_core/account_manager_facade_impl_unittest.cc
index 11411c8..2771c81 100644
--- a/components/account_manager_core/account_manager_facade_impl_unittest.cc
+++ b/components/account_manager_core/account_manager_facade_impl_unittest.cc
@@ -162,8 +162,8 @@
   MockObserver& operator=(const MockObserver&) = delete;
   ~MockObserver() override = default;
 
-  MOCK_METHOD(void, OnAccountUpserted, (const AccountKey& account), (override));
-  MOCK_METHOD(void, OnAccountRemoved, (const AccountKey& account), (override));
+  MOCK_METHOD(void, OnAccountUpserted, (const Account& account), (override));
+  MOCK_METHOD(void, OnAccountRemoved, (const Account& account), (override));
 };
 
 MATCHER_P(AccountEq, expected_account, "") {
@@ -251,7 +251,7 @@
 
   Account account = CreateTestGaiaAccount(kTestAccountEmail);
   base::RunLoop run_loop;
-  EXPECT_CALL(observer, OnAccountUpserted(account.key))
+  EXPECT_CALL(observer, OnAccountUpserted(AccountEq(account)))
       .WillOnce(base::test::RunClosure(run_loop.QuitClosure()));
   account_manager().NotifyOnTokenUpsertedObservers(account);
   run_loop.Run();
@@ -265,7 +265,7 @@
 
   Account account = CreateTestGaiaAccount(kTestAccountEmail);
   base::RunLoop run_loop;
-  EXPECT_CALL(observer, OnAccountRemoved(account.key))
+  EXPECT_CALL(observer, OnAccountRemoved(AccountEq(account)))
       .WillOnce(base::test::RunClosure(run_loop.QuitClosure()));
   account_manager().NotifyOnAccountRemovedObservers(account);
   run_loop.Run();
diff --git a/components/browser_sync/profile_sync_components_factory_impl.cc b/components/browser_sync/profile_sync_components_factory_impl.cc
index 5c17ee5..f93914e 100644
--- a/components/browser_sync/profile_sync_components_factory_impl.cc
+++ b/components/browser_sync/profile_sync_components_factory_impl.cc
@@ -400,15 +400,16 @@
 
 std::unique_ptr<DataTypeManager>
 ProfileSyncComponentsFactoryImpl::CreateDataTypeManager(
+    syncer::ModelTypeSet initial_types,
     const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
         debug_info_listener,
     const DataTypeController::TypeMap* controllers,
     const syncer::DataTypeEncryptionHandler* encryption_handler,
     syncer::ModelTypeConfigurer* configurer,
     DataTypeManagerObserver* observer) {
-  return std::make_unique<DataTypeManagerImpl>(debug_info_listener, controllers,
-                                               encryption_handler, configurer,
-                                               observer);
+  return std::make_unique<DataTypeManagerImpl>(
+      initial_types, debug_info_listener, controllers, encryption_handler,
+      configurer, observer);
 }
 
 std::unique_ptr<syncer::SyncEngine>
diff --git a/components/browser_sync/profile_sync_components_factory_impl.h b/components/browser_sync/profile_sync_components_factory_impl.h
index ccce5c20..e3f28deb 100644
--- a/components/browser_sync/profile_sync_components_factory_impl.h
+++ b/components/browser_sync/profile_sync_components_factory_impl.h
@@ -71,6 +71,7 @@
 
   // SyncApiComponentFactory implementation:
   std::unique_ptr<syncer::DataTypeManager> CreateDataTypeManager(
+      syncer::ModelTypeSet initial_types,
       const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
           debug_info_listener,
       const syncer::DataTypeController::TypeMap* controllers,
diff --git a/components/download/internal/background_service/scheduler/battery_status_listener_impl.cc b/components/download/internal/background_service/scheduler/battery_status_listener_impl.cc
index e74bf55..d42874a 100644
--- a/components/download/internal/background_service/scheduler/battery_status_listener_impl.cc
+++ b/components/download/internal/background_service/scheduler/battery_status_listener_impl.cc
@@ -30,13 +30,13 @@
   observer_ = observer;
 
   DCHECK(base::PowerMonitor::IsInitialized());
-  base::PowerMonitor::AddObserver(this);
+  base::PowerMonitor::AddPowerStateObserver(this);
 
   UpdateBatteryPercentage(true);
 }
 
 void BatteryStatusListenerImpl::Stop() {
-  base::PowerMonitor::RemoveObserver(this);
+  base::PowerMonitor::RemovePowerStateObserver(this);
 }
 
 int BatteryStatusListenerImpl::GetBatteryPercentageInternal() {
diff --git a/components/download/internal/background_service/scheduler/battery_status_listener_impl.h b/components/download/internal/background_service/scheduler/battery_status_listener_impl.h
index 1efbcf4..8f95b93 100644
--- a/components/download/internal/background_service/scheduler/battery_status_listener_impl.h
+++ b/components/download/internal/background_service/scheduler/battery_status_listener_impl.h
@@ -14,7 +14,7 @@
 
 // Default implementation of BatteryStatusListener.
 class BatteryStatusListenerImpl : public BatteryStatusListener,
-                                  public base::PowerObserver {
+                                  public base::PowerStateObserver {
  public:
   explicit BatteryStatusListenerImpl(
       const base::TimeDelta& battery_query_interval);
@@ -35,7 +35,7 @@
   // |battery_query_interval_| when |force| is false.
   void UpdateBatteryPercentage(bool force);
 
-  // base::PowerObserver implementation.
+  // base::PowerStateObserver implementation.
   void OnPowerStateChange(bool on_battery_power) override;
 
   // Cached battery percentage.
diff --git a/components/embedder_support/android/metrics/android_metrics_service_client.cc b/components/embedder_support/android/metrics/android_metrics_service_client.cc
index 9f0e9fd..36070ac 100644
--- a/components/embedder_support/android/metrics/android_metrics_service_client.cc
+++ b/components/embedder_support/android/metrics/android_metrics_service_client.cc
@@ -484,6 +484,10 @@
   return AsProtobufChannel(version_info::android::GetChannel());
 }
 
+bool AndroidMetricsServiceClient::IsExtendedStableChannel() {
+  return false;  // Not supported on AndroidMetricsServiceClients.
+}
+
 std::string AndroidMetricsServiceClient::GetVersionString() {
   return metrics::GetVersionString();
 }
diff --git a/components/embedder_support/android/metrics/android_metrics_service_client.h b/components/embedder_support/android/metrics/android_metrics_service_client.h
index 4a193b3..d19fdae 100644
--- a/components/embedder_support/android/metrics/android_metrics_service_client.h
+++ b/components/embedder_support/android/metrics/android_metrics_service_client.h
@@ -139,6 +139,7 @@
   std::string GetApplicationLocale() override;
   bool GetBrand(std::string* brand_code) override;
   SystemProfileProto::Channel GetChannel() override;
+  bool IsExtendedStableChannel() override;
   std::string GetVersionString() override;
   void CollectFinalMetricsForLog(
       const base::OnceClosure done_callback) override;
diff --git a/components/full_restore/BUILD.gn b/components/full_restore/BUILD.gn
index dbc755f..0bc9c8df 100644
--- a/components/full_restore/BUILD.gn
+++ b/components/full_restore/BUILD.gn
@@ -9,6 +9,8 @@
     "app_launch_info.h",
     "app_restore_data.cc",
     "app_restore_data.h",
+    "arc_save_handler.cc",
+    "arc_save_handler.h",
     "full_restore_file_handler.cc",
     "full_restore_file_handler.h",
     "full_restore_info.cc",
diff --git a/components/full_restore/arc_save_handler.cc b/components/full_restore/arc_save_handler.cc
new file mode 100644
index 0000000..9984f24
--- /dev/null
+++ b/components/full_restore/arc_save_handler.cc
@@ -0,0 +1,89 @@
+// Copyright 2021 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/full_restore/arc_save_handler.h"
+
+#include "base/containers/contains.h"
+#include "components/full_restore/app_launch_info.h"
+#include "components/full_restore/full_restore_info.h"
+#include "components/full_restore/full_restore_save_handler.h"
+#include "components/full_restore/full_restore_utils.h"
+#include "components/full_restore/window_info.h"
+#include "ui/aura/window.h"
+
+namespace full_restore {
+
+ArcSaveHandler::ArcSaveHandler(const base::FilePath& profile_path)
+    : profile_path_(profile_path) {}
+
+ArcSaveHandler::~ArcSaveHandler() = default;
+
+void ArcSaveHandler::SaveAppLaunchInfo(AppLaunchInfoPtr app_launch_info) {
+  DCHECK(app_launch_info->arc_session_id.has_value());
+
+  // Save |app_launch_info| to |session_id_to_app_launch_info_|, and wait for
+  // the ARC task to be created.
+  int32_t session_id = app_launch_info->arc_session_id.value();
+  session_id_to_app_launch_info_[session_id] = std::move(app_launch_info);
+}
+
+void ArcSaveHandler::OnWindowInitialized(aura::Window* window) {
+  int32_t task_id = window->GetProperty(::full_restore::kWindowIdKey);
+  if (!base::Contains(task_id_to_app_id_, task_id))
+    return;
+
+  // If the task has been created, call OnAppLaunched to save the window
+  // information.
+  FullRestoreInfo::GetInstance()->OnAppLaunched(window);
+}
+
+void ArcSaveHandler::OnWindowDestroyed(aura::Window* window) {
+  int32_t task_id = window->GetProperty(::full_restore::kWindowIdKey);
+
+  auto task_it = task_id_to_app_id_.find(task_id);
+  if (task_it == task_id_to_app_id_.end())
+    return;
+
+  FullRestoreSaveHandler::GetInstance()->RemoveWindowInfo(
+      profile_path_, task_it->second, task_id);
+}
+
+void ArcSaveHandler::OnTaskCreated(const std::string& app_id,
+                                   int32_t task_id,
+                                   int32_t session_id) {
+  auto it = session_id_to_app_launch_info_.find(session_id);
+  if (it == session_id_to_app_launch_info_.end())
+    return;
+
+  task_id_to_app_id_[task_id] = app_id;
+
+  auto app_launch_info = std::move(it->second);
+  session_id_to_app_launch_info_.erase(it);
+
+  app_launch_info->window_id = task_id;
+  FullRestoreSaveHandler::GetInstance()->AddAppLaunchInfo(
+      profile_path_, std::move(app_launch_info));
+}
+
+void ArcSaveHandler::OnTaskDestroyed(int32_t task_id) {
+  auto it = task_id_to_app_id_.find(task_id);
+  if (it == task_id_to_app_id_.end())
+    return;
+
+  FullRestoreSaveHandler::GetInstance()->RemoveAppRestoreData(
+      profile_path_, it->second, task_id);
+
+  task_id_to_app_id_.erase(task_id);
+}
+
+int32_t ArcSaveHandler::GetArcSessionId() {
+  if (session_id_ >= kArcSessionIdOffsetForRestoredLaunching) {
+    LOG(WARNING) << "ARC session id is too large: " << session_id_;
+    session_id_ = 0;
+  }
+
+  return ++session_id_;
+}
+
+}  // namespace full_restore
diff --git a/components/full_restore/arc_save_handler.h b/components/full_restore/arc_save_handler.h
new file mode 100644
index 0000000..20d082b
--- /dev/null
+++ b/components/full_restore/arc_save_handler.h
@@ -0,0 +1,75 @@
+// Copyright 2021 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_FULL_RESTORE_ARC_SAVE_HANDLER_H_
+#define COMPONENTS_FULL_RESTORE_ARC_SAVE_HANDLER_H_
+
+#include <map>
+#include <memory>
+#include <utility>
+
+#include "base/component_export.h"
+#include "base/files/file_path.h"
+
+namespace aura {
+class Window;
+}
+
+namespace full_restore {
+
+struct AppLaunchInfo;
+
+// ArcSaveHandler is a helper class for FullRestoreSaveHandler to handle ARC app
+// windows special cases, e.g. ARC task creation, ARC session id, etc.
+class COMPONENT_EXPORT(FULL_RESTORE) ArcSaveHandler {
+ public:
+  using AppLaunchInfoPtr = std::unique_ptr<AppLaunchInfo>;
+
+  explicit ArcSaveHandler(const base::FilePath& profile_path);
+  ArcSaveHandler(const ArcSaveHandler&) = delete;
+  ArcSaveHandler& operator=(const ArcSaveHandler&) = delete;
+  ~ArcSaveHandler();
+
+  // Saves |app_launch_info| to |arc_session_id_to_app_launch_info_|, and wait
+  // for the ARC task to be created.
+  void SaveAppLaunchInfo(AppLaunchInfoPtr app_launch_info);
+
+  // Invoked when |window| is initialized.
+  void OnWindowInitialized(aura::Window* window);
+
+  // Invoked when |window| is destroyed.
+  void OnWindowDestroyed(aura::Window* window);
+
+  // Invoked when the task is created for an ARC app.
+  void OnTaskCreated(const std::string& app_id,
+                     int32_t task_id,
+                     int32_t session_id);
+
+  // Invoked when the task is destroyed for an ARC app.
+  void OnTaskDestroyed(int32_t task_id);
+
+  // Generates the ARC session id (0 - 1,000,000,000) for ARC apps.
+  int32_t GetArcSessionId();
+
+  const std::map<int32_t, std::string>& GetArcTaskIdMapForTesting() const {
+    return task_id_to_app_id_;
+  }
+
+ private:
+  // The user profile path for ARC app.
+  base::FilePath profile_path_;
+
+  int32_t session_id_ = 0;
+
+  // The map from the ARC session id to the app launch info.
+  std::map<int32_t, AppLaunchInfoPtr> session_id_to_app_launch_info_;
+
+  // The map from the task id to the app id. The task id is saved in the window
+  // property. This map is used to find the app id when save the window info.
+  std::map<int32_t, std::string> task_id_to_app_id_;
+};
+
+}  // namespace full_restore
+
+#endif  // COMPONENTS_FULL_RESTORE_ARC_SAVE_HANDLER_H_
diff --git a/components/full_restore/full_restore_read_handler.cc b/components/full_restore/full_restore_read_handler.cc
index 14fa02e..d63571c 100644
--- a/components/full_restore/full_restore_read_handler.cc
+++ b/components/full_restore/full_restore_read_handler.cc
@@ -121,37 +121,19 @@
   it->second->RemoveApp(app_id);
 }
 
-void FullRestoreReadHandler::RemoveAppRestoreData(
-    const base::FilePath& profile_path,
-    const std::string& app_id,
+std::unique_ptr<WindowInfo> FullRestoreReadHandler::GetWindowInfo(
     int32_t restore_window_id) {
-  auto it = profile_path_to_restore_data_.find(profile_path);
-  if (it == profile_path_to_restore_data_.end())
-    return;
+  // TODO(crbug.com/1146900): Handle ARC app windows.
 
-  it->second->RemoveAppRestoreData(app_id, restore_window_id);
-}
-
-bool FullRestoreReadHandler::HasWindowInfo(int32_t restore_window_id) {
   if (!SessionID::IsValidValue(restore_window_id))
-    return false;
+    return nullptr;
 
   auto it = window_id_to_app_restore_info_.find(restore_window_id);
   if (it == window_id_to_app_restore_info_.end())
-    return false;
-
-  return true;
-}
-
-std::unique_ptr<WindowInfo> FullRestoreReadHandler::GetWindowInfo(
-    const base::FilePath& profile_path,
-    const std::string& app_id,
-    int32_t restore_window_id) {
-  auto it = profile_path_to_restore_data_.find(profile_path);
-  if (it == profile_path_to_restore_data_.end())
     return nullptr;
 
-  return it->second->GetWindowInfo(app_id, restore_window_id);
+  return profile_path_to_restore_data_[it->second.first]->GetWindowInfo(
+      it->second.second, restore_window_id);
 }
 
 std::unique_ptr<WindowInfo> FullRestoreReadHandler::GetWindowInfo(
@@ -233,20 +215,6 @@
   arc_session_id_to_window_id_[arc_session_id] = window_id;
 }
 
-std::unique_ptr<WindowInfo> FullRestoreReadHandler::GetWindowInfo(
-    int32_t restore_window_id) {
-  if (!SessionID::IsValidValue(restore_window_id))
-    return nullptr;
-
-  auto it = window_id_to_app_restore_info_.find(restore_window_id);
-  if (it == window_id_to_app_restore_info_.end())
-    return nullptr;
-
-  const base::FilePath& profile_path = it->second.first;
-  const std::string& app_id = it->second.second;
-  return GetWindowInfo(profile_path, app_id, restore_window_id);
-}
-
 void FullRestoreReadHandler::OnGetRestoreData(
     const base::FilePath& profile_path,
     Callback callback,
@@ -267,14 +235,13 @@
   std::move(callback).Run(std::move(restore_data));
 }
 
-void FullRestoreReadHandler::RemoveAppRestoreData(int32_t window_id) {
+void FullRestoreReadHandler::RemoveAppRestoreData(int window_id) {
   auto it = window_id_to_app_restore_info_.find(window_id);
   if (it == window_id_to_app_restore_info_.end())
     return;
 
-  const base::FilePath& profile_path = it->second.first;
-  const std::string& app_id = it->second.second;
-  RemoveAppRestoreData(profile_path, app_id, window_id);
+  profile_path_to_restore_data_[it->second.first]->RemoveAppRestoreData(
+      it->second.second, window_id);
 
   window_id_to_app_restore_info_.erase(it);
 }
diff --git a/components/full_restore/full_restore_read_handler.h b/components/full_restore/full_restore_read_handler.h
index 5ec2be1d..3e7abcb 100644
--- a/components/full_restore/full_restore_read_handler.h
+++ b/components/full_restore/full_restore_read_handler.h
@@ -73,24 +73,8 @@
   // from |profile_path_to_restore_data_| for |profile_path| .
   void RemoveApp(const base::FilePath& profile_path, const std::string& app_id);
 
-  // Removes AppRestoreData from |profile_path| for |app_id| and
-  // |restore_window_id|.
-  void RemoveAppRestoreData(const base::FilePath& profile_path,
-                            const std::string& app_id,
-                            int32_t restore_window_id);
-
-  // Returns true if there is a window info for |restore_window_id| from the
-  // full restore file. Otherwise, returns false. This interface can't be used
-  // for Arc app windows.
-  bool HasWindowInfo(int32_t restore_window_id);
-
-  // Gets the window information from |profile_path| for |app_id| and
-  // |restore_window_id|.
-  std::unique_ptr<WindowInfo> GetWindowInfo(const base::FilePath& profile_path,
-                                            const std::string& app_id,
-                                            int32_t restore_window_id);
-
-  // Gets the window information for |window|.
+  // Gets the window information for |restore_window_id| or |window|.
+  std::unique_ptr<WindowInfo> GetWindowInfo(int32_t restore_window_id);
   std::unique_ptr<WindowInfo> GetWindowInfo(aura::Window* window);
 
   // Fetches the restore id for the window from RestoreData for the given
@@ -126,9 +110,6 @@
   }
 
  private:
-  // Gets the window information for |restore_window_id|.
-  std::unique_ptr<WindowInfo> GetWindowInfo(int32_t restore_window_id);
-
   // Invoked when reading the restore data from |profile_path| is finished, and
   // calls |callback| to notify that the reading operation is done.
   void OnGetRestoreData(const base::FilePath& profile_path,
@@ -136,7 +117,7 @@
                         std::unique_ptr<RestoreData>);
 
   // Removes AppRestoreData for |restore_window_id|.
-  void RemoveAppRestoreData(int32_t restore_window_id);
+  void RemoveAppRestoreData(int restore_window_id);
 
   // The current active user profile path.
   base::FilePath active_profile_path_;
@@ -146,9 +127,9 @@
       profile_path_to_restore_data_;
 
   // The map from the window id to the full restore file path and the
-  // app id. The window id is saved in the window property
+  // app id. The window id id is saved in the window property
   // |kRestoreWindowIdKey|. This map is used to find the file path and the app
-  // id when get the window info. This map is not used for ARC app windows.
+  // id when get the window info.
   std::map<int32_t, std::pair<base::FilePath, std::string>>
       window_id_to_app_restore_info_;
 
diff --git a/components/full_restore/full_restore_save_handler.cc b/components/full_restore/full_restore_save_handler.cc
index 4f313b6..6d3dbd4e 100644
--- a/components/full_restore/full_restore_save_handler.cc
+++ b/components/full_restore/full_restore_save_handler.cc
@@ -4,8 +4,6 @@
 
 #include "components/full_restore/full_restore_save_handler.h"
 
-#include <utility>
-
 #include "ash/public/cpp/app_types.h"
 #include "base/bind.h"
 #include "base/files/file_path.h"
@@ -49,6 +47,7 @@
 void FullRestoreSaveHandler::SetPrimaryProfilePath(
     const base::FilePath& profile_path) {
   primary_profile_path_ = profile_path;
+  arc_save_handler_ = std::make_unique<ArcSaveHandler>(primary_profile_path_);
 }
 
 void FullRestoreSaveHandler::SetActiveProfilePath(
@@ -57,22 +56,17 @@
 }
 
 void FullRestoreSaveHandler::OnWindowInitialized(aura::Window* window) {
-  int32_t window_id = window->GetProperty(::full_restore::kWindowIdKey);
-
   if (window->GetProperty(aura::client::kAppType) ==
       static_cast<int>(ash::AppType::ARC_APP)) {
-    task_id_to_app_window_info_[window_id].window = window;
     observed_windows_.AddObservation(window);
 
-    // If the task id has an app id, OnTaskCreated has been invoked, and the app
-    // launch info has been saved, so OnAppLaunched can be called to save the
-    // window info.
-    if (!task_id_to_app_window_info_[window_id].app_id.empty())
-      FullRestoreInfo::GetInstance()->OnAppLaunched(window);
+    if (arc_save_handler_)
+      arc_save_handler_->OnWindowInitialized(window);
 
     return;
   }
 
+  int32_t window_id = window->GetProperty(::full_restore::kWindowIdKey);
   if (!SessionID::IsValidValue(window_id))
     return;
 
@@ -118,13 +112,8 @@
 
   if (window->GetProperty(aura::client::kAppType) ==
       static_cast<int>(ash::AppType::ARC_APP)) {
-    auto it = task_id_to_app_window_info_.find(window_id);
-    if (it != task_id_to_app_window_info_.end()) {
-      // The window could be recreated, so only remove the window info. When the
-      // task is destroyed, the full restore data can be removed.
-      it->second.window = nullptr;
-      RemoveWindowInfo(primary_profile_path_, it->second.app_id, window_id);
-    }
+    if (arc_save_handler_)
+      arc_save_handler_->OnWindowDestroyed(window);
     return;
   }
 
@@ -141,11 +130,16 @@
 
   const std::string app_id = app_launch_info->app_id;
 
+  if (app_launch_info->arc_session_id.has_value()) {
+    if (arc_save_handler_)
+      arc_save_handler_->SaveAppLaunchInfo(std::move(app_launch_info));
+    return;
+  }
+
   if (!app_launch_info->window_id.has_value()) {
-    // For ARC apps and Chrome apps, save |app_launch_info| to
-    // |app_id_to_app_launch_infos_|, and wait for the task id or window
-    // initialized to get the window id.
-    app_id_to_app_launch_infos_[app_id][profile_path].emplace_back(
+    // For Chrome apps, save |app_launch_info| to |app_id_to_app_launch_infos_|,
+    // and wait for the window to be initialized to get the window id.
+    app_id_to_app_launch_infos_[app_id][profile_path].push_back(
         std::move(app_launch_info));
     return;
   }
@@ -200,35 +194,13 @@
 void FullRestoreSaveHandler::OnTaskCreated(const std::string& app_id,
                                            int32_t task_id,
                                            int32_t session_id) {
-  task_id_to_app_window_info_[task_id].app_id = app_id;
-
-  auto it = app_id_to_app_launch_infos_.find(app_id);
-  if (it == app_id_to_app_launch_infos_.end())
-    return;
-
-  auto launch_it = it->second.find(primary_profile_path_);
-  if (launch_it == it->second.end() || launch_it->second.empty())
-    return;
-
-  auto app_launch_info = std::move(*launch_it->second.begin());
-  app_launch_info->window_id = task_id;
-  it->second.erase(primary_profile_path_);
-  if (it->second.empty())
-    app_id_to_app_launch_infos_.erase(it);
-
-  AddAppLaunchInfo(primary_profile_path_, std::move(app_launch_info));
-
-  // If the window has been created, OnAppLaunched can be called to save the
-  // window info.
-  if (task_id_to_app_window_info_[task_id].window) {
-    FullRestoreInfo::GetInstance()->OnAppLaunched(
-        task_id_to_app_window_info_[task_id].window);
-  }
+  if (arc_save_handler_)
+    arc_save_handler_->OnTaskCreated(app_id, task_id, session_id);
 }
 
 void FullRestoreSaveHandler::OnTaskDestroyed(int32_t task_id) {
-  RemoveAppRestoreData(task_id);
-  task_id_to_app_window_info_.erase(task_id);
+  if (arc_save_handler_)
+    arc_save_handler_->OnTaskDestroyed(task_id);
 }
 
 void FullRestoreSaveHandler::Flush(const base::FilePath& profile_path) {
@@ -334,12 +306,9 @@
 }
 
 int32_t FullRestoreSaveHandler::GetArcSessionId() {
-  if (arc_session_id_ >= kArcSessionIdOffsetForRestoredLaunching) {
-    LOG(WARNING) << "ARC session id is too large: " << arc_session_id_;
-    arc_session_id_ = 0;
-  }
-
-  return ++arc_session_id_;
+  if (!arc_save_handler_)
+    return -1;
+  return arc_save_handler_->GetArcSessionId();
 }
 
 void FullRestoreSaveHandler::MaybeStartSaveTimer() {
diff --git a/components/full_restore/full_restore_save_handler.h b/components/full_restore/full_restore_save_handler.h
index 4806cef..e6d3412 100644
--- a/components/full_restore/full_restore_save_handler.h
+++ b/components/full_restore/full_restore_save_handler.h
@@ -8,12 +8,14 @@
 #include <map>
 #include <memory>
 #include <set>
+#include <utility>
 
 #include "base/component_export.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_multi_source_observation.h"
 #include "base/timer/timer.h"
+#include "components/full_restore/arc_save_handler.h"
 #include "ui/aura/env_observer.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_observer.h"
@@ -111,11 +113,6 @@
   base::OneShotTimer* GetTimerForTesting() { return &save_timer_; }
 
  private:
-  struct AppWindowInfo {
-    std::string app_id;
-    aura::Window* window;
-  };
-
   // Map from a profile path to AppLaunchInfos.
   using AppLaunchInfos = std::map<base::FilePath, std::list<AppLaunchInfoPtr>>;
 
@@ -162,9 +159,6 @@
   // path.
   std::map<std::string, AppLaunchInfos> app_id_to_app_launch_infos_;
 
-  // The map from the task id to the AppWindowInfo for ARC apps.
-  std::map<int, AppWindowInfo> task_id_to_app_window_info_;
-
   // The current active user profile path.
   base::FilePath active_profile_path_;
 
@@ -177,7 +171,7 @@
   // Records whether the saving process is running for a full restore file.
   std::set<base::FilePath> save_running_;
 
-  int32_t arc_session_id_ = 0;
+  std::unique_ptr<ArcSaveHandler> arc_save_handler_;
 
   base::ScopedMultiSourceObservation<aura::Window, aura::WindowObserver>
       observed_windows_{this};
diff --git a/components/full_restore/full_restore_utils.cc b/components/full_restore/full_restore_utils.cc
index 48bbd64..a63a4dd 100644
--- a/components/full_restore/full_restore_utils.cc
+++ b/components/full_restore/full_restore_utils.cc
@@ -38,6 +38,14 @@
   FullRestoreSaveHandler::GetInstance()->SaveWindowInfo(window_info);
 }
 
+std::unique_ptr<WindowInfo> GetWindowInfo(int32_t restore_window_id) {
+  if (!ash::features::IsFullRestoreEnabled())
+    return nullptr;
+
+  return FullRestoreReadHandler::GetInstance()->GetWindowInfo(
+      restore_window_id);
+}
+
 std::unique_ptr<WindowInfo> GetWindowInfo(aura::Window* window) {
   if (!ash::features::IsFullRestoreEnabled())
     return nullptr;
@@ -75,8 +83,8 @@
   if (!ash::features::IsFullRestoreEnabled())
     return false;
 
-  return FullRestoreReadHandler::GetInstance()->HasWindowInfo(
-      restore_window_id);
+  std::unique_ptr<WindowInfo> window_info = GetWindowInfo(restore_window_id);
+  return !!window_info;
 }
 
 void ModifyWidgetParams(int32_t restore_window_id,
diff --git a/components/full_restore/full_restore_utils.h b/components/full_restore/full_restore_utils.h
index 98290a13..8957331 100644
--- a/components/full_restore/full_restore_utils.h
+++ b/components/full_restore/full_restore_utils.h
@@ -70,7 +70,9 @@
 COMPONENT_EXPORT(FULL_RESTORE)
 void SaveWindowInfo(const WindowInfo& window_info);
 
-// Gets the window information from the full restore file for |window|.
+// Gets the window information from the full restore file.
+COMPONENT_EXPORT(FULL_RESTORE)
+std::unique_ptr<WindowInfo> GetWindowInfo(int32_t restore_window_id);
 COMPONENT_EXPORT(FULL_RESTORE)
 std::unique_ptr<WindowInfo> GetWindowInfo(aura::Window* window);
 
@@ -92,8 +94,7 @@
 void SetActiveProfilePath(const base::FilePath& profile_path);
 
 // Returns true if there is a window info for |restore_window_id| from the full
-// restore file. Otherwise, returns false. This interface can't be used for Arc
-// app windows.
+// restore file. Otherwise, returns false.
 COMPONENT_EXPORT(FULL_RESTORE)
 bool HasWindowInfo(int32_t restore_window_id);
 
diff --git a/components/gcm_driver/DEPS b/components/gcm_driver/DEPS
index 9c56017f..07ac22c 100644
--- a/components/gcm_driver/DEPS
+++ b/components/gcm_driver/DEPS
@@ -15,6 +15,7 @@
   # Whitelist specific headers from //google_apis/gaia. Contact
   # blundell@chromium.org if looking to add more.
   "+google_apis/gaia/core_account_id.h",
+  "+google_apis/gaia/gaia_constants.h",
   "+google_apis/gaia/gaia_oauth_client.h",
   "+google_apis/gaia/google_service_auth_error.h",
   "+google_apis/gcm",
diff --git a/components/gcm_driver/gcm_account_tracker.cc b/components/gcm_driver/gcm_account_tracker.cc
index 98edc8d..fec1e8c 100644
--- a/components/gcm_driver/gcm_account_tracker.cc
+++ b/components/gcm_driver/gcm_account_tracker.cc
@@ -19,6 +19,7 @@
 #include "components/signin/public/identity_manager/access_token_info.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
 #include "components/signin/public/identity_manager/scope_set.h"
+#include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "net/base/ip_endpoint.h"
 
@@ -26,10 +27,6 @@
 
 namespace {
 
-// Scopes needed by the OAuth2 access tokens.
-const char kGCMGroupServerScope[] = "https://www.googleapis.com/auth/gcm";
-const char kGCMCheckinServerScope[] =
-    "https://www.googleapis.com/auth/android_checkin";
 // Name of the GCM account tracker for fetching access tokens.
 const char kGCMAccountTrackerName[] = "gcm_account_tracker";
 // Minimum token validity when sending to GCM groups server.
@@ -290,8 +287,8 @@
   DCHECK_EQ(account_iter->second.state, TOKEN_NEEDED);
 
   signin::ScopeSet scopes;
-  scopes.insert(kGCMGroupServerScope);
-  scopes.insert(kGCMCheckinServerScope);
+  scopes.insert(GaiaConstants::kGCMGroupServerOAuth2Scope);
+  scopes.insert(GaiaConstants::kGCMCheckinServerOAuth2Scope);
 
   // NOTE: It is safe to use base::Unretained() here as |token_fetcher| is owned
   // by this object and guarantees that it will not invoke its callback after
diff --git a/components/language/content/browser/ulp_language_code_locator/BUILD.gn b/components/language/content/browser/ulp_language_code_locator/BUILD.gn
index 15547fe..9b711fdb 100644
--- a/components/language/content/browser/ulp_language_code_locator/BUILD.gn
+++ b/components/language/content/browser/ulp_language_code_locator/BUILD.gn
@@ -3,9 +3,11 @@
 # found in the LICENSE file.
 
 import("//build/config/compiler/compiler.gni")
+import("//build/config/python.gni")
 import("//testing/test.gni")
 
-action("ulp_serialized_to_static_c") {
+# TODO(crbug.com/1112471): Get this to run correctly under Python3.
+python2_action("ulp_serialized_to_static_c") {
   script = "ulp_serialized_to_static_c.py"
   inputs = [
     "geolanguage-data_rank0.bin",
diff --git a/components/metrics/metrics_log.cc b/components/metrics/metrics_log.cc
index cd308f5..cd0c8cc 100644
--- a/components/metrics/metrics_log.cc
+++ b/components/metrics/metrics_log.cc
@@ -183,6 +183,7 @@
 void MetricsLog::RecordCoreSystemProfile(MetricsServiceClient* client,
                                          SystemProfileProto* system_profile) {
   RecordCoreSystemProfile(client->GetVersionString(), client->GetChannel(),
+                          client->IsExtendedStableChannel(),
                           client->GetApplicationLocale(),
                           client->GetAppPackageName(), system_profile);
 
@@ -195,12 +196,15 @@
 void MetricsLog::RecordCoreSystemProfile(
     const std::string& version,
     metrics::SystemProfileProto::Channel channel,
+    bool is_extended_stable_channel,
     const std::string& application_locale,
     const std::string& package_name,
     SystemProfileProto* system_profile) {
   system_profile->set_build_timestamp(metrics::MetricsLog::GetBuildTime());
   system_profile->set_app_version(version);
   system_profile->set_channel(channel);
+  if (is_extended_stable_channel)
+    system_profile->set_is_extended_stable_channel(true);
   system_profile->set_application_locale(application_locale);
 
 #if defined(ADDRESS_SANITIZER) || DCHECK_IS_ON()
diff --git a/components/metrics/metrics_log.h b/components/metrics/metrics_log.h
index 2e47d87..e0b9f46 100644
--- a/components/metrics/metrics_log.h
+++ b/components/metrics/metrics_log.h
@@ -121,6 +121,7 @@
   static void RecordCoreSystemProfile(
       const std::string& version,
       metrics::SystemProfileProto::Channel channel,
+      bool is_extended_stable_channel,
       const std::string& application_locale,
       const std::string& package_name,
       SystemProfileProto* system_profile);
diff --git a/components/metrics/metrics_service_client.h b/components/metrics/metrics_service_client.h
index fcc3d63..9a925993 100644
--- a/components/metrics/metrics_service_client.h
+++ b/components/metrics/metrics_service_client.h
@@ -66,6 +66,9 @@
   // Returns the release channel (e.g. stable, beta, etc) of the application.
   virtual SystemProfileProto::Channel GetChannel() = 0;
 
+  // Returns true if the application is on the extended stable channel.
+  virtual bool IsExtendedStableChannel() = 0;
+
   // Returns the version of the application as a string.
   virtual std::string GetVersionString() = 0;
 
diff --git a/components/metrics/test/test_metrics_service_client.cc b/components/metrics/test/test_metrics_service_client.cc
index 576fd07..2be627da 100644
--- a/components/metrics/test/test_metrics_service_client.cc
+++ b/components/metrics/test/test_metrics_service_client.cc
@@ -50,6 +50,10 @@
   return SystemProfileProto::CHANNEL_BETA;
 }
 
+bool TestMetricsServiceClient::IsExtendedStableChannel() {
+  return false;
+}
+
 std::string TestMetricsServiceClient::GetVersionString() {
   return version_string_;
 }
diff --git a/components/metrics/test/test_metrics_service_client.h b/components/metrics/test/test_metrics_service_client.h
index c42ed34..8baaaca 100644
--- a/components/metrics/test/test_metrics_service_client.h
+++ b/components/metrics/test/test_metrics_service_client.h
@@ -33,6 +33,7 @@
   std::string GetApplicationLocale() override;
   bool GetBrand(std::string* brand_code) override;
   SystemProfileProto::Channel GetChannel() override;
+  bool IsExtendedStableChannel() override;
   std::string GetVersionString() override;
   void CollectFinalMetricsForLog(base::OnceClosure done_callback) override;
   std::unique_ptr<MetricsLogUploader> CreateUploader(
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc
index b303c20..af899b8 100644
--- a/components/password_manager/core/browser/password_manager.cc
+++ b/components/password_manager/core/browser/password_manager.cc
@@ -269,7 +269,8 @@
     const FormData& form_data,
     autofill::FieldRendererId generation_element_id,
     const std::u16string& password) {
-  PasswordFormManager* manager = GetMatchedManager(driver, form_data);
+  PasswordFormManager* manager =
+      GetMatchedManager(driver, form_data.unique_renderer_id);
   if (manager) {
     manager->OnGeneratedPasswordAccepted(form_data, generation_element_id,
                                          password);
@@ -285,7 +286,8 @@
     const FormData& form_data,
     const std::u16string& generated_password) {
   DCHECK(client_->IsSavingAndFillingEnabled(form_data.url));
-  PasswordFormManager* form_manager = GetMatchedManager(driver, form_data);
+  PasswordFormManager* form_manager =
+      GetMatchedManager(driver, form_data.unique_renderer_id);
   UMA_HISTOGRAM_BOOLEAN("PasswordManager.GeneratedFormHasNoFormManager",
                         !form_manager);
   if (form_manager)
@@ -296,20 +298,20 @@
                                                   const FormData& form_data) {
   DCHECK(client_->IsSavingAndFillingEnabled(form_data.url));
 
-  PasswordFormManager* form_manager = GetMatchedManager(driver, form_data);
+  PasswordFormManager* form_manager =
+      GetMatchedManager(driver, form_data.unique_renderer_id);
   if (form_manager)
     form_manager->PasswordNoLongerGenerated();
 }
 
 void PasswordManager::SetGenerationElementAndTypeForForm(
     password_manager::PasswordManagerDriver* driver,
-    const FormData& form_data,
+    FormRendererId form_id,
     FieldRendererId generation_element,
     autofill::password_generation::PasswordGenerationType type) {
-  DCHECK(client_->IsSavingAndFillingEnabled(form_data.url));
-
-  PasswordFormManager* form_manager = GetMatchedManager(driver, form_data);
+  PasswordFormManager* form_manager = GetMatchedManager(driver, form_id);
   if (form_manager) {
+    DCHECK(client_->IsSavingAndFillingEnabled(form_manager->GetURL()));
     form_manager->SetGenerationElement(generation_element);
     form_manager->SetGenerationPopupWasShown(type);
   }
@@ -465,7 +467,8 @@
 void PasswordManager::OnPasswordFormCleared(
     PasswordManagerDriver* driver,
     const autofill::FormData& form_data) {
-  PasswordFormManager* manager = GetMatchedManager(driver, form_data);
+  PasswordFormManager* manager =
+      GetMatchedManager(driver, form_data.unique_renderer_id);
   if (!manager || !manager->is_submitted() ||
       !manager->GetSubmittedForm()->IsPossibleChangePasswordForm()) {
     return;
@@ -605,7 +608,8 @@
     if (!client_->IsFillingEnabled(form_data.url))
       continue;
 
-    PasswordFormManager* manager = GetMatchedManager(driver, form_data);
+    PasswordFormManager* manager =
+        GetMatchedManager(driver, form_data.unique_renderer_id);
 
     if (manager) {
       // This extra filling is just duplicating redundancy that was in
@@ -666,7 +670,7 @@
   }
 
   PasswordFormManager* matched_manager =
-      GetMatchedManager(driver, submitted_form);
+      GetMatchedManager(driver, submitted_form.unique_renderer_id);
 
   auto availability =
       matched_manager
@@ -736,7 +740,8 @@
     const FormData& form,
     const std::u16string& generated_password,
     FieldRendererId generation_element) {
-  PasswordFormManager* form_manager = GetMatchedManager(driver, form);
+  PasswordFormManager* form_manager =
+      GetMatchedManager(driver, form.unique_renderer_id);
   UMA_HISTOGRAM_BOOLEAN("PasswordManager.GeneratedFormHasNoFormManager",
                         !form_manager);
 
@@ -1106,7 +1111,7 @@
     if (logger)
       logger->LogFormStructure(Logger::STRING_SERVER_PREDICTIONS, *form);
     FormData form_data = SimplifiedFormDataFromFormStructure(*form);
-    if (GetMatchedManager(driver, form_data)) {
+    if (GetMatchedManager(driver, form_data.unique_renderer_id)) {
       // The form manager is already created.
       continue;
     }
@@ -1174,7 +1179,7 @@
 // PasswordFormManager when PasswordFormManager is gone.
 PasswordFormManager* PasswordManager::GetMatchedManager(
     PasswordManagerDriver* driver,
-    const FormData& form) {
+    FormRendererId form_id) {
   for (auto& form_manager : form_managers_) {
 // Until support of cross-origin iframes is implemented, there is only one
 // driver on iOS. It needs to be set in order for filling to work.
@@ -1182,7 +1187,7 @@
     if (driver && !form_manager->GetDriver())
       form_manager->SetDriver(driver->AsWeakPtr());
 #endif
-    if (form_manager->DoesManage(form, driver))
+    if (form_manager->DoesManageAccordingToRendererId(form_id, driver))
       return form_manager.get();
   }
   return nullptr;
diff --git a/components/password_manager/core/browser/password_manager.h b/components/password_manager/core/browser/password_manager.h
index b25ec4d0..aeb1fc4 100644
--- a/components/password_manager/core/browser/password_manager.h
+++ b/components/password_manager/core/browser/password_manager.h
@@ -81,6 +81,11 @@
                                const autofill::FormData& form_data) override;
   void OnPasswordFormCleared(PasswordManagerDriver* driver,
                              const autofill::FormData& form_data) override;
+  void SetGenerationElementAndTypeForForm(
+      PasswordManagerDriver* driver,
+      autofill::FormRendererId form_id,
+      autofill::FieldRendererId generation_element,
+      autofill::password_generation::PasswordGenerationType type) override;
 #if defined(OS_IOS)
   void OnPasswordFormSubmittedNoChecksForiOS(
       PasswordManagerDriver* driver,
@@ -124,13 +129,6 @@
   void OnPasswordNoLongerGenerated(PasswordManagerDriver* driver,
                                    const autofill::FormData& form_data);
 
-  // Update the `generation_element` and `type` for `form_data`.
-  void SetGenerationElementAndTypeForForm(
-      PasswordManagerDriver* driver,
-      const autofill::FormData& form_data,
-      autofill::FieldRendererId generation_element,
-      autofill::password_generation::PasswordGenerationType type);
-
   // Called upon navigation to persist the state from |CredentialCache|
   // used to decide when to record
   // |PasswordManager.ResultOfSavingFlowAfterUnblacklistin|.
@@ -291,10 +289,10 @@
       const GURL& form_origin,
       BrowserSavePasswordProgressLogger* logger);
 
-  // Returns the manager which manages |form|. |driver| is needed to determine
-  // the match. Returns nullptr when no matched manager is found.
+  // Returns the manager which manages |form_id|. |driver| is needed to
+  // determine the match. Returns nullptr when no matched manager is found.
   PasswordFormManager* GetMatchedManager(PasswordManagerDriver* driver,
-                                         const autofill::FormData& form);
+                                         autofill::FormRendererId form_id);
 
   // Log a frame (main frame, iframe) of a submitted password form.
   void ReportSubmittedFormFrameMetric(const PasswordManagerDriver* driver,
diff --git a/components/password_manager/core/browser/password_manager_interface.h b/components/password_manager/core/browser/password_manager_interface.h
index f6155558..6dffdc14 100644
--- a/components/password_manager/core/browser/password_manager_interface.h
+++ b/components/password_manager/core/browser/password_manager_interface.h
@@ -46,6 +46,13 @@
   virtual void OnPasswordFormCleared(PasswordManagerDriver* driver,
                                      const autofill::FormData& form_data) = 0;
 
+  // Update the `generation_element` and `type` for `form_id`.
+  virtual void SetGenerationElementAndTypeForForm(
+      PasswordManagerDriver* driver,
+      autofill::FormRendererId form_id,
+      autofill::FieldRendererId generation_element,
+      autofill::password_generation::PasswordGenerationType type) = 0;
+
 #if defined(OS_IOS)
   // Handles a password form being submitted, assumes that submission is
   // successful and does not do any checks on success of submission. For
diff --git a/components/password_manager/core/browser/password_manager_unittest.cc b/components/password_manager/core/browser/password_manager_unittest.cc
index 193201e..a066475 100644
--- a/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_unittest.cc
@@ -2157,7 +2157,8 @@
   manager()->OnPasswordFormsParsed(&driver_, {form.form_data});
 
   manager()->SetGenerationElementAndTypeForForm(
-      &driver_, form.form_data, form.form_data.fields[1].unique_renderer_id,
+      &driver_, form.form_data.unique_renderer_id,
+      form.form_data.fields[1].unique_renderer_id,
       autofill::password_generation::PasswordGenerationType::kAutomatic);
   EXPECT_CALL(*store_, AddLogin(_));
   manager()->OnPresaveGeneratedPassword(&driver_, form.form_data,
diff --git a/components/password_manager/ios/shared_password_controller.mm b/components/password_manager/ios/shared_password_controller.mm
index 1328383..75d1b81 100644
--- a/components/password_manager/ios/shared_password_controller.mm
+++ b/components/password_manager/ios/shared_password_controller.mm
@@ -24,6 +24,7 @@
 #include "components/autofill/core/common/form_data.h"
 #include "components/autofill/core/common/password_form_fill_data.h"
 #include "components/autofill/core/common/password_form_generation_data.h"
+#include "components/autofill/core/common/password_generation_util.h"
 #include "components/autofill/core/common/renderer_id.h"
 #include "components/autofill/core/common/signatures.h"
 #include "components/autofill/ios/browser/autofill_util.h"
@@ -57,6 +58,8 @@
 using autofill::FormData;
 using autofill::FormRendererId;
 using autofill::PasswordFormGenerationData;
+using autofill::password_generation::LogPasswordGenerationEvent;
+using autofill::password_generation::PasswordGenerationType;
 using base::SysNSStringToUTF16;
 using base::SysUTF16ToNSString;
 using base::SysUTF8ToNSString;
@@ -169,6 +172,8 @@
   if (!_lastFocusedFieldIdentifier) {
     return;
   }
+  LogPasswordGenerationEvent(
+      autofill::password_generation::PASSWORD_GENERATION_CONTEXT_MENU_PRESSED);
   [self generatePasswordForFormId:_lastFocusedFormIdentifier
                   fieldIdentifier:_lastFocusedFieldIdentifier
               isManuallyTriggered:YES];
@@ -293,6 +298,8 @@
     // flow and avoid the manual flow, for a cleaner and simpler UI.
     if (formQuery.typedValue.length < kMinimumLengthForEditedPassword) {
       self.isPasswordGenerated = NO;
+      LogPasswordGenerationEvent(
+          autofill::password_generation::PASSWORD_DELETED);
       self.passwordGeneratedIdentifier = FieldRendererId();
       _passwordManager->OnPasswordNoLongerGenerated(
           _delegate.passwordManagerDriver);
@@ -606,6 +613,8 @@
        showGeneratedPotentialPassword:self.generatedPotentialPassword
                       decisionHandler:^(BOOL accept) {
                         if (accept) {
+                          LogPasswordGenerationEvent(
+                              autofill::password_generation::PASSWORD_ACCEPTED);
                           [weakSelf
                               injectGeneratedPasswordForFormId:formIdentifier
                                              generatedPassword:
@@ -617,6 +626,11 @@
                           completionHandler();
                         }
                       }];
+
+  _passwordManager->SetGenerationElementAndTypeForForm(
+      _delegate.passwordManagerDriver, formIdentifier, fieldIdentifier,
+      isManuallyTriggered ? PasswordGenerationType::kManual
+                          : PasswordGenerationType::kAutomatic);
 }
 
 - (void)injectGeneratedPasswordForFormId:(FormRendererId)formIdentifier
diff --git a/components/password_manager/ios/shared_password_controller_unittest.mm b/components/password_manager/ios/shared_password_controller_unittest.mm
index 8079018..02ead83 100644
--- a/components/password_manager/ios/shared_password_controller_unittest.mm
+++ b/components/password_manager/ios/shared_password_controller_unittest.mm
@@ -4,6 +4,7 @@
 
 #import "components/password_manager/ios/shared_password_controller.h"
 
+#include "base/test/metrics/histogram_tester.h"
 #include "components/autofill/core/browser/ui/popup_item_ids.h"
 #include "components/autofill/core/common/form_data.h"
 #include "components/autofill/core/common/password_form_generation_data.h"
@@ -57,6 +58,13 @@
               (PasswordManagerDriver*, const autofill::FormData&),
               (override));
   MOCK_METHOD(void,
+              SetGenerationElementAndTypeForForm,
+              (PasswordManagerDriver*,
+               autofill::FormRendererId,
+               autofill::FieldRendererId,
+               autofill::password_generation::PasswordGenerationType),
+              (override));
+  MOCK_METHOD(void,
               OnPasswordFormSubmittedNoChecksForiOS,
               (PasswordManagerDriver*, const autofill::FormData&),
               (override));
@@ -356,6 +364,7 @@
   [[delegate_ expect] sharedPasswordController:controller_
                 showGeneratedPotentialPassword:[OCMArg isNotNil]
                                decisionHandler:[OCMArg any]];
+  EXPECT_CALL(password_manager_, SetGenerationElementAndTypeForForm);
 
   [controller_ didSelectSuggestion:suggestion
                               form:@"test-form-name"
@@ -370,6 +379,7 @@
 
 // Tests that generated passwords are presaved.
 TEST_F(SharedPasswordControllerTest, PresavesGeneratedPassword) {
+  base::HistogramTester histogram_tester;
   autofill::FormRendererId form_id(0);
   autofill::FieldRendererId field_id(1);
   autofill::PasswordFormGenerationData form_generation_data = {
@@ -414,6 +424,7 @@
             completionHandler:extract_completion_handler_arg];
 
   EXPECT_CALL(password_manager_, PresaveGeneratedPassword);
+  EXPECT_CALL(password_manager_, SetGenerationElementAndTypeForForm);
 
   [controller_ didSelectSuggestion:suggestion
                               form:@"test-form-name"
@@ -424,11 +435,15 @@
                  completionHandler:nil];
 
   [delegate_ verify];
+  histogram_tester.ExpectUniqueSample(
+      "PasswordGeneration.Event",
+      autofill::password_generation::PASSWORD_ACCEPTED, 1);
 }
 
 // Tests that triggering password generation on the last focused field triggers
 // the generation flow.
 TEST_F(SharedPasswordControllerTest, TriggerPasswordGeneration) {
+  base::HistogramTester histogram_tester;
   autofill::FormActivityParams params;
   params.unique_form_id = autofill::FormRendererId(0);
   params.field_type = "password";
@@ -445,10 +460,15 @@
   [[delegate_ expect] sharedPasswordController:controller_
                 showGeneratedPotentialPassword:[OCMArg isNotNil]
                                decisionHandler:[OCMArg any]];
+  EXPECT_CALL(password_manager_, SetGenerationElementAndTypeForForm);
 
   [controller_ triggerPasswordGeneration];
 
   [delegate_ verify];
+  histogram_tester.ExpectUniqueSample(
+      "PasswordGeneration.Event",
+      autofill::password_generation::PASSWORD_GENERATION_CONTEXT_MENU_PRESSED,
+      1);
 }
 
 // Tests that triggering password generation on the last focused field does not
diff --git a/components/performance_manager/v8_memory/v8_context_tracker_browsertest.cc b/components/performance_manager/v8_memory/v8_context_tracker_browsertest.cc
index b506a664..d724983 100644
--- a/components/performance_manager/v8_memory/v8_context_tracker_browsertest.cc
+++ b/components/performance_manager/v8_memory/v8_context_tracker_browsertest.cc
@@ -110,7 +110,10 @@
     auto* ec_state = v8_context_tracker->GetExecutionContextState(
         frame_node->GetFrameToken());
     ASSERT_TRUE(ec_state);
-    ASSERT_TRUE(ec_state->iframe_attribution_data);
+    ASSERT_TRUE(ec_state->iframe_attribution_data)
+        << "url " << frame_node->GetURL() << ", current "
+        << frame_node->IsCurrent() << ", state "
+        << frame_node->GetLifecycleState();
   });
 }
 
diff --git a/components/policy/core/common/cloud/user_cloud_policy_store.cc b/components/policy/core/common/cloud/user_cloud_policy_store.cc
index 9597e36a..93401a3 100644
--- a/components/policy/core/common/cloud/user_cloud_policy_store.cc
+++ b/components/policy/core/common/cloud/user_cloud_policy_store.cc
@@ -203,9 +203,6 @@
 
 void DesktopCloudPolicyStore::PolicyLoaded(bool validate_in_background,
                                            PolicyLoadResult result) {
-  // TODO(zmin): figure out what do with the metrics. https://crbug.com/814371
-  UMA_HISTOGRAM_ENUMERATION("Enterprise.UserCloudPolicyStore.LoadStatus",
-                            result.status, LOAD_RESULT_SIZE);
   switch (result.status) {
     case LOAD_RESULT_LOAD_ERROR:
       status_ = STATUS_LOAD_ERROR;
@@ -308,10 +305,6 @@
     bool doing_key_rotation,
     const std::string& signing_key,
     UserCloudPolicyValidator* validator) {
-  // TODO(zmin): metrics
-  UMA_HISTOGRAM_ENUMERATION(
-      "Enterprise.UserCloudPolicyStore.LoadValidationStatus",
-      validator->status(), CloudPolicyValidatorBase::VALIDATION_STATUS_SIZE);
   validation_result_ = validator->GetValidationResult();
   if (!validator->success()) {
     DVLOG(1) << "Validation failed: status=" << validator->status();
@@ -356,9 +349,6 @@
 
 void DesktopCloudPolicyStore::OnPolicyToStoreValidated(
     UserCloudPolicyValidator* validator) {
-  UMA_HISTOGRAM_ENUMERATION(
-      "Enterprise.UserCloudPolicyStore.StoreValidationStatus",
-      validator->status(), CloudPolicyValidatorBase::VALIDATION_STATUS_SIZE);
   validation_result_ = validator->GetValidationResult();
   DVLOG(1) << "Policy validation complete: status = " << validator->status();
   if (!validator->success()) {
diff --git a/components/power_scheduler/power_mode_arbiter.cc b/components/power_scheduler/power_mode_arbiter.cc
index 6e53dc67..fad1748d 100644
--- a/components/power_scheduler/power_mode_arbiter.cc
+++ b/components/power_scheduler/power_mode_arbiter.cc
@@ -25,18 +25,18 @@
 // Created and owned by the arbiter on thread pool initialization because there
 // has to be exactly one per process, and //base can't depend on the
 // power_scheduler component.
-class PowerModeArbiter::ChargingPowerModeVoter : base::PowerObserver {
+class PowerModeArbiter::ChargingPowerModeVoter : base::PowerStateObserver {
  public:
   ChargingPowerModeVoter()
       : charging_voter_(PowerModeArbiter::GetInstance()->NewVoter(
             "PowerModeVoter.Charging")) {
-    base::PowerMonitor::AddObserver(this);
+    base::PowerMonitor::AddPowerStateObserver(this);
     if (base::PowerMonitor::IsInitialized())
       OnPowerStateChange(base::PowerMonitor::IsOnBatteryPower());
   }
 
   ~ChargingPowerModeVoter() override {
-    base::PowerMonitor::RemoveObserver(this);
+    base::PowerMonitor::RemovePowerStateObserver(this);
   }
 
   void OnPowerStateChange(bool on_battery_power) override {
diff --git a/components/search_engines/template_url_fetcher.cc b/components/search_engines/template_url_fetcher.cc
index 9af4b042..775366d5 100644
--- a/components/search_engines/template_url_fetcher.cc
+++ b/components/search_engines/template_url_fetcher.cc
@@ -124,7 +124,6 @@
   auto resource_request = std::make_unique<network::ResourceRequest>();
   resource_request->url = osdd_url;
   resource_request->request_initiator = initiator;
-  resource_request->render_frame_id = render_frame_id;
   // TODO(crbug.com/1059639): Remove |resource_type| once the request is handled
   // with RequestDestination without ResourceType.
   resource_request->resource_type =
diff --git a/components/security_interstitials/content/cert_logger.proto b/components/security_interstitials/content/cert_logger.proto
index 5cc4ee61..4447c80 100644
--- a/components/security_interstitials/content/cert_logger.proto
+++ b/components/security_interstitials/content/cert_logger.proto
@@ -265,6 +265,14 @@
   // calls done during verification.
   repeated MacTrustFlags mac_combined_trust_debug_info = 7;
 
+  enum MacTrustImplType {
+    MAC_TRUST_IMPL_UNKNOWN = 0;
+    MAC_TRUST_IMPL_DOMAIN_CACHE = 1;
+    MAC_TRUST_IMPL_SIMPLE = 2;
+    MAC_TRUST_IMPL_MRU_CACHE = 3;
+  };
+  optional MacTrustImplType mac_trust_impl = 13;
+
   // The time (in usec since the Windows epoch) when the trial verifier
   // attempted to verify the chain.
   optional int64 trial_verification_time_usec = 8;
diff --git a/components/security_interstitials/content/certificate_error_report.cc b/components/security_interstitials/content/certificate_error_report.cc
index ae77b68..bf0b3af 100644
--- a/components/security_interstitials/content/certificate_error_report.cc
+++ b/components/security_interstitials/content/certificate_error_report.cc
@@ -147,6 +147,23 @@
       report_cert_info->add_status_codes(code);
   }
 }
+
+chrome_browser_ssl::TrialVerificationInfo::MacTrustImplType
+TrustImplTypeFromMojom(
+    network::mojom::CertVerifierDebugInfo::MacTrustImplType input) {
+  switch (input) {
+    case network::mojom::CertVerifierDebugInfo::MacTrustImplType::kUnknown:
+      return chrome_browser_ssl::TrialVerificationInfo::MAC_TRUST_IMPL_UNKNOWN;
+    case network::mojom::CertVerifierDebugInfo::MacTrustImplType::kDomainCache:
+      return chrome_browser_ssl::TrialVerificationInfo::
+          MAC_TRUST_IMPL_DOMAIN_CACHE;
+    case network::mojom::CertVerifierDebugInfo::MacTrustImplType::kSimple:
+      return chrome_browser_ssl::TrialVerificationInfo::MAC_TRUST_IMPL_SIMPLE;
+    case network::mojom::CertVerifierDebugInfo::MacTrustImplType::kMruCache:
+      return chrome_browser_ssl::TrialVerificationInfo::
+          MAC_TRUST_IMPL_MRU_CACHE;
+  }
+}
 #endif  // defined(OS_APPLE)
 #endif  // BUILDFLAG(TRIAL_COMPARISON_CERT_VERIFIER_SUPPORTED)
 
@@ -223,6 +240,8 @@
   AddMacTrustFlagsToReport(
       debug_info->mac_combined_trust_debug_info,
       trial_report->mutable_mac_combined_trust_debug_info());
+  trial_report->set_mac_trust_impl(
+      TrustImplTypeFromMojom(debug_info->mac_trust_impl));
 #endif
   if (!debug_info->trial_verification_time.is_null()) {
     trial_report->set_trial_verification_time_usec(
diff --git a/components/security_interstitials/content/certificate_error_report_unittest.cc b/components/security_interstitials/content/certificate_error_report_unittest.cc
index 8433e169..afc743e 100644
--- a/components/security_interstitials/content/certificate_error_report_unittest.cc
+++ b/components/security_interstitials/content/certificate_error_report_unittest.cc
@@ -368,6 +368,8 @@
   debug_info->mac_combined_trust_debug_info =
       net::TrustStoreMac::TRUST_SETTINGS_DICT_CONTAINS_APPLICATION |
       net::TrustStoreMac::TRUST_SETTINGS_DICT_CONTAINS_RESULT;
+  debug_info->mac_trust_impl =
+      network::mojom::CertVerifierDebugInfo::MacTrustImplType::kMruCache;
 #endif
   base::Time time = base::Time::Now();
   debug_info->trial_verification_time = time;
@@ -427,8 +429,12 @@
   EXPECT_EQ(chrome_browser_ssl::TrialVerificationInfo::
                 MAC_TRUST_SETTINGS_DICT_CONTAINS_RESULT,
             trial_info.mac_combined_trust_debug_info()[1]);
+  EXPECT_TRUE(trial_info.has_mac_trust_impl());
+  EXPECT_EQ(chrome_browser_ssl::TrialVerificationInfo::MAC_TRUST_IMPL_MRU_CACHE,
+            trial_info.mac_trust_impl());
 #else
   EXPECT_EQ(0, trial_info.mac_combined_trust_debug_info_size());
+  EXPECT_FALSE(trial_info.has_mac_trust_impl());
 #endif
   ASSERT_TRUE(trial_info.has_trial_verification_time_usec());
   EXPECT_EQ(time.ToDeltaSinceWindowsEpoch().InMicroseconds(),
diff --git a/components/signin/internal/identity_manager/account_tracker_service.cc b/components/signin/internal/identity_manager/account_tracker_service.cc
index f96293076..68944ea7 100644
--- a/components/signin/internal/identity_manager/account_tracker_service.cc
+++ b/components/signin/internal/identity_manager/account_tracker_service.cc
@@ -19,7 +19,6 @@
 #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 "base/threading/scoped_blocking_call.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
@@ -443,9 +442,8 @@
     return;
   for (const auto& pair : accounts_) {
     const CoreAccountId& account_id = pair.second.account_id;
-    PostTaskAndReplyWithResult(
-        image_storage_task_runner_.get(), FROM_HERE,
-        base::BindOnce(&ReadImage, GetImagePathFor(account_id)),
+    image_storage_task_runner_->PostTaskAndReplyWithResult(
+        FROM_HERE, base::BindOnce(&ReadImage, GetImagePathFor(account_id)),
         base::BindOnce(&AccountTrackerService::OnAccountImageLoaded,
                        weak_factory_.GetWeakPtr(), account_id));
   }
@@ -458,8 +456,8 @@
   if (!image_storage_task_runner_)
     return;
 
-  PostTaskAndReplyWithResult(
-      image_storage_task_runner_.get(), FROM_HERE,
+  image_storage_task_runner_->PostTaskAndReplyWithResult(
+      FROM_HERE,
       base::BindOnce(&SaveImage, image.As1xPNGBytes(),
                      GetImagePathFor(account_id)),
       base::BindOnce(&AccountTrackerService::OnAccountImageUpdated,
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/AccountTrackerService.java b/components/signin/public/android/java/src/org/chromium/components/signin/AccountTrackerService.java
index 1c83ad0..c27b8fd8 100644
--- a/components/signin/public/android/java/src/org/chromium/components/signin/AccountTrackerService.java
+++ b/components/signin/public/android/java/src/org/chromium/components/signin/AccountTrackerService.java
@@ -19,6 +19,8 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Android wrapper of AccountTrackerService which provides access from the java layer.
@@ -81,7 +83,7 @@
                     || mSystemAccountsChanged)
                 && mSystemAccountsSeedingStatus
                         != SystemAccountsSeedingStatus.SEEDING_IN_PROGRESS) {
-            seedSystemAccounts();
+            seedAccounts();
         }
         return false;
     }
@@ -112,7 +114,7 @@
         mSystemAccountsSeedingObservers.removeObserver(observer);
     }
 
-    private void seedSystemAccounts() {
+    private void seedAccounts() {
         ThreadUtils.assertOnUiThread();
         mSystemAccountsChanged = false;
         final AccountManagerFacade accountManagerFacade =
@@ -131,54 +133,42 @@
         }
 
         accountManagerFacade.tryGetGoogleAccounts(accounts -> {
-            new AsyncTask<String[][]>() {
+            final List<String> emails = AccountUtils.toAccountNames(accounts);
+            new AsyncTask<List<String>>() {
                 @Override
-                public String[][] doInBackground() {
+                public List<String> doInBackground() {
                     Log.d(TAG, "Getting id/email mapping");
-
-                    long seedingStartTime = SystemClock.elapsedRealtime();
-
-                    String[][] accountIdNameMap = new String[2][accounts.size()];
-                    for (int i = 0; i < accounts.size(); ++i) {
-                        accountIdNameMap[0][i] =
-                                accountManagerFacade.getAccountGaiaId(accounts.get(i).name);
-                        accountIdNameMap[1][i] = accounts.get(i).name;
+                    final long seedingStartTime = SystemClock.elapsedRealtime();
+                    final List<String> gaiaIds = new ArrayList<>();
+                    for (String email : emails) {
+                        final String gaiaId = accountManagerFacade.getAccountGaiaId(email);
+                        if (gaiaId == null) {
+                            return gaiaIds;
+                        }
+                        gaiaIds.add(gaiaId);
                     }
-
                     RecordHistogram.recordTimesHistogram("Signin.AndroidGetAccountIdsTime",
                             SystemClock.elapsedRealtime() - seedingStartTime);
-
-                    return accountIdNameMap;
+                    return gaiaIds;
                 }
                 @Override
-                public void onPostExecute(String[][] accountIdNameMap) {
-                    if (mSystemAccountsChanged) {
-                        seedSystemAccounts();
-                        return;
-                    }
-                    if (areAccountIdsValid(accountIdNameMap[0])) {
-                        AccountTrackerServiceJni.get().seedAccountsInfo(
-                                mNativeAccountTrackerService, accountIdNameMap[0],
-                                accountIdNameMap[1]);
-                        mSystemAccountsSeedingStatus = SystemAccountsSeedingStatus.SEEDING_DONE;
-                        notifyObserversOnSeedingComplete();
+                public void onPostExecute(List<String> gaiaIds) {
+                    if (mSystemAccountsChanged || gaiaIds.size() < emails.size()) {
+                        seedAccounts();
                     } else {
-                        Log.w(TAG, "Invalid mapping of id/email");
-                        seedSystemAccounts();
+                        finishSeedingAccounts(gaiaIds, emails);
                     }
                 }
             }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
         });
     }
 
-    private boolean areAccountIdsValid(String[] accountIds) {
-        for (String accountId : accountIds) {
-            if (accountId == null) return false;
-        }
-        return true;
-    }
-
-    private void notifyObserversOnSeedingComplete() {
+    private void finishSeedingAccounts(List<String> gaiaIds, List<String> emails) {
+        assert gaiaIds.size() == emails.size() : "gaia IDs and emails should have the same size!";
+        AccountTrackerServiceJni.get().seedAccountsInfo(mNativeAccountTrackerService,
+                gaiaIds.toArray(new String[0]), emails.toArray(new String[0]));
+        mSystemAccountsSeedingStatus = SystemAccountsSeedingStatus.SEEDING_DONE;
+        // TODO(crbug/1187458): Download account information in the end of account seeding
         for (OnSystemAccountsSeededListener observer : mSystemAccountsSeedingObservers) {
             observer.onSystemAccountsSeedingComplete();
         }
@@ -203,7 +193,6 @@
 
     @NativeMethods
     interface Natives {
-        void seedAccountsInfo(
-                long nativeAccountTrackerService, String[] gaiaIds, String[] accountNames);
+        void seedAccountsInfo(long nativeAccountTrackerService, String[] gaiaIds, String[] emails);
     }
 }
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/ProfileOAuth2TokenServiceDelegateTest.java b/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/ProfileOAuth2TokenServiceDelegateTest.java
index ec7a9725..846098d2 100644
--- a/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/ProfileOAuth2TokenServiceDelegateTest.java
+++ b/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/ProfileOAuth2TokenServiceDelegateTest.java
@@ -4,6 +4,9 @@
 
 package org.chromium.components.signin.identitymanager;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -17,13 +20,14 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.Spy;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
+import org.mockito.quality.Strictness;
 
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Batch;
-import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.JniMocker;
 import org.chromium.components.signin.AccessTokenData;
 import org.chromium.components.signin.AccountTrackerService;
@@ -31,6 +35,7 @@
 import org.chromium.components.signin.test.util.FakeAccountManagerFacade;
 
 import java.util.Arrays;
+import java.util.List;
 import java.util.concurrent.CountDownLatch;
 
 /** Tests for {@link ProfileOAuth2TokenServiceDelegate}. */
@@ -38,20 +43,22 @@
 @Batch(Batch.UNIT_TESTS)
 public class ProfileOAuth2TokenServiceDelegateTest {
     private static final long NATIVE_DELEGATE = 1000L;
+    private static final Account ACCOUNT = AccountUtils.createAccountFromName("test@gmail.com");
+
     /**
      * Class handling GetAccessToken callbacks and providing a blocking {@link
      * #getToken()}.
      */
-    private static class GetAccessTokenCallbackForTest
+    private static class CustomGetAccessTokenCallback
             implements ProfileOAuth2TokenServiceDelegate.GetAccessTokenCallback {
         private String mToken;
-        final CountDownLatch mTokenRetrievedCountDown = new CountDownLatch(1);
+        private final CountDownLatch mTokenRetrievedCountDown = new CountDownLatch(1);
 
         /**
          * Blocks until the callback is called once and returns the token.
          * See {@link CountDownLatch#await}
          */
-        public String getToken() {
+        String getToken() {
             try {
                 mTokenRetrievedCountDown.await();
             } catch (InterruptedException e) {
@@ -74,7 +81,7 @@
     }
 
     @Rule
-    public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+    public final MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
 
     @Rule
     public final JniMocker mocker = new JniMocker();
@@ -85,6 +92,9 @@
     @Mock
     private ProfileOAuth2TokenServiceDelegate.Natives mNativeMock;
 
+    private final CustomGetAccessTokenCallback mTokenCallback = new CustomGetAccessTokenCallback();
+
+    @Spy
     private final FakeAccountManagerFacade mAccountManagerFacade =
             new FakeAccountManagerFacade(null);
 
@@ -99,85 +109,74 @@
 
     @Test
     @SmallTest
-    @Feature({"Sync"})
     public void testGetAccountsNoAccountsRegistered() {
-        String[] sysAccounts = mDelegate.getSystemAccountNames();
-        Assert.assertEquals("There should be no accounts registered", 0, sysAccounts.length);
+        Assert.assertArrayEquals(new String[] {}, mDelegate.getSystemAccountNames());
     }
 
     @Test
     @SmallTest
-    @Feature({"Sync"})
     public void testGetAccountsOneAccountRegistered() {
-        Account account1 = AccountUtils.createAccountFromName("foo@gmail.com");
-        mAccountManagerFacade.addAccount(account1);
-
-        String[] sysAccounts = mDelegate.getSystemAccountNames();
-        Assert.assertEquals("There should be one registered account", 1, sysAccounts.length);
-        Assert.assertEquals("The account should be " + account1, account1.name, sysAccounts[0]);
+        mAccountManagerFacade.addAccount(ACCOUNT);
+        Assert.assertArrayEquals(new String[] {ACCOUNT.name}, mDelegate.getSystemAccountNames());
     }
 
     @Test
     @SmallTest
-    @Feature({"Sync"})
     public void testGetAccountsTwoAccountsRegistered() {
-        Account account1 = AccountUtils.createAccountFromName("foo@gmail.com");
-        mAccountManagerFacade.addAccount(account1);
-        Account account2 = AccountUtils.createAccountFromName("bar@gmail.com");
+        mAccountManagerFacade.addAccount(ACCOUNT);
+        final Account account2 = AccountUtils.createAccountFromName("bar@gmail.com");
         mAccountManagerFacade.addAccount(account2);
 
-        String[] sysAccounts = mDelegate.getSystemAccountNames();
-        Assert.assertEquals("There should be two registered account", 2, sysAccounts.length);
-        Assert.assertTrue("The list should contain " + account1,
-                Arrays.asList(sysAccounts).contains(account1.name));
-        Assert.assertTrue("The list should contain " + account2,
-                Arrays.asList(sysAccounts).contains(account2.name));
+        final List<String> accounts = Arrays.asList(mDelegate.getSystemAccountNames());
+        Assert.assertEquals("There should be two registered account", 2, accounts.size());
+        Assert.assertTrue("The list should contain " + ACCOUNT, accounts.contains(ACCOUNT.name));
+        Assert.assertTrue("The list should contain " + account2, accounts.contains(account2.name));
     }
 
     @Test
     @SmallTest
-    @Feature({"Sync"})
-    public void testGetOAuth2AccessTokenWithTimeoutOnSuccess() {
-        String authToken = "someToken";
-        // Auth token should be successfully received.
-        runTestOfGetOAuth2AccessTokenWithTimeout(authToken);
-    }
-
-    @Test
-    @SmallTest
-    @Feature({"Sync"})
-    public void testGetOAuth2AccessTokenWithTimeoutOnError() {
-        String authToken = null;
-        // Should not crash when auth token is null.
-        runTestOfGetOAuth2AccessTokenWithTimeout(authToken);
-    }
-
-    private void runTestOfGetOAuth2AccessTokenWithTimeout(String expectedToken) {
-        String scope = "oauth2:http://example.com/scope";
-        Account account = AccountUtils.createAccountFromName("test@gmail.com");
-        mAccountManagerFacade.addAccount(account);
-        GetAccessTokenCallbackForTest callback = new GetAccessTokenCallbackForTest();
+    public void testGetOAuth2AccessTokenOnSuccess() {
+        final String scope = "oauth2:http://example.com/scope";
+        mAccountManagerFacade.addAccount(ACCOUNT);
+        final AccessTokenData expectedToken = mAccountManagerFacade.getAccessToken(ACCOUNT, scope);
 
         ThreadUtils.runOnUiThreadBlocking(
-                () -> { mDelegate.getAccessToken(account, scope, callback); });
+                () -> { mDelegate.getAccessToken(ACCOUNT, scope, mTokenCallback); });
+        Assert.assertEquals(expectedToken.getToken(), mTokenCallback.getToken());
+    }
 
-        Assert.assertEquals(mAccountManagerFacade.getAccessToken(account, scope).getToken(),
-                callback.getToken());
+    @Test
+    @SmallTest
+    public void testGetOAuth2AccessTokenOnFailure() {
+        final String scope = "oauth2:http://example.com/scope";
+        mAccountManagerFacade.addAccount(ACCOUNT);
+        doReturn(null).when(mAccountManagerFacade).getAccessToken(any(Account.class), anyString());
+
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> { mDelegate.getAccessToken(ACCOUNT, scope, mTokenCallback); });
+        Assert.assertNull(mTokenCallback.getToken());
     }
 
     @Test
     @SmallTest
     public void testHasOAuth2RefreshTokenWhenAccountIsNotOnDevice() {
-        mAccountManagerFacade.addAccount(AccountUtils.createAccountFromName("test1@gmail.com"));
+        mAccountManagerFacade.addAccount(ACCOUNT);
         Assert.assertFalse(mDelegate.hasOAuth2RefreshToken("test2@gmail.com"));
     }
 
     @Test
     @SmallTest
     public void testHasOAuth2RefreshTokenWhenAccountIsOnDevice() {
-        final String accountEmail = "test1@gmail.com";
-        mAccountManagerFacade.addAccount(AccountUtils.createAccountFromName(accountEmail));
-        Assert.assertTrue(mDelegate.hasOAuth2RefreshToken(accountEmail));
+        mAccountManagerFacade.addAccount(ACCOUNT);
+        Assert.assertTrue(mDelegate.hasOAuth2RefreshToken(ACCOUNT.name));
+    }
+
+    @Test
+    @SmallTest
+    public void testHasOAuth2RefreshTokenWhenCacheIsNotPopulated() {
+        mAccountManagerFacade.addAccount(ACCOUNT);
+        when(mAccountManagerFacade.isCachePopulated()).thenReturn(false);
+        Assert.assertFalse(mDelegate.hasOAuth2RefreshToken(ACCOUNT.name));
     }
 
     @Test
diff --git a/components/signin/public/android/junit/src/org/chromium/components/signin/AccountTrackerServiceTest.java b/components/signin/public/android/junit/src/org/chromium/components/signin/AccountTrackerServiceTest.java
index 6c79246b..d080b092 100644
--- a/components/signin/public/android/junit/src/org/chromium/components/signin/AccountTrackerServiceTest.java
+++ b/components/signin/public/android/junit/src/org/chromium/components/signin/AccountTrackerServiceTest.java
@@ -20,6 +20,7 @@
 import org.mockito.Spy;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
+import org.mockito.quality.Strictness;
 import org.robolectric.annotation.Config;
 
 import org.chromium.base.task.test.CustomShadowAsyncTask;
@@ -37,7 +38,7 @@
     private static final String ACCOUNT_EMAIL = "test@gmail.com";
 
     @Rule
-    public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+    public final MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
 
     @Rule
     public final JniMocker mocker = new JniMocker();
@@ -49,11 +50,14 @@
     @Mock
     private AccountTrackerService.Natives mNativeMock;
 
+    private AccountTrackerService mService;
+
     @Before
     public void setUp() {
         AccountManagerFacadeProvider.setInstanceForTests(mFakeAccountManagerFacade);
         mocker.mock(AccountTrackerServiceJni.TEST_HOOKS, mNativeMock);
         mFakeAccountManagerFacade.addAccount(AccountUtils.createAccountFromName(ACCOUNT_EMAIL));
+        mService = new AccountTrackerService(ACCOUNT_TRACKER_SERVICE_NATIVE);
     }
 
     @After
@@ -72,8 +76,8 @@
         })
                 .when(mNativeMock)
                 .seedAccountsInfo(eq(ACCOUNT_TRACKER_SERVICE_NATIVE), any(), any());
-        AccountTrackerService service = new AccountTrackerService(ACCOUNT_TRACKER_SERVICE_NATIVE);
-        service.checkAndSeedSystemAccounts();
+
+        mService.checkAndSeedSystemAccounts();
         verify(mFakeAccountManagerFacade).addObserver(notNull());
         verify(mNativeMock).seedAccountsInfo(eq(ACCOUNT_TRACKER_SERVICE_NATIVE), any(), any());
     }
diff --git a/components/signin/public/identity_manager/access_token_constants.cc b/components/signin/public/identity_manager/access_token_constants.cc
index 5fed8cc..381209fc 100644
--- a/components/signin/public/identity_manager/access_token_constants.cc
+++ b/components/signin/public/identity_manager/access_token_constants.cc
@@ -49,8 +49,9 @@
       // Required by cloud policy.
       GaiaConstants::kDeviceManagementServiceOAuth,
 
-      // Required by CRoS.
+      // Required by GCM account tracker.
       GaiaConstants::kGCMGroupServerOAuth2Scope,
+      GaiaConstants::kGCMCheckinServerOAuth2Scope,
 
       // Required by Suggestions.
       GaiaConstants::kDriveReadOnlyOAuth2Scope,
diff --git a/components/subresource_redirect/subresource_redirect_browser_test_util.cc b/components/subresource_redirect/subresource_redirect_browser_test_util.cc
index 653d83d3..e55b3ad 100644
--- a/components/subresource_redirect/subresource_redirect_browser_test_util.cc
+++ b/components/subresource_redirect/subresource_redirect_browser_test_util.cc
@@ -85,7 +85,7 @@
       return response;
     case FailureMode::kTimeout:
       response = std::make_unique<net::test_server::DelayedHttpResponse>(
-          base::TimeDelta::FromSeconds(2));
+          base::TimeDelta::FromSeconds(3));
       break;
     case FailureMode::kNone:
       break;
diff --git a/components/sync/driver/BUILD.gn b/components/sync/driver/BUILD.gn
index 1171a23..2d08224 100644
--- a/components/sync/driver/BUILD.gn
+++ b/components/sync/driver/BUILD.gn
@@ -4,7 +4,6 @@
 
 import("//build/config/chromeos/ui_mode.gni")
 import("//build/config/features.gni")
-import("//tools/grit/grit_rule.gni")
 
 static_library("driver") {
   sources = [
@@ -116,16 +115,6 @@
   configs += [ "//build/config/compiler:wexit_time_destructors" ]
 }
 
-grit("resources") {
-  source = "resources.grd"
-
-  outputs = [
-    "grit/sync_driver_resources.h",
-    "sync_driver_resources.pak",
-  ]
-  output_dir = "$root_gen_dir/components"
-}
-
 static_library("test_support") {
   testonly = true
   sources = [
diff --git a/components/sync/driver/data_type_manager_impl.cc b/components/sync/driver/data_type_manager_impl.cc
index d9dc764..02e2c498 100644
--- a/components/sync/driver/data_type_manager_impl.cc
+++ b/components/sync/driver/data_type_manager_impl.cc
@@ -53,6 +53,7 @@
 DataTypeManagerImpl::AssociationTypesInfo::~AssociationTypesInfo() = default;
 
 DataTypeManagerImpl::DataTypeManagerImpl(
+    ModelTypeSet initial_types,
     const WeakHandle<DataTypeDebugInfoListener>& debug_info_listener,
     const DataTypeController::TypeMap* controllers,
     const DataTypeEncryptionHandler* encryption_handler,
@@ -60,6 +61,7 @@
     DataTypeManagerObserver* observer)
     : configurer_(configurer),
       controllers_(controllers),
+      downloaded_types_(initial_types),
       debug_info_listener_(debug_info_listener),
       model_load_manager_(controllers, this),
       observer_(observer),
diff --git a/components/sync/driver/data_type_manager_impl.h b/components/sync/driver/data_type_manager_impl.h
index 8016772..81e45c6 100644
--- a/components/sync/driver/data_type_manager_impl.h
+++ b/components/sync/driver/data_type_manager_impl.h
@@ -33,6 +33,7 @@
   // TODO(crbug.com/1170318): Get rid of the |initial_types| param, it doesn't
   // seem to actually do anything.
   DataTypeManagerImpl(
+      ModelTypeSet initial_types,
       const WeakHandle<DataTypeDebugInfoListener>& debug_info_listener,
       const DataTypeController::TypeMap* controllers,
       const DataTypeEncryptionHandler* encryption_handler,
diff --git a/components/sync/driver/data_type_manager_impl_unittest.cc b/components/sync/driver/data_type_manager_impl_unittest.cc
index 96249d82..7c1b96e 100644
--- a/components/sync/driver/data_type_manager_impl_unittest.cc
+++ b/components/sync/driver/data_type_manager_impl_unittest.cc
@@ -220,10 +220,10 @@
  protected:
   void SetUp() override { RecreateDataTypeManager(); }
 
-  void RecreateDataTypeManager() {
+  void RecreateDataTypeManager(ModelTypeSet initial_types = ModelTypeSet()) {
     dtm_ = std::make_unique<DataTypeManagerImpl>(
-        MakeWeakHandle(debug_info_listener_.AsWeakPtr()), &controllers_,
-        &encryption_handler_, &configurer_, &observer_);
+        initial_types, MakeWeakHandle(debug_info_listener_.AsWeakPtr()),
+        &controllers_, &encryption_handler_, &configurer_, &observer_);
   }
 
   void SetConfigureStartExpectation() { observer_.ExpectStart(); }
@@ -1278,8 +1278,9 @@
 
 // Test that sync configures properly if all types are ready.
 TEST_F(SyncDataTypeManagerImplTest, AllTypesReady) {
-  // TODO(crbug.com/1170318): Mark PRIORITY_PREFERENCES and BOOKMARKS as already
-  // downloaded.
+  // Mark PRIORITY_PREFERENCES and BOOKMARKS as already downloaded.
+  RecreateDataTypeManager(/*initial_types=*/{PRIORITY_PREFERENCES, BOOKMARKS});
+
   AddController(PRIORITY_PREFERENCES);
   AddController(BOOKMARKS);
 
diff --git a/components/sync/driver/fake_sync_api_component_factory.cc b/components/sync/driver/fake_sync_api_component_factory.cc
index 4520932..f91a03c 100644
--- a/components/sync/driver/fake_sync_api_component_factory.cc
+++ b/components/sync/driver/fake_sync_api_component_factory.cc
@@ -32,14 +32,15 @@
 
 std::unique_ptr<DataTypeManager>
 FakeSyncApiComponentFactory::CreateDataTypeManager(
+    ModelTypeSet initial_types,
     const WeakHandle<DataTypeDebugInfoListener>& debug_info_listener,
     const DataTypeController::TypeMap* controllers,
     const DataTypeEncryptionHandler* encryption_handler,
     ModelTypeConfigurer* configurer,
     DataTypeManagerObserver* observer) {
   auto data_type_manager = std::make_unique<TestDataTypeManagerImpl>(
-      debug_info_listener, controllers, encryption_handler, configurer,
-      observer);
+      initial_types, debug_info_listener, controllers, encryption_handler,
+      configurer, observer);
   last_created_data_type_manager_ = data_type_manager->AsWeakPtr();
   return data_type_manager;
 }
diff --git a/components/sync/driver/fake_sync_api_component_factory.h b/components/sync/driver/fake_sync_api_component_factory.h
index f601c20..d5b9d39 100644
--- a/components/sync/driver/fake_sync_api_component_factory.h
+++ b/components/sync/driver/fake_sync_api_component_factory.h
@@ -49,6 +49,7 @@
 
   // SyncApiComponentFactory overrides.
   std::unique_ptr<DataTypeManager> CreateDataTypeManager(
+      ModelTypeSet initial_types,
       const WeakHandle<DataTypeDebugInfoListener>& debug_info_listener,
       const DataTypeController::TypeMap* controllers,
       const DataTypeEncryptionHandler* encryption_handler,
diff --git a/components/sync/driver/glue/sync_engine_impl.cc b/components/sync/driver/glue/sync_engine_impl.cc
index 79e050f..bcc443ca 100644
--- a/components/sync/driver/glue/sync_engine_impl.cc
+++ b/components/sync/driver/glue/sync_engine_impl.cc
@@ -378,6 +378,22 @@
       std::move(cb));
 }
 
+void SyncEngineImpl::GetThrottledDataTypesForTest(
+    base::OnceCallback<void(ModelTypeSet)> cb) const {
+  DCHECK(IsInitialized());
+  // Instead of reading directly from |cached_status_.throttled_types|, issue
+  // a round trip to the backend sequence, in case there is an ongoing cycle
+  // that could update the throttled types.
+  sync_task_runner_->PostTaskAndReply(
+      FROM_HERE, base::DoNothing(),
+      base::BindOnce(
+          [](base::WeakPtr<SyncEngineImpl> engine,
+             base::OnceCallback<void(ModelTypeSet)> cb) {
+            std::move(cb).Run(engine->cached_status_.throttled_types);
+          },
+          weak_ptr_factory_.GetWeakPtr(), std::move(cb)));
+}
+
 void SyncEngineImpl::RequestBufferedProtocolEventsAndEnableForwarding() {
   sync_task_runner_->PostTask(
       FROM_HERE,
@@ -454,15 +470,16 @@
     UpdateLastSyncedTime();
   }
 
-  host_->OnEngineInitialized(js_backend, debug_info_listener, /*success=*/true,
-                             is_first_time_sync_configure);
+  host_->OnEngineInitialized(initial_types, js_backend, debug_info_listener,
+                             /*success=*/true, is_first_time_sync_configure);
 }
 
 void SyncEngineImpl::HandleInitializationFailureOnFrontendLoop() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  host_->OnEngineInitialized(
-      WeakHandle<JsBackend>(), WeakHandle<DataTypeDebugInfoListener>(),
-      /*success=*/false, /*is_first_time_sync_configure=*/false);
+  host_->OnEngineInitialized(ModelTypeSet(), WeakHandle<JsBackend>(),
+                             WeakHandle<DataTypeDebugInfoListener>(),
+                             /*success=*/false,
+                             /*is_first_time_sync_configure=*/false);
 }
 
 void SyncEngineImpl::HandleSyncCycleCompletedOnFrontendLoop(
diff --git a/components/sync/driver/glue/sync_engine_impl.h b/components/sync/driver/glue/sync_engine_impl.h
index 1e6d12aa..c5abde4 100644
--- a/components/sync/driver/glue/sync_engine_impl.h
+++ b/components/sync/driver/glue/sync_engine_impl.h
@@ -96,6 +96,8 @@
   const Status& GetDetailedStatus() const override;
   void HasUnsyncedItemsForTest(
       base::OnceCallback<void(bool)> cb) const override;
+  void GetThrottledDataTypesForTest(
+      base::OnceCallback<void(ModelTypeSet)> cb) const override;
   void RequestBufferedProtocolEventsAndEnableForwarding() override;
   void DisableProtocolEventForwarding() override;
   void OnCookieJarChanged(bool account_mismatch,
diff --git a/components/sync/driver/glue/sync_engine_impl_unittest.cc b/components/sync/driver/glue/sync_engine_impl_unittest.cc
index 130da6c..88c58b19 100644
--- a/components/sync/driver/glue/sync_engine_impl_unittest.cc
+++ b/components/sync/driver/glue/sync_engine_impl_unittest.cc
@@ -4,7 +4,9 @@
 
 #include "components/sync/driver/glue/sync_engine_impl.h"
 
-#include <memory>
+#include <cstddef>
+#include <map>
+#include <set>
 #include <string>
 #include <utility>
 
@@ -14,6 +16,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/location.h"
 #include "base/run_loop.h"
+#include "base/synchronization/waitable_event.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
 #include "base/test/mock_callback.h"
@@ -24,6 +27,8 @@
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "components/invalidation/impl/invalidation_logger.h"
+#include "components/invalidation/impl/invalidation_switches.h"
+#include "components/invalidation/impl/profile_invalidation_provider.h"
 #include "components/invalidation/public/invalidation_service.h"
 #include "components/invalidation/public/invalidation_util.h"
 #include "components/invalidation/public/invalidator_state.h"
@@ -39,14 +44,18 @@
 #include "components/sync/invalidations/switches.h"
 #include "components/sync/invalidations/sync_invalidations_service.h"
 #include "components/sync/protocol/sync_invalidations_payload.pb.h"
+#include "components/sync/test/callback_counter.h"
 #include "components/sync/test/engine/fake_sync_manager.h"
 #include "components/sync/test/engine/sync_engine_host_stub.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/test/test_network_connection_tracker.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 using testing::_;
 using testing::NiceMock;
+using testing::NotNull;
 
 namespace syncer {
 
@@ -58,13 +67,17 @@
 
 class TestSyncEngineHost : public SyncEngineHostStub {
  public:
-  TestSyncEngineHost() = default;
+  explicit TestSyncEngineHost(
+      base::OnceCallback<void(ModelTypeSet)> set_engine_types)
+      : set_engine_types_(std::move(set_engine_types)) {}
 
-  void OnEngineInitialized(const WeakHandle<JsBackend>&,
+  void OnEngineInitialized(ModelTypeSet initial_types,
+                           const WeakHandle<JsBackend>&,
                            const WeakHandle<DataTypeDebugInfoListener>&,
                            bool success,
                            bool is_first_time_sync_configure) override {
     EXPECT_EQ(expect_success_, success);
+    std::move(set_engine_types_).Run(initial_types);
     std::move(quit_closure_).Run();
   }
 
@@ -77,6 +90,7 @@
   }
 
  private:
+  base::OnceCallback<void(ModelTypeSet)> set_engine_types_;
   bool expect_success_ = false;
   base::OnceClosure quit_closure_;
 };
@@ -91,7 +105,7 @@
         fake_manager_(fake_manager) {
     *fake_manager_ = nullptr;
   }
-  ~FakeSyncManagerFactory() override = default;
+  ~FakeSyncManagerFactory() override {}
 
   // SyncManagerFactory implementation.  Called on the sync thread.
   std::unique_ptr<SyncManager> CreateSyncManager(
@@ -184,8 +198,12 @@
 
 class SyncEngineImplTest : public testing::Test {
  protected:
-  SyncEngineImplTest() = default;
-  ~SyncEngineImplTest() override = default;
+  SyncEngineImplTest()
+      : host_(base::BindOnce(&SyncEngineImplTest::SetEngineTypes,
+                             base::Unretained(this))),
+        fake_manager_(nullptr) {}
+
+  ~SyncEngineImplTest() override {}
 
   void SetUp() override {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
@@ -242,14 +260,10 @@
     backend_->Initialize(std::move(params));
 
     PumpSyncThread();
-    // |fake_manager_| is set on the sync thread, but we can rely on the message
-    // loop barriers to guarantee that we see the updated value.
+    // |fake_manager_factory_|'s fake_manager() is set on the sync
+    // thread, but we can rely on the message loop barriers to
+    // guarantee that we see the updated value.
     DCHECK(fake_manager_);
-
-    if (expect_success) {
-      EXPECT_TRUE(engine_types_.Empty());
-      engine_types_ = fake_manager_->GetEnabledTypes();
-    }
   }
 
   void ShutdownBackend(ShutdownReason reason) {
@@ -265,6 +279,9 @@
   }
 
   ModelTypeSet ConfigureDataTypesWithUnready(ModelTypeSet unready_types) {
+    ModelTypeSet disabled_types =
+        Difference(ModelTypeSet::All(), enabled_types_);
+
     ModelTypeConfigurer::ConfigureParams params;
     params.reason = CONFIGURE_REASON_RECONFIGURATION;
     params.enabled_types = Difference(enabled_types_, unready_types);
@@ -272,7 +289,7 @@
     if (!params.to_download.Empty()) {
       params.to_download.Put(NIGORI);
     }
-    params.to_purge = Difference(engine_types_, enabled_types_);
+    params.to_purge = Intersection(engine_types_, disabled_types);
     params.ready_task = base::BindOnce(&SyncEngineImplTest::DownloadReady,
                                        base::Unretained(this));
 
@@ -296,6 +313,11 @@
     std::move(quit_loop_).Run();
   }
 
+  void SetEngineTypes(ModelTypeSet engine_types) {
+    EXPECT_TRUE(engine_types_.Empty());
+    engine_types_ = engine_types;
+  }
+
   void PumpSyncThread() {
     base::RunLoop run_loop;
     quit_loop_ = run_loop.QuitClosure();
@@ -313,7 +335,7 @@
       sync_transport_data_cleared_cb_;
   std::unique_ptr<SyncEngineImpl> backend_;
   std::unique_ptr<FakeSyncManagerFactory> fake_manager_factory_;
-  FakeSyncManager* fake_manager_ = nullptr;
+  FakeSyncManager* fake_manager_;
   ModelTypeSet engine_types_;
   ModelTypeSet enabled_types_;
   base::OnceClosure quit_loop_;
diff --git a/components/sync/driver/profile_sync_service.cc b/components/sync/driver/profile_sync_service.cc
index 11c562e..74c915f 100644
--- a/components/sync/driver/profile_sync_service.cc
+++ b/components/sync/driver/profile_sync_service.cc
@@ -290,12 +290,15 @@
   return GetRegisteredDataTypes();
 }
 
-ModelTypeSet ProfileSyncService::GetThrottledDataTypesForTest() const {
+void ProfileSyncService::GetThrottledDataTypesForTest(
+    base::OnceCallback<void(ModelTypeSet)> cb) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (engine_ && engine_->IsInitialized()) {
-    return engine_->GetDetailedStatus().throttled_types;
+  if (!engine_ || !engine_->IsInitialized()) {
+    std::move(cb).Run(ModelTypeSet());
+    return;
   }
-  return ModelTypeSet();
+
+  engine_->GetThrottledDataTypesForTest(std::move(cb));
 }
 
 void ProfileSyncService::TriggerPoliciesLoadedForTest() {
@@ -760,6 +763,7 @@
 }
 
 void ProfileSyncService::OnEngineInitialized(
+    ModelTypeSet initial_types,
     const WeakHandle<JsBackend>& js_backend,
     const WeakHandle<DataTypeDebugInfoListener>& debug_info_listener,
     bool success,
@@ -793,8 +797,8 @@
 
   data_type_manager_ =
       sync_client_->GetSyncApiComponentFactory()->CreateDataTypeManager(
-          debug_info_listener, &data_type_controllers_, &crypto_, engine_.get(),
-          this);
+          initial_types, debug_info_listener, &data_type_controllers_, &crypto_,
+          engine_.get(), this);
 
   crypto_.SetSyncEngine(GetAuthenticatedAccountInfo(), engine_.get());
 
diff --git a/components/sync/driver/profile_sync_service.h b/components/sync/driver/profile_sync_service.h
index 59122e7..f914eac 100644
--- a/components/sync/driver/profile_sync_service.h
+++ b/components/sync/driver/profile_sync_service.h
@@ -159,6 +159,7 @@
 
   // SyncEngineHost implementation.
   void OnEngineInitialized(
+      ModelTypeSet initial_types,
       const WeakHandle<JsBackend>& js_backend,
       const WeakHandle<DataTypeDebugInfoListener>& debug_info_listener,
       bool success,
@@ -233,7 +234,9 @@
                                   create_http_post_provider_factory_cb);
 
   ModelTypeSet GetRegisteredDataTypesForTest() const;
-  ModelTypeSet GetThrottledDataTypesForTest() const;
+
+  void GetThrottledDataTypesForTest(
+      base::OnceCallback<void(ModelTypeSet)> cb) const;
 
   // Simulates that all policies just got loaded. This does nothing if the
   // policies were already loaded.
diff --git a/components/sync/driver/profile_sync_service_startup_unittest.cc b/components/sync/driver/profile_sync_service_startup_unittest.cc
index ba984d2..3be576a 100644
--- a/components/sync/driver/profile_sync_service_startup_unittest.cc
+++ b/components/sync/driver/profile_sync_service_startup_unittest.cc
@@ -696,8 +696,6 @@
 
   ASSERT_EQ(DataTypeController::MODEL_STARTING,
             get_controller(SESSIONS)->state());
-  EXPECT_EQ(SyncService::TransportState::CONFIGURING,
-            sync_service()->GetTransportState());
   EXPECT_NE(nullptr, data_type_manager());
   EXPECT_TRUE(engine());
 
diff --git a/components/sync/driver/resources.grd b/components/sync/driver/resources.grd
deleted file mode 100644
index fd57888..0000000
--- a/components/sync/driver/resources.grd
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<grit latest_public_release="0"
-      current_release="1"
-      output_all_resource_defines="false">
-  <outputs>
-    <output filename="grit/sync_driver_resources.h" type="rc_header">
-      <emit emit_type='prepend'></emit>
-    </output>
-    <output filename="sync_driver_resources.pak" type="data_package" />
-  </outputs>
-  <release seq="1">
-    <includes>
-      <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_INDEX_HTML" file="resources/index.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
-      <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_INDEX_JS" file="resources/sync_index.js" type="BINDATA" />
-      <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_CHROME_SYNC_JS" file="resources/chrome_sync.js" type="BINDATA" />
-      <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_SYNC_LOG_JS" file="resources/sync_log.js" type="BINDATA" />
-      <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_SYNC_NODE_BROWSER_JS" file="resources/sync_node_browser.js" type="BINDATA" />
-      <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_SYNC_SEARCH_JS" file="resources/sync_search.js" type="BINDATA" />
-      <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_ABOUT_JS" file="resources/about.js" type="BINDATA" />
-      <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_DATA_JS" file="resources/data.js" type="BINDATA" />
-      <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_EVENTS_JS" file="resources/events.js" type="BINDATA" />
-      <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_SEARCH_JS" file="resources/search.js" type="BINDATA" />
-      <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_USER_EVENTS_JS" file="resources/user_events.js" type="BINDATA" />
-      <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_TRAFFIC_LOG_JS"  file="resources/traffic_log.js" type="BINDATA" />
-      <include name="IDR_SYNC_DRIVER_SYNC_INTERNALS_INVALIDATIONS_JS"  file="resources/invalidations.js" type="BINDATA" />
-    </includes>
-  </release>
-</grit>
diff --git a/components/sync/driver/resources/BUILD.gn b/components/sync/driver/resources/BUILD.gn
index 84c559e..cddf519f 100644
--- a/components/sync/driver/resources/BUILD.gn
+++ b/components/sync/driver/resources/BUILD.gn
@@ -3,6 +3,65 @@
 # found in the LICENSE file.
 
 import("//third_party/closure_compiler/compile_js.gni")
+import("//tools/grit/grit_rule.gni")
+import("//tools/grit/preprocess_if_expr.gni")
+import("//ui/webui/resources/tools/generate_grd.gni")
+
+grd_file = "$target_gen_dir/resources.grd"
+
+preprocess_if_expr("preprocess") {
+  in_folder = "./"
+  out_folder = "$target_gen_dir/preprocess"
+  out_manifest = "$target_gen_dir/manifest.json"
+  in_files = [
+    "sync_index.js",
+    "sync_node_browser.css",
+    "sync_search.css",
+  ]
+}
+
+generate_grd("build_grd") {
+  deps = [ ":preprocess" ]
+  grd_prefix = "sync_driver_sync_internals"
+  out_grd = grd_file
+  input_files = [
+    "about.css",
+    "about.js",
+    "chrome_sync.js",
+    "data.js",
+    "events.css",
+    "events.js",
+    "index.html",
+    "invalidations.css",
+    "invalidations.js",
+    "search.js",
+    "star_small.png",
+    "sync_log.js",
+    "sync_node_browser.js",
+    "sync_search.js",
+    "traffic_log.css",
+    "traffic_log.js",
+    "user_events.js",
+  ]
+  input_files_base_dir = rebase_path("./", "//")
+  manifest_files = [ "$target_gen_dir/manifest.json" ]
+}
+
+grit("resources") {
+  source = grd_file
+
+  # Required because the .grd is generated.
+  enable_input_discovery_for_gn_analyze = false
+
+  outputs = [
+    "grit/sync_driver_sync_internals_resources.h",
+    "grit/sync_driver_sync_internals_resources_map.cc",
+    "grit/sync_driver_sync_internals_resources_map.h",
+    "sync_driver_sync_internals_resources.pak",
+  ]
+  output_dir = "$root_gen_dir/components"
+  deps = [ ":build_grd" ]
+}
 
 js_type_check("closure_compile") {
   uses_legacy_modules = true
diff --git a/components/sync/driver/sync_api_component_factory.h b/components/sync/driver/sync_api_component_factory.h
index d3ce7fcb7..041c893 100644
--- a/components/sync/driver/sync_api_component_factory.h
+++ b/components/sync/driver/sync_api_component_factory.h
@@ -29,9 +29,10 @@
 // service (like SyncableService) implementations.
 class SyncApiComponentFactory {
  public:
-  virtual ~SyncApiComponentFactory() = default;
+  virtual ~SyncApiComponentFactory() {}
 
   virtual std::unique_ptr<DataTypeManager> CreateDataTypeManager(
+      ModelTypeSet initial_types,
       const WeakHandle<DataTypeDebugInfoListener>& debug_info_listener,
       const DataTypeController::TypeMap* controllers,
       const DataTypeEncryptionHandler* encryption_handler,
diff --git a/components/sync/engine/commit_contribution_impl.h b/components/sync/engine/commit_contribution_impl.h
index 4d092ac6..d37b8ab 100644
--- a/components/sync/engine/commit_contribution_impl.h
+++ b/components/sync/engine/commit_contribution_impl.h
@@ -77,7 +77,8 @@
   // all (i.e. there is no internet connection).
   base::OnceCallback<void(SyncCommitError)> on_full_commit_failure_callback_;
 
-  // A non-owned pointer to cryptographer to encrypt entities.
+  // Null if |type_| is not encrypted. Otherwise this is used to encrypt the
+  // committed entities.
   Cryptographer* const cryptographer_;
 
   const PassphraseType passphrase_type_;
diff --git a/components/sync/engine/model_type_registry.cc b/components/sync/engine/model_type_registry.cc
index f85be165..5be3090 100644
--- a/components/sync/engine/model_type_registry.cc
+++ b/components/sync/engine/model_type_registry.cc
@@ -51,14 +51,19 @@
 
 }  // namespace
 
-ModelTypeRegistry::ModelTypeRegistry(NudgeHandler* nudge_handler,
-                                     CancelationSignal* cancelation_signal,
-                                     KeystoreKeysHandler* keystore_keys_handler)
+ModelTypeRegistry::ModelTypeRegistry(
+    NudgeHandler* nudge_handler,
+    CancelationSignal* cancelation_signal,
+    SyncEncryptionHandler* sync_encryption_handler)
     : nudge_handler_(nudge_handler),
       cancelation_signal_(cancelation_signal),
-      keystore_keys_handler_(keystore_keys_handler) {}
+      sync_encryption_handler_(sync_encryption_handler) {
+  sync_encryption_handler_->AddObserver(this);
+}
 
-ModelTypeRegistry::~ModelTypeRegistry() = default;
+ModelTypeRegistry::~ModelTypeRegistry() {
+  sync_encryption_handler_->RemoveObserver(this);
+}
 
 void ModelTypeRegistry::ConnectDataType(
     ModelType type,
@@ -75,22 +80,16 @@
   bool initial_sync_done =
       activation_response->model_type_state.initial_sync_done();
 
-  DCHECK(!encrypted_types_.Has(type) || cryptographer_)
-      << "Connecting encrypted type " << ModelTypeToString(type)
-      << " but the cryptographer isn't set";
-
   auto worker = std::make_unique<ModelTypeWorker>(
       type, activation_response->model_type_state,
       /*trigger_initial_sync=*/!initial_sync_done,
-      encrypted_types_.Has(type) ? cryptographer_->Clone() : nullptr,
+      encrypted_types_.Has(type) ? sync_encryption_handler_->GetCryptographer()
+                                 : nullptr,
       passphrase_type_, nudge_handler_,
       std::move(activation_response->type_processor), cancelation_signal_);
 
-  // If the cryptographer wasn't set yet, it will be informed to this |worker|
-  // as soon as it's set in OnCryptographerStateChanged().
-  if (cryptographer_) {
-    worker->UpdateFallbackCryptographerForUma(cryptographer_->Clone());
-  }
+  worker->SetFallbackCryptographerForUma(
+      sync_encryption_handler_->GetCryptographer());
 
   // Save a raw pointer and add the worker to our structures.
   ModelTypeWorker* worker_ptr = worker.get();
@@ -171,7 +170,7 @@
 }
 
 KeystoreKeysHandler* ModelTypeRegistry::keystore_keys_handler() {
-  return keystore_keys_handler_;
+  return sync_encryption_handler_->GetKeystoreKeysHandler();
 }
 
 bool ModelTypeRegistry::HasUnsyncedItems() const {
@@ -222,17 +221,22 @@
   // workers never have their Cryptographers removed. This probably is not a use
   // case that currently needs to be supported, but it should be guarded against
   // here.
+  for (const auto& worker : connected_model_type_workers_) {
+    if (encrypted_types.Has(worker->GetModelType()) &&
+        !encrypted_types_.Has(worker->GetModelType())) {
+      worker->EnableEncryption(sync_encryption_handler_->GetCryptographer());
+    }
+  }
   encrypted_types_ = encrypted_types;
-  UpdateCryptographerForConnectedEncryptedTypes();
 }
 
 void ModelTypeRegistry::OnCryptographerStateChanged(
     Cryptographer* cryptographer,
     bool has_pending_keys) {
-  cryptographer_ = cryptographer->Clone();
-  UpdateCryptographerForConnectedEncryptedTypes();
   for (const auto& worker : connected_model_type_workers_) {
-    worker->UpdateFallbackCryptographerForUma(cryptographer_->Clone());
+    if (encrypted_types_.Has(worker->GetModelType())) {
+      worker->OnCryptographerChange();
+    }
   }
 }
 
@@ -246,15 +250,4 @@
   }
 }
 
-void ModelTypeRegistry::UpdateCryptographerForConnectedEncryptedTypes() {
-  for (const auto& worker : connected_model_type_workers_) {
-    if (encrypted_types_.Has(worker->GetModelType())) {
-      DCHECK(cryptographer_)
-          << ModelTypeToString(worker->GetModelType())
-          << " is a connected encrypted type but there's no cryptographer";
-      worker->UpdateCryptographer(cryptographer_->Clone());
-    }
-  }
-}
-
 }  // namespace syncer
diff --git a/components/sync/engine/model_type_registry.h b/components/sync/engine/model_type_registry.h
index fef8ad0..a3da783 100644
--- a/components/sync/engine/model_type_registry.h
+++ b/components/sync/engine/model_type_registry.h
@@ -23,7 +23,7 @@
 
 class CancelationSignal;
 class CommitContributor;
-class KeystoreKeysHandler;
+class SyncEncryptionHandler;
 class ModelTypeWorker;
 class UpdateHandler;
 
@@ -34,9 +34,11 @@
 class ModelTypeRegistry : public ModelTypeConnector,
                           public SyncEncryptionHandler::Observer {
  public:
+  // |nudge_handler|, |cancelation_signal| and |sync_encryption_handler| must
+  // outlive this object.
   ModelTypeRegistry(NudgeHandler* nudge_handler,
                     CancelationSignal* cancelation_signal,
-                    KeystoreKeysHandler* keystore_keys_handler);
+                    SyncEncryptionHandler* sync_encryption_handler);
   ~ModelTypeRegistry() override;
 
   // Implementation of ModelTypeConnector.
@@ -86,9 +88,6 @@
   base::WeakPtr<ModelTypeConnector> AsWeakPtr();
 
  private:
-  // Called when either |cryptographer_| or |encrypted_types_| change.
-  void UpdateCryptographerForConnectedEncryptedTypes();
-
   // Enabled proxy types, which don't have a worker.
   ModelTypeSet enabled_proxy_types_;
 
@@ -99,9 +98,6 @@
   UpdateHandlerMap update_handler_map_;
   CommitContributorMap commit_contributor_map_;
 
-  // A copy of the most recent cryptographer.
-  std::unique_ptr<Cryptographer> cryptographer_;
-
   // A copy of the most recent passphrase type.
   PassphraseType passphrase_type_ =
       SyncEncryptionHandler::kInitialPassphraseType;
@@ -115,7 +111,7 @@
   // ModelTypeWorker to cancel blocking operation.
   CancelationSignal* const cancelation_signal_;
 
-  KeystoreKeysHandler* const keystore_keys_handler_;
+  SyncEncryptionHandler* const sync_encryption_handler_;
 
   base::WeakPtrFactory<ModelTypeRegistry> weak_ptr_factory_{this};
 
diff --git a/components/sync/engine/model_type_worker.cc b/components/sync/engine/model_type_worker.cc
index 95bda2bf..ec1e5c6 100644
--- a/components/sync/engine/model_type_worker.cc
+++ b/components/sync/engine/model_type_worker.cc
@@ -153,7 +153,7 @@
     ModelType type,
     const sync_pb::ModelTypeState& initial_state,
     bool trigger_initial_sync,
-    std::unique_ptr<Cryptographer> cryptographer,
+    Cryptographer* cryptographer,
     PassphraseType passphrase_type,
     NudgeHandler* nudge_handler,
     std::unique_ptr<ModelTypeProcessor> model_type_processor,
@@ -161,7 +161,7 @@
     : type_(type),
       model_type_state_(initial_state),
       model_type_processor_(std::move(model_type_processor)),
-      cryptographer_(std::move(cryptographer)),
+      cryptographer_(cryptographer),
       passphrase_type_(passphrase_type),
       nudge_handler_(nudge_handler),
       min_gu_responses_to_ignore_key_(kMinGuResponsesToIgnoreKey),
@@ -183,15 +183,15 @@
   // type state that has already done its initial sync, and is going to be
   // tracking metadata changes, however it does not have the most recent
   // encryption key name. The cryptographer was updated while the worker was not
-  // around, and we're not going to receive the normal UpdateCryptographer() or
+  // around, and we're not going to receive the usual OnCryptographerChange() or
   // EncryptionAcceptedApplyUpdates() calls to drive this process.
   //
   // If |cryptographer_->CanEncrypt()| is false, all the rest of this logic can
-  // be safely skipped, since |UpdateCryptographer(...)| must be called first
+  // be safely skipped, since |OnCryptographerChange()| must be called first
   // and things should be driven normally after that.
   //
   // If |model_type_state_.initial_sync_done()| is false, |model_type_state_|
-  // may still need to be updated, since UpdateCryptographer() is never going to
+  // may still need to be updated, since OnCryptographerChange() will never
   // happen, but we can assume PassiveApplyUpdates(...) will push the state to
   // the processor, and we should not push it now. In fact, doing so now would
   // violate the processor's assumption that the first OnUpdateReceived is will
@@ -215,22 +215,29 @@
   return type_;
 }
 
-void ModelTypeWorker::UpdateCryptographer(
-    std::unique_ptr<Cryptographer> cryptographer) {
+void ModelTypeWorker::EnableEncryption(Cryptographer* cryptographer) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(!cryptographer_);
   DCHECK(cryptographer);
-  cryptographer_ = std::move(cryptographer);
+  cryptographer_ = cryptographer;
+  OnCryptographerChange();
+}
+
+void ModelTypeWorker::SetFallbackCryptographerForUma(
+    Cryptographer* fallback_cryptographer_for_uma) {
+  DCHECK(!fallback_cryptographer_for_uma_);
+  DCHECK(fallback_cryptographer_for_uma);
+  fallback_cryptographer_for_uma_ = fallback_cryptographer_for_uma;
+}
+
+void ModelTypeWorker::OnCryptographerChange() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(cryptographer_);
   UpdateEncryptionKeyName();
   DecryptStoredEntities();
   NudgeIfReadyToCommit();
 }
 
-void ModelTypeWorker::UpdateFallbackCryptographerForUma(
-    std::unique_ptr<Cryptographer> fallback_cryptographer_for_uma) {
-  DCHECK(fallback_cryptographer_for_uma);
-  fallback_cryptographer_for_uma_ = std::move(fallback_cryptographer_for_uma);
-}
-
 void ModelTypeWorker::UpdatePassphraseType(PassphraseType type) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   passphrase_type_ = type;
@@ -281,8 +288,8 @@
     }
 
     UpdateResponseData response_data;
-    switch (PopulateUpdateResponseData(cryptographer_.get(), type_,
-                                       *update_entity, &response_data)) {
+    switch (PopulateUpdateResponseData(cryptographer_, type_, *update_entity,
+                                       &response_data)) {
       case SUCCESS:
         pending_updates_.push_back(std::move(response_data));
         // Override any previously undecryptable update for the same id.
@@ -536,8 +543,7 @@
                      weak_ptr_factory_.GetWeakPtr()),
       base::BindOnce(&ModelTypeWorker::OnFullCommitFailure,
                      weak_ptr_factory_.GetWeakPtr()),
-      cryptographer_.get(), passphrase_type_,
-      CommitOnlyTypes().Has(GetModelType()));
+      cryptographer_, passphrase_type_, CommitOnlyTypes().Has(GetModelType()));
 }
 
 bool ModelTypeWorker::HasLocalChangesForTest() const {
@@ -613,8 +619,8 @@
     const sync_pb::SyncEntity& encrypted_update = it->second;
 
     UpdateResponseData response_data;
-    switch (PopulateUpdateResponseData(cryptographer_.get(), type_,
-                                       encrypted_update, &response_data)) {
+    switch (PopulateUpdateResponseData(cryptographer_, type_, encrypted_update,
+                                       &response_data)) {
       case SUCCESS:
         pending_updates_.push_back(std::move(response_data));
         it = entries_pending_decryption_.erase(it);
@@ -802,7 +808,7 @@
   // |fallback_cryptographer_for_uma_| can decrypt the data.
   for (const auto& id_and_pending_update : entries_pending_decryption_) {
     UpdateResponseData ignored;
-    if (PopulateUpdateResponseData(fallback_cryptographer_for_uma_.get(), type_,
+    if (PopulateUpdateResponseData(fallback_cryptographer_for_uma_, type_,
                                    id_and_pending_update.second,
                                    &ignored) == SUCCESS) {
       base::UmaHistogramEnumeration(
diff --git a/components/sync/engine/model_type_worker.h b/components/sync/engine/model_type_worker.h
index 1e128092..e14a3bdc 100644
--- a/components/sync/engine/model_type_worker.h
+++ b/components/sync/engine/model_type_worker.h
@@ -60,10 +60,13 @@
   // Public for testing.
   enum DecryptionStatus { SUCCESS, DECRYPTION_PENDING, FAILED_TO_DECRYPT };
 
+  // |nudge_handler| and |cancelation_signal| must outlive this object.
+  // |cryptographer| must either outlive this object or be null. Passing a
+  // a null cryptographer means this type won't use encryption.
   ModelTypeWorker(ModelType type,
                   const sync_pb::ModelTypeState& initial_state,
                   bool trigger_initial_sync,
-                  std::unique_ptr<Cryptographer> cryptographer,
+                  Cryptographer* cryptographer,
                   PassphraseType passphrase_type,
                   NudgeHandler* nudge_handler,
                   std::unique_ptr<ModelTypeProcessor> model_type_processor,
@@ -81,12 +84,22 @@
 
   ModelType GetModelType() const;
 
-  void UpdateCryptographer(std::unique_ptr<Cryptographer> cryptographer);
-  // Causes a worker without cryptographer to record whether
-  // |fallback_cryptographer_for_uma| would have been able to decrypt incoming
-  // encrypted updates. |fallback_cryptographer_for_uma| must be non-null.
-  void UpdateFallbackCryptographerForUma(
-      std::unique_ptr<Cryptographer> fallback_cryptographer_for_uma);
+  // Will start using |cryptographer| to encrypt/decrypt data. Must be called at
+  // most once, if the type transitioned from non-encrypted to encrypted.
+  // |cryptographer| must outlive this object.
+  void EnableEncryption(Cryptographer* cryptographer);
+
+  // Always called in production, may not be called in tests. Causes a worker
+  // without cryptographer to log whether |fallback_cryptographer_for_uma| would
+  // have been able to decrypt incoming encrypted updates.
+  // |fallback_cryptographer_for_uma| must outlive this object.
+  void SetFallbackCryptographerForUma(
+      Cryptographer* fallback_cryptographer_for_uma);
+
+  // Must only be called if there is a cryptographer. Called on every change to
+  // its state.
+  void OnCryptographerChange();
+
   void UpdatePassphraseType(PassphraseType type);
 
   // UpdateHandler implementation.
@@ -209,24 +222,23 @@
   // Pointer to the ModelTypeProcessor associated with this worker. Never null.
   std::unique_ptr<ModelTypeProcessor> model_type_processor_;
 
-  // A private copy of the most recent cryptographer known to sync.
-  // Initialized at construction time and updated with UpdateCryptographer().
-  // null if encryption is not enabled for this type.
-  std::unique_ptr<Cryptographer> cryptographer_;
+  // Initialized on construction or later via InitCryptographer(). Null as long
+  // as encryption is not enabled for this type.
+  Cryptographer* cryptographer_ = nullptr;
 
   // Used to investigate an issue where the worker receives encrypted updates
   // despite not having a |cryptographer_| (|type_| is not an encrypted type).
   // In those cases, this will eventually hold the underlying cryptographer used
   // by other types. The worker then records whether that cryptographer is able
   // to decrypt the updates. See crbug.com/1178418.
-  std::unique_ptr<Cryptographer> fallback_cryptographer_for_uma_;
+  Cryptographer* fallback_cryptographer_for_uma_ = nullptr;
 
   // A private copy of the most recent passphrase type. Initialized at
   // construction time and updated with UpdatePassphraseType().
   PassphraseType passphrase_type_;
 
   // Interface used to access and send nudges to the sync scheduler. Not owned.
-  NudgeHandler* nudge_handler_;
+  NudgeHandler* const nudge_handler_;
 
   // A map of sync entities, keyed by server_id. Holds updates encrypted with
   // pending keys. Entries are stored in a map for de-duplication (applying only
@@ -258,7 +270,7 @@
 
   // Cancellation signal is used to cancel blocking operation on engine
   // shutdown.
-  CancelationSignal* cancelation_signal_;
+  CancelationSignal* const cancelation_signal_;
 
   SEQUENCE_CHECKER(sequence_checker_);
 
diff --git a/components/sync/engine/model_type_worker_unittest.cc b/components/sync/engine/model_type_worker_unittest.cc
index 8d427a0..ff71b18 100644
--- a/components/sync/engine/model_type_worker_unittest.cc
+++ b/components/sync/engine/model_type_worker_unittest.cc
@@ -115,8 +115,12 @@
   const ClientTagHash kHash2 = GenerateTagHash(kTag2);
   const ClientTagHash kHash3 = GenerateTagHash(kTag3);
 
-  explicit ModelTypeWorkerTest(ModelType model_type = PREFERENCES)
+  ModelTypeWorkerTest()
+      : ModelTypeWorkerTest(PREFERENCES, /*is_encrypted_type=*/false) {}
+
+  ModelTypeWorkerTest(ModelType model_type, bool is_encrypted_type)
       : model_type_(model_type),
+        is_encrypted_type_(is_encrypted_type),
         foreign_encryption_key_index_(0),
         update_encryption_filter_index_(0),
         mock_type_processor_(nullptr),
@@ -177,14 +181,26 @@
 
     worker_ = std::make_unique<ModelTypeWorker>(
         type, state, !state.initial_sync_done(),
-        cryptographer_ ? cryptographer_->Clone() : nullptr,
+        is_encrypted_type_ ? &cryptographer_ : nullptr,
         PassphraseType::kImplicitPassphrase, &mock_nudge_handler_,
         std::move(processor), &cancelation_signal_);
   }
 
-  void InitializeCryptographer() {
-    if (!cryptographer_) {
-      cryptographer_ = std::make_unique<FakeCryptographer>();
+  // If the type isn't encrypted yet, makes the cryptographer available to the
+  // worker and marks the type as encrypted. Otherwise, just notifies a change
+  // in the cryptographer state.
+  void EnableEncryptionOrNotify() {
+    if (!worker()) {
+      // No worker to notify, just ensure |is_encrypted_type_| is true.
+      is_encrypted_type_ = true;
+      return;
+    }
+
+    if (is_encrypted_type_) {
+      worker()->OnCryptographerChange();
+    } else {
+      is_encrypted_type_ = true;
+      worker()->EnableEncryption(&cryptographer_);
     }
   }
 
@@ -192,32 +208,23 @@
   // the cryptographer becomes unusable (no default key until the issue gets
   // resolved, via DecryptPendingKey()).
   void AddPendingKey() {
-    InitializeCryptographer();
-
     foreign_encryption_key_index_++;
-    cryptographer_->ClearDefaultEncryptionKey();
-
-    // Update the worker with the latest cryptographer.
-    if (worker()) {
-      worker()->UpdateCryptographer(cryptographer_->Clone());
-    }
+    cryptographer_.ClearDefaultEncryptionKey();
+    EnableEncryptionOrNotify();
   }
 
   // Update the local cryptographer with all relevant keys.
   void DecryptPendingKey() {
     DCHECK_NE(foreign_encryption_key_index_, 0);
-    InitializeCryptographer();
-
     std::string last_key_name;
     for (int i = 1; i <= foreign_encryption_key_index_; ++i) {
       last_key_name = GetNthKeyName(i);
-      cryptographer_->AddEncryptionKey(last_key_name);
+      cryptographer_.AddEncryptionKey(last_key_name);
     }
-    cryptographer_->SelectDefaultEncryptionKey(last_key_name);
+    cryptographer_.SelectDefaultEncryptionKey(last_key_name);
 
-    // Update the worker with the latest cryptographer.
+    EnableEncryptionOrNotify();
     if (worker()) {
-      worker()->UpdateCryptographer(cryptographer_->Clone());
       worker()->EncryptionAcceptedMaybeApplyUpdates();
     }
   }
@@ -402,27 +409,23 @@
 
   void ResetWorker() { worker_.reset(); }
 
-  // Returns the name of the encryption key in the cryptographer last passed to
-  // the CommitQueue. Returns an empty string if no cryptographer is
-  // in use. See also: DecryptPendingKey().
-  std::string GetLocalCryptographerKeyName() const {
-    if (!cryptographer_) {
-      return std::string();
-    }
-    return cryptographer_->GetDefaultEncryptionKeyName();
-  }
-
   MockModelTypeProcessor* processor() { return mock_type_processor_; }
   ModelTypeWorker* worker() { return worker_.get(); }
   SingleTypeMockServer* server() { return mock_server_.get(); }
   MockNudgeHandler* nudge_handler() { return &mock_nudge_handler_; }
   StatusController* status_controller() { return &status_controller_; }
+  std::string default_encryption_key_name() {
+    return cryptographer_.GetDefaultEncryptionKeyName();
+  }
 
  private:
   const ModelType model_type_;
 
-  // The cryptographer itself. Null if we're not encrypting the type.
-  std::unique_ptr<FakeCryptographer> cryptographer_;
+  FakeCryptographer cryptographer_;
+
+  // Determines whether |worker_| has access to the cryptographer or not.
+  // Can be set to true via EnableEncryptionOrNotify().
+  bool is_encrypted_type_;
 
   // The number of the most recent foreign encryption key known to our
   // cryptographer. Note that not all of these will be decryptable.
@@ -969,7 +972,7 @@
   AddPendingKey();
   DecryptPendingKey();
   ASSERT_EQ(1U, processor()->GetNumUpdateResponses());
-  EXPECT_EQ(GetLocalCryptographerKeyName(),
+  EXPECT_EQ(default_encryption_key_name(),
             processor()->GetNthUpdateState(0).encryption_key_name());
 
   // Normal commit request stuff.
@@ -1001,7 +1004,7 @@
   AddPendingKey();
   DecryptPendingKey();
   ASSERT_EQ(1U, processor()->GetNumUpdateResponses());
-  EXPECT_EQ(GetLocalCryptographerKeyName(),
+  EXPECT_EQ(default_encryption_key_name(),
             processor()->GetNthUpdateState(0).encryption_key_name());
 
   // Normal commit request stuff.
@@ -1150,7 +1153,7 @@
   // possible, so that it will have the chance to re-encrypt local data if
   // necessary.
   ASSERT_EQ(1U, processor()->GetNumUpdateResponses());
-  EXPECT_EQ(GetLocalCryptographerKeyName(),
+  EXPECT_EQ(default_encryption_key_name(),
             processor()->GetNthUpdateState(0).encryption_key_name());
 }
 
@@ -1168,7 +1171,7 @@
   // Init the cryptographer, it'll push the EKN.
   DecryptPendingKey();
   ASSERT_EQ(1U, processor()->GetNumUpdateResponses());
-  EXPECT_EQ(GetLocalCryptographerKeyName(),
+  EXPECT_EQ(default_encryption_key_name(),
             processor()->GetNthUpdateState(0).encryption_key_name());
 }
 
@@ -1187,7 +1190,7 @@
   // Now perform first sync and make sure the EKN makes it.
   TriggerTypeRootUpdateFromServer();
   ASSERT_EQ(1U, processor()->GetNumUpdateResponses());
-  EXPECT_EQ(GetLocalCryptographerKeyName(),
+  EXPECT_EQ(default_encryption_key_name(),
             processor()->GetNthUpdateState(0).encryption_key_name());
 }
 
@@ -1205,7 +1208,7 @@
   // Now perform first sync and make sure the EKN makes it.
   TriggerTypeRootUpdateFromServer();
   ASSERT_EQ(1U, processor()->GetNumUpdateResponses());
-  EXPECT_EQ(GetLocalCryptographerKeyName(),
+  EXPECT_EQ(default_encryption_key_name(),
             processor()->GetNthUpdateState(0).encryption_key_name());
 }
 
@@ -1233,7 +1236,7 @@
   const UpdateResponseData& update = processor()->GetUpdateResponse(kHash1);
   EXPECT_EQ(kTag1, update.entity.specifics.preference().name());
   EXPECT_EQ(kValue1, update.entity.specifics.preference().value());
-  EXPECT_EQ(GetLocalCryptographerKeyName(), update.encryption_key_name);
+  EXPECT_EQ(default_encryption_key_name(), update.encryption_key_name);
 }
 
 TEST_F(ModelTypeWorkerTest, OverwriteUndecryptableUpdateWithDecryptableOne) {
@@ -1298,9 +1301,10 @@
 
   // This isn't an encrypted type, so this worker has no cryptographer. Under
   // the hood however, the overall client does have a cryptographer containing
-  // key 1. That one is injected with UpdateFallbackCryptographerForUma().
-  worker()->UpdateFallbackCryptographerForUma(
-      FakeCryptographer::FromSingleDefaultKey(GetNthKeyName(1)));
+  // key 1. That one is injected with SetFallbackCryptographerForUma().
+  std::unique_ptr<Cryptographer> cryptographer_for_uma =
+      FakeCryptographer::FromSingleDefaultKey(GetNthKeyName(1));
+  worker()->SetFallbackCryptographerForUma(cryptographer_for_uma.get());
 
   // Send an update encrypted with key 1 and another encrypted with an unknown
   // key 2.
@@ -1322,6 +1326,9 @@
   histogram_tester.ExpectUniqueSample(
       "Sync.ModelTypeBlockedDueToUndecryptableUpdate",
       ModelTypeHistogramValue(worker()->GetModelType()), 1);
+
+  // The worker must not outlive |cryptographer_for_uma|.
+  ResetWorker();
 }
 
 TEST_F(ModelTypeWorkerTest, TimeUntilEncryptionKeyFoundMetric) {
@@ -1874,9 +1881,8 @@
  protected:
   const std::string kPassword = "SomePassword";
 
-  ModelTypeWorkerPasswordsTest() : ModelTypeWorkerTest(PASSWORDS) {
-    InitializeCryptographer();
-  }
+  ModelTypeWorkerPasswordsTest()
+      : ModelTypeWorkerTest(PASSWORDS, /*is_encrypted_type=*/true) {}
 };
 
 // Similar to EncryptedCommit but tests PASSWORDS specifically, which use a
@@ -1890,7 +1896,7 @@
   AddPendingKey();
   DecryptPendingKey();
   ASSERT_EQ(1U, processor()->GetNumUpdateResponses());
-  EXPECT_EQ(GetLocalCryptographerKeyName(),
+  EXPECT_EQ(default_encryption_key_name(),
             processor()->GetNthUpdateState(0).encryption_key_name());
 
   EntitySpecifics specifics;
@@ -2065,7 +2071,8 @@
 // to test some special encryption requirements for BOOKMARKS.
 class ModelTypeWorkerBookmarksTest : public ModelTypeWorkerTest {
  protected:
-  ModelTypeWorkerBookmarksTest() : ModelTypeWorkerTest(BOOKMARKS) {}
+  ModelTypeWorkerBookmarksTest()
+      : ModelTypeWorkerTest(BOOKMARKS, /*is_encrypted_type=*/false) {}
 };
 
 TEST_F(ModelTypeWorkerBookmarksTest, CanDecryptUpdateWithMissingBookmarkGUID) {
diff --git a/components/sync/engine/nigori/cryptographer.h b/components/sync/engine/nigori/cryptographer.h
index 9b471cb..f014664 100644
--- a/components/sync/engine/nigori/cryptographer.h
+++ b/components/sync/engine/nigori/cryptographer.h
@@ -19,8 +19,6 @@
   Cryptographer();
   virtual ~Cryptographer();
 
-  virtual std::unique_ptr<Cryptographer> Clone() const = 0;
-
   // Returns whether this cryptographer is ready to encrypt data, using
   // EncryptString(). This usually means that a default encryption key is
   // available and there are no pending keys.
diff --git a/components/sync/engine/sync_encryption_handler.h b/components/sync/engine/sync_encryption_handler.h
index f214158..017c0d5c 100644
--- a/components/sync/engine/sync_encryption_handler.h
+++ b/components/sync/engine/sync_encryption_handler.h
@@ -123,6 +123,10 @@
   // even delete this API altogether.
   virtual bool Init() = 0;
 
+  // TODO(crbug.com/1178418): Add similar getters for the rest of the state
+  // notified to the observers.
+  virtual Cryptographer* GetCryptographer() = 0;
+
   // Attempts to re-encrypt encrypted data types using the passphrase provided.
   // Notifies observers of the result of the operation via OnPassphraseAccepted
   // or OnPassphraseRequired, updates the nigori node, and does re-encryption as
diff --git a/components/sync/engine/sync_engine.h b/components/sync/engine/sync_engine.h
index b120550..80b2bb1 100644
--- a/components/sync/engine/sync_engine.h
+++ b/components/sync/engine/sync_engine.h
@@ -156,6 +156,9 @@
   virtual void HasUnsyncedItemsForTest(
       base::OnceCallback<void(bool)> cb) const = 0;
 
+  // Returns datatypes that are currently throttled.
+  virtual void GetThrottledDataTypesForTest(
+      base::OnceCallback<void(ModelTypeSet)> cb) const = 0;
 
   // Requests that the backend forward to the fronent any protocol events in
   // its buffer and begin forwarding automatically from now on.  Repeated calls
diff --git a/components/sync/engine/sync_engine_host.h b/components/sync/engine/sync_engine_host.h
index 73e6308..84d018e2 100644
--- a/components/sync/engine/sync_engine_host.h
+++ b/components/sync/engine/sync_engine_host.h
@@ -35,6 +35,7 @@
   // initialized only if |success| is true.
 
   virtual void OnEngineInitialized(
+      ModelTypeSet initial_types,
       const WeakHandle<JsBackend>& js_backend,
       const WeakHandle<DataTypeDebugInfoListener>& debug_info_listener,
       bool success,
diff --git a/components/sync/engine/sync_manager_impl.cc b/components/sync/engine/sync_manager_impl.cc
index a8288c0..1e4a843 100644
--- a/components/sync/engine/sync_manager_impl.cc
+++ b/components/sync/engine/sync_manager_impl.cc
@@ -197,9 +197,7 @@
   }
 
   model_type_registry_ = std::make_unique<ModelTypeRegistry>(
-      this, args->cancelation_signal,
-      sync_encryption_handler_->GetKeystoreKeysHandler());
-  sync_encryption_handler_->AddObserver(model_type_registry_.get());
+      this, args->cancelation_signal, sync_encryption_handler_);
 
   // Build a SyncCycleContext and store the worker in it.
   DVLOG(1) << "Sync is bringing up SyncCycleContext.";
@@ -340,9 +338,6 @@
   scheduler_.reset();
   cycle_context_.reset();
 
-  if (model_type_registry_)
-    sync_encryption_handler_->RemoveObserver(model_type_registry_.get());
-
   model_type_registry_.reset();
 
   if (sync_encryption_handler_) {
diff --git a/components/sync/nigori/cryptographer_impl.cc b/components/sync/nigori/cryptographer_impl.cc
index 443adf68..05dca19 100644
--- a/components/sync/nigori/cryptographer_impl.cc
+++ b/components/sync/nigori/cryptographer_impl.cc
@@ -33,15 +33,12 @@
 std::unique_ptr<CryptographerImpl> CryptographerImpl::FromProto(
     const sync_pb::CryptographerData& proto) {
   NigoriKeyBag key_bag = NigoriKeyBag::CreateFromProto(proto.key_bag());
-  std::string default_encryption_key_name = proto.default_key_name();
-  if (!default_encryption_key_name.empty() &&
-      !key_bag.HasKey(default_encryption_key_name)) {
-    // A default key name was specified but not present among keys.
-    return nullptr;
-  }
-
-  return base::WrapUnique(new CryptographerImpl(
-      std::move(key_bag), std::move(default_encryption_key_name)));
+  // TODO(crbug.com/1109221): An invalid local state should be handled in the
+  // caller instead of CHECK-ing here, e.g. by resetting the local state.
+  CHECK(proto.default_key_name().empty() ||
+        key_bag.HasKey(proto.default_key_name()));
+  return base::WrapUnique(
+      new CryptographerImpl(std::move(key_bag), proto.default_key_name()));
 }
 
 CryptographerImpl::CryptographerImpl(NigoriKeyBag key_bag,
@@ -79,10 +76,21 @@
   default_encryption_key_name_ = key_name;
 }
 
+void CryptographerImpl::EmplaceKeysAndSelectDefaultKeyFrom(
+    const CryptographerImpl& other) {
+  EmplaceKeysFrom(other.key_bag_);
+  SelectDefaultEncryptionKey(other.default_encryption_key_name_);
+}
+
 void CryptographerImpl::ClearDefaultEncryptionKey() {
   default_encryption_key_name_.clear();
 }
 
+void CryptographerImpl::ClearAllKeys() {
+  default_encryption_key_name_.clear();
+  key_bag_ = NigoriKeyBag::CreateEmpty();
+}
+
 bool CryptographerImpl::HasKey(const std::string& key_name) const {
   return key_bag_.HasKey(key_name);
 }
@@ -92,7 +100,7 @@
   return key_bag_.ExportKey(default_encryption_key_name_);
 }
 
-std::unique_ptr<CryptographerImpl> CryptographerImpl::CloneImpl() const {
+std::unique_ptr<CryptographerImpl> CryptographerImpl::Clone() const {
   return base::WrapUnique(
       new CryptographerImpl(key_bag_.Clone(), default_encryption_key_name_));
 }
@@ -101,10 +109,6 @@
   return key_bag_.size();
 }
 
-std::unique_ptr<Cryptographer> CryptographerImpl::Clone() const {
-  return CloneImpl();
-}
-
 bool CryptographerImpl::CanEncrypt() const {
   return !default_encryption_key_name_.empty();
 }
diff --git a/components/sync/nigori/cryptographer_impl.h b/components/sync/nigori/cryptographer_impl.h
index d988518..f5d478f 100644
--- a/components/sync/nigori/cryptographer_impl.h
+++ b/components/sync/nigori/cryptographer_impl.h
@@ -61,10 +61,22 @@
   // return true. |key_name| must not be empty and must represent a known key.
   void SelectDefaultEncryptionKey(const std::string& key_name);
 
+  // Adds all keys in |other| that weren't previously known, and selects the
+  // same default key. |other| must have selected a default key.
+  void EmplaceKeysAndSelectDefaultKeyFrom(const CryptographerImpl& other);
+
   // Clears the default encryption key, which causes CanEncrypt() to return
   // false.
   void ClearDefaultEncryptionKey();
 
+  // Reverts the cryptographer to an empty one, i.e. what would be returned by
+  // CreateEmpty(). The default key is also cleared.
+  // The set of known encryption keys shouldn't decrease in general, since this
+  // may lead to data becoming undecryptable. This method can be called a) if
+  // sync is disabled, or b) if sync finds an error that can be solved by
+  // resetting the encryption state.
+  void ClearAllKeys();
+
   // Determines whether |key_name| represents a known key.
   bool HasKey(const std::string& key_name) const;
 
@@ -72,13 +84,11 @@
   // have a default encryption key set, as reflected by CanEncrypt().
   sync_pb::NigoriKey ExportDefaultKey() const;
 
-  // Similar to Clone() but returns CryptographerImpl.
-  std::unique_ptr<CryptographerImpl> CloneImpl() const;
+  std::unique_ptr<CryptographerImpl> Clone() const;
 
   size_t KeyBagSizeForTesting() const;
 
   // Cryptographer overrides.
-  std::unique_ptr<Cryptographer> Clone() const override;
   bool CanEncrypt() const override;
   bool CanDecrypt(const sync_pb::EncryptedData& encrypted) const override;
   std::string GetDefaultEncryptionKeyName() const override;
diff --git a/components/sync/nigori/keystore_keys_cryptographer.cc b/components/sync/nigori/keystore_keys_cryptographer.cc
index 2b54650..b236a50 100644
--- a/components/sync/nigori/keystore_keys_cryptographer.cc
+++ b/components/sync/nigori/keystore_keys_cryptographer.cc
@@ -72,13 +72,13 @@
 
 std::unique_ptr<KeystoreKeysCryptographer> KeystoreKeysCryptographer::Clone()
     const {
-  return base::WrapUnique(new KeystoreKeysCryptographer(
-      cryptographer_->CloneImpl(), keystore_keys_));
+  return base::WrapUnique(
+      new KeystoreKeysCryptographer(cryptographer_->Clone(), keystore_keys_));
 }
 
 std::unique_ptr<CryptographerImpl>
 KeystoreKeysCryptographer::ToCryptographerImpl() const {
-  return cryptographer_->CloneImpl();
+  return cryptographer_->Clone();
 }
 
 bool KeystoreKeysCryptographer::EncryptKeystoreDecryptorToken(
diff --git a/components/sync/nigori/nigori_key_bag.h b/components/sync/nigori/nigori_key_bag.h
index c11991d..809867d7 100644
--- a/components/sync/nigori/nigori_key_bag.h
+++ b/components/sync/nigori/nigori_key_bag.h
@@ -30,6 +30,8 @@
   NigoriKeyBag(NigoriKeyBag&& other);
   ~NigoriKeyBag();
 
+  NigoriKeyBag& operator=(NigoriKeyBag&&) = default;
+
   void CopyFrom(const NigoriKeyBag& other);
 
   // Serialization to proto.
diff --git a/components/sync/nigori/nigori_state.cc b/components/sync/nigori/nigori_state.cc
index 2e6b79d..37db313 100644
--- a/components/sync/nigori/nigori_state.cc
+++ b/components/sync/nigori/nigori_state.cc
@@ -276,7 +276,7 @@
 
 NigoriState NigoriState::Clone() const {
   NigoriState result;
-  result.cryptographer = cryptographer->CloneImpl();
+  result.cryptographer = cryptographer->Clone();
   result.pending_keys = pending_keys;
   result.passphrase_type = passphrase_type;
   result.keystore_migration_time = keystore_migration_time;
diff --git a/components/sync/nigori/nigori_state.h b/components/sync/nigori/nigori_state.h
index 02ea4a3..37a739d8 100644
--- a/components/sync/nigori/nigori_state.h
+++ b/components/sync/nigori/nigori_state.h
@@ -51,6 +51,8 @@
 
   bool NeedsKeystoreReencryption() const;
 
+  // TODO(crbug.com/1109221): Make this const unique_ptr to avoid the object
+  // being destroyed after it's been injected to the ModelTypeWorker-s.
   std::unique_ptr<CryptographerImpl> cryptographer;
 
   // Pending keys represent a remote update that contained a keybag that cannot
diff --git a/components/sync/nigori/nigori_sync_bridge_impl.cc b/components/sync/nigori/nigori_sync_bridge_impl.cc
index 204793c..bd0c5dc 100644
--- a/components/sync/nigori/nigori_sync_bridge_impl.cc
+++ b/components/sync/nigori/nigori_sync_bridge_impl.cc
@@ -659,6 +659,11 @@
   return this;
 }
 
+Cryptographer* NigoriSyncBridgeImpl::GetCryptographer() {
+  DCHECK(state_.cryptographer);
+  return state_.cryptographer.get();
+}
+
 bool NigoriSyncBridgeImpl::NeedKeystoreKey() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Explicitly asks the server for keystore keys if it's first-time sync, i.e.
@@ -1024,7 +1029,7 @@
   // storing explicit passphrase key in prefs, we need to find better solution.
   storage_->ClearData();
   state_.keystore_keys_cryptographer = KeystoreKeysCryptographer::CreateEmpty();
-  state_.cryptographer = CryptographerImpl::CreateEmpty();
+  state_.cryptographer->ClearAllKeys();
   state_.pending_keys.reset();
   state_.pending_keystore_decryptor_token.reset();
   state_.passphrase_type = NigoriSpecifics::UNKNOWN;
@@ -1040,7 +1045,7 @@
                                                   false);
 }
 
-const CryptographerImpl& NigoriSyncBridgeImpl::GetCryptographerForTesting()
+const CryptographerImpl& NigoriSyncBridgeImpl::GetCryptographerImplForTesting()
     const {
   return *state_.cryptographer;
 }
diff --git a/components/sync/nigori/nigori_sync_bridge_impl.h b/components/sync/nigori/nigori_sync_bridge_impl.h
index 92c34b0c..342e34d8 100644
--- a/components/sync/nigori/nigori_sync_bridge_impl.h
+++ b/components/sync/nigori/nigori_sync_bridge_impl.h
@@ -68,6 +68,7 @@
       const std::vector<std::vector<uint8_t>>& keys) override;
   base::Time GetKeystoreMigrationTime() const override;
   KeystoreKeysHandler* GetKeystoreKeysHandler() override;
+  Cryptographer* GetCryptographer() override;
 
   // KeystoreKeysHandler implementation.
   bool NeedKeystoreKey() const override;
@@ -81,10 +82,8 @@
   std::unique_ptr<EntityData> GetData() override;
   void ApplyDisableSyncChanges() override;
 
-  // TODO(crbug.com/922900): investigate whether we need this getter outside of
-  // tests and decide whether this method should be a part of
-  // SyncEncryptionHandler interface.
-  const CryptographerImpl& GetCryptographerForTesting() const;
+  const CryptographerImpl& GetCryptographerImplForTesting() const;
+  // TODO(crbug.com/922900): Move these getters to SyncEncryptionHandler.
   sync_pb::NigoriSpecifics::PassphraseType GetPassphraseTypeForTesting() const;
   ModelTypeSet GetEncryptedTypesForTesting() const;
   bool HasPendingKeysForTesting() const;
diff --git a/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc b/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc
index 6cc0cd5..d994c96 100644
--- a/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc
+++ b/components/sync/nigori/nigori_sync_bridge_impl_unittest.cc
@@ -361,6 +361,7 @@
   MockNigoriLocalChangeProcessor* processor() { return processor_; }
   MockObserver* observer() { return &observer_; }
   MockNigoriStorage* storage() { return storage_; }
+  Cryptographer* cryptographer() { return bridge_->GetCryptographer(); }
 
   const std::vector<uint8_t> kRawKeystoreKey = {0, 1, 2, 3, 4};
   const std::vector<uint8_t> kTrustedVaultKey = {2, 3, 4, 5, 6};
@@ -430,9 +431,8 @@
                                NotNull(), /*has_pending_keys=*/false));
   bridge()->SetDecryptionPassphrase(kKeyParams.password);
 
-  const Cryptographer& cryptographer = bridge()->GetCryptographerForTesting();
-  EXPECT_THAT(cryptographer, CanDecryptWith(kKeyParams));
-  EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(kKeyParams));
+  EXPECT_THAT(*cryptographer(), CanDecryptWith(kKeyParams));
+  EXPECT_THAT(*cryptographer(), HasDefaultKeyDerivedFrom(kKeyParams));
 }
 
 // Simplest case of keystore Nigori: we have only one keystore key and no old
@@ -463,9 +463,8 @@
   EXPECT_TRUE(bridge()->Init());
   EXPECT_THAT(bridge()->GetKeystoreMigrationTime(), Not(NullTime()));
 
-  const Cryptographer& cryptographer = bridge()->GetCryptographerForTesting();
-  EXPECT_THAT(cryptographer, CanDecryptWith(kKeystoreKeyParams));
-  EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(kKeystoreKeyParams));
+  EXPECT_THAT(*cryptographer(), CanDecryptWith(kKeystoreKeyParams));
+  EXPECT_THAT(*cryptographer(), HasDefaultKeyDerivedFrom(kKeystoreKeyParams));
 }
 
 // Tests that client can properly process remote updates with rotated keystore
@@ -486,10 +485,9 @@
   EXPECT_THAT(bridge()->MergeSyncData(std::move(entity_data)),
               Eq(base::nullopt));
 
-  const Cryptographer& cryptographer = bridge()->GetCryptographerForTesting();
-  EXPECT_THAT(cryptographer, CanDecryptWith(kOldKeyParams));
-  EXPECT_THAT(cryptographer, CanDecryptWith(kCurrentKeyParams));
-  EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(kCurrentKeyParams));
+  EXPECT_THAT(*cryptographer(), CanDecryptWith(kOldKeyParams));
+  EXPECT_THAT(*cryptographer(), CanDecryptWith(kCurrentKeyParams));
+  EXPECT_THAT(*cryptographer(), HasDefaultKeyDerivedFrom(kCurrentKeyParams));
 }
 
 // In the backward compatible mode keystore Nigori's keystore_decryptor_token
@@ -509,10 +507,9 @@
   EXPECT_THAT(bridge()->MergeSyncData(std::move(entity_data)),
               Eq(base::nullopt));
 
-  const Cryptographer& cryptographer = bridge()->GetCryptographerForTesting();
-  EXPECT_THAT(cryptographer, CanDecryptWith(kGaiaKeyParams));
-  EXPECT_THAT(cryptographer, CanDecryptWith(kKeystoreKeyParams));
-  EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(kGaiaKeyParams));
+  EXPECT_THAT(*cryptographer(), CanDecryptWith(kGaiaKeyParams));
+  EXPECT_THAT(*cryptographer(), CanDecryptWith(kKeystoreKeyParams));
+  EXPECT_THAT(*cryptographer(), HasDefaultKeyDerivedFrom(kGaiaKeyParams));
 }
 
 TEST_F(NigoriSyncBridgeImplTest, ShouldExposeBackwardCompatibleKeystoreNigori) {
@@ -576,11 +573,10 @@
   EXPECT_THAT(bridge()->MergeSyncData(std::move(entity_data)),
               Eq(base::nullopt));
 
-  const Cryptographer& cryptographer = bridge()->GetCryptographerForTesting();
   for (const KeyParams& key_params : kAllKeyParams) {
-    EXPECT_THAT(cryptographer, CanDecryptWith(key_params));
+    EXPECT_THAT(*cryptographer(), CanDecryptWith(key_params));
   }
-  EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(kCurrentKeyParams));
+  EXPECT_THAT(*cryptographer(), HasDefaultKeyDerivedFrom(kCurrentKeyParams));
 }
 
 // Tests that we build keystore Nigori, put it to processor, initialize the
@@ -610,9 +606,8 @@
   EXPECT_EQ(bridge()->GetPassphraseTypeForTesting(),
             sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE);
 
-  const Cryptographer& cryptographer = bridge()->GetCryptographerForTesting();
-  EXPECT_THAT(cryptographer, CanDecryptWith(kKeystoreKeyParams));
-  EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(kKeystoreKeyParams));
+  EXPECT_THAT(*cryptographer(), CanDecryptWith(kKeystoreKeyParams));
+  EXPECT_THAT(*cryptographer(), HasDefaultKeyDerivedFrom(kKeystoreKeyParams));
 }
 
 // Tests that upon receiving Nigori corrupted due to absence of
@@ -676,10 +671,9 @@
   EXPECT_THAT(bridge()->ApplySyncChanges(base::nullopt), Eq(base::nullopt));
   EXPECT_THAT(bridge()->GetData(), HasKeystoreNigori());
 
-  const Cryptographer& cryptographer = bridge()->GetCryptographerForTesting();
-  EXPECT_THAT(cryptographer, CanDecryptWith(kKeystoreKeyParams1));
-  EXPECT_THAT(cryptographer, CanDecryptWith(kKeystoreKeyParams2));
-  EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(kKeystoreKeyParams2));
+  EXPECT_THAT(*cryptographer(), CanDecryptWith(kKeystoreKeyParams1));
+  EXPECT_THAT(*cryptographer(), CanDecryptWith(kKeystoreKeyParams2));
+  EXPECT_THAT(*cryptographer(), HasDefaultKeyDerivedFrom(kKeystoreKeyParams2));
 }
 
 // This test emulates late arrival of keystore keys, so neither
@@ -704,15 +698,14 @@
           EncryptedDataEq(entity_data.specifics.nigori().encryption_keybag())));
   EXPECT_THAT(bridge()->MergeSyncData(std::move(entity_data)),
               Eq(base::nullopt));
-  const Cryptographer& cryptographer = bridge()->GetCryptographerForTesting();
-  EXPECT_FALSE(cryptographer.CanEncrypt());
+  EXPECT_FALSE(cryptographer()->CanEncrypt());
 
   EXPECT_CALL(*observer(), OnCryptographerStateChanged(
                                NotNull(), /*has_pending_keys=*/false));
   EXPECT_CALL(*observer(), OnPassphraseAccepted());
   EXPECT_TRUE(bridge()->SetKeystoreKeys({kRawKeystoreKey}));
-  EXPECT_THAT(cryptographer, CanDecryptWith(kKeystoreKeyParams));
-  EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(kKeystoreKeyParams));
+  EXPECT_THAT(*cryptographer(), CanDecryptWith(kKeystoreKeyParams));
+  EXPECT_THAT(*cryptographer(), HasDefaultKeyDerivedFrom(kKeystoreKeyParams));
 }
 
 // This test emulates late arrival of keystore keys in backward-compatible
@@ -740,10 +733,9 @@
   EXPECT_CALL(*observer(), OnPassphraseAccepted());
   bridge()->SetDecryptionPassphrase(kPassphraseKeyParams.password);
 
-  const Cryptographer& cryptographer = bridge()->GetCryptographerForTesting();
-  EXPECT_THAT(cryptographer, CanDecryptWith(kKeystoreKeyParams));
-  EXPECT_THAT(cryptographer, CanDecryptWith(kPassphraseKeyParams));
-  EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(kPassphraseKeyParams));
+  EXPECT_THAT(*cryptographer(), CanDecryptWith(kKeystoreKeyParams));
+  EXPECT_THAT(*cryptographer(), CanDecryptWith(kPassphraseKeyParams));
+  EXPECT_THAT(*cryptographer(), HasDefaultKeyDerivedFrom(kPassphraseKeyParams));
 
   // Regression part of the test, SetKeystoreKeys() call in this scenario used
   // to cause the crash (see crbug.com/1042203).
@@ -778,9 +770,8 @@
           EncryptedDataEq(expected_pending_keys)));
   bridge()->SetDecryptionPassphrase("wrong_passphrase");
 
-  const CryptographerImpl& cryptographer =
-      bridge()->GetCryptographerForTesting();
-  EXPECT_THAT(cryptographer.KeyBagSizeForTesting(), Eq(size_t(0)));
+  EXPECT_THAT(bridge()->GetCryptographerImplForTesting().KeyBagSizeForTesting(),
+              Eq(size_t(0)));
 }
 
 // Tests that attempt to SetEncryptionPassphrase() has no effect (at least
@@ -804,9 +795,8 @@
   // implemented. They might be not properly working with deferred state
   // change.
   EXPECT_THAT(bridge()->GetData(), HasKeystoreNigori());
-  const Cryptographer& cryptographer = bridge()->GetCryptographerForTesting();
-  EXPECT_THAT(cryptographer, CanDecryptWith(kKeystoreKeyParams));
-  EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(kKeystoreKeyParams));
+  EXPECT_THAT(*cryptographer(), CanDecryptWith(kKeystoreKeyParams));
+  EXPECT_THAT(*cryptographer(), HasDefaultKeyDerivedFrom(kKeystoreKeyParams));
 }
 
 // Tests that we can perform initial sync with custom passphrase Nigori.
@@ -964,11 +954,11 @@
   ASSERT_TRUE(bridge()->SetKeystoreKeys({kRawKeystoreKey}));
   ASSERT_THAT(bridge()->MergeSyncData(std::move(entity_data)),
               Eq(base::nullopt));
-  ASSERT_TRUE(bridge()->GetCryptographerForTesting().CanEncrypt());
+  ASSERT_TRUE(cryptographer()->CanEncrypt());
 
   EXPECT_CALL(*storage(), ClearData);
   bridge()->ApplyDisableSyncChanges();
-  EXPECT_FALSE(bridge()->GetCryptographerForTesting().CanEncrypt());
+  EXPECT_FALSE(cryptographer()->CanEncrypt());
 }
 
 // Tests decryption logic for explicit passphrase. In order to check that we're
@@ -1001,10 +991,10 @@
                                                    PASSPHRASE_BOOTSTRAP_TOKEN));
   bridge()->SetDecryptionPassphrase(passphrase_key_params.password);
 
-  const Cryptographer& cryptographer = bridge()->GetCryptographerForTesting();
-  EXPECT_THAT(cryptographer, CanDecryptWith(kOldKeyParams));
-  EXPECT_THAT(cryptographer, CanDecryptWith(passphrase_key_params));
-  EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(passphrase_key_params));
+  EXPECT_THAT(*cryptographer(), CanDecryptWith(kOldKeyParams));
+  EXPECT_THAT(*cryptographer(), CanDecryptWith(passphrase_key_params));
+  EXPECT_THAT(*cryptographer(),
+              HasDefaultKeyDerivedFrom(passphrase_key_params));
 }
 
 INSTANTIATE_TEST_SUITE_P(Scrypt,
@@ -1056,9 +1046,9 @@
   const KeyParams passphrase_key_params = {
       bridge()->GetCustomPassphraseKeyDerivationParamsForTesting(),
       kCustomPassphrase};
-  const Cryptographer& cryptographer = bridge()->GetCryptographerForTesting();
-  EXPECT_THAT(cryptographer, CanDecryptWith(passphrase_key_params));
-  EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(passphrase_key_params));
+  EXPECT_THAT(*cryptographer(), CanDecryptWith(passphrase_key_params));
+  EXPECT_THAT(*cryptographer(),
+              HasDefaultKeyDerivedFrom(passphrase_key_params));
 }
 
 // Tests that pending local change with setting custom passphrase is applied,
@@ -1119,11 +1109,11 @@
   const KeyParams passphrase_key_params = {
       bridge()->GetCustomPassphraseKeyDerivationParamsForTesting(),
       kCustomPassphrase};
-  const Cryptographer& cryptographer = bridge()->GetCryptographerForTesting();
-  EXPECT_THAT(cryptographer, CanDecryptWith(kKeystoreKeyParams1));
-  EXPECT_THAT(cryptographer, CanDecryptWith(kKeystoreKeyParams2));
-  EXPECT_THAT(cryptographer, CanDecryptWith(passphrase_key_params));
-  EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(passphrase_key_params));
+  EXPECT_THAT(*cryptographer(), CanDecryptWith(kKeystoreKeyParams1));
+  EXPECT_THAT(*cryptographer(), CanDecryptWith(kKeystoreKeyParams2));
+  EXPECT_THAT(*cryptographer(), CanDecryptWith(passphrase_key_params));
+  EXPECT_THAT(*cryptographer(),
+              HasDefaultKeyDerivedFrom(passphrase_key_params));
 }
 
 // Tests that SetEncryptionPassphrase() call doesn't lead to custom passphrase
@@ -1170,9 +1160,9 @@
   EXPECT_CALL(observer, OnPassphraseRequired).Times(0);
   ASSERT_THAT(bridge->MergeSyncData(std::move(entity_data)), Eq(base::nullopt));
 
-  const Cryptographer& cryptographer = bridge->GetCryptographerForTesting();
-  EXPECT_THAT(cryptographer, CanDecryptWith(kKeyParams));
-  EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(kKeyParams));
+  EXPECT_THAT(*bridge->GetCryptographer(), CanDecryptWith(kKeyParams));
+  EXPECT_THAT(*bridge->GetCryptographer(),
+              HasDefaultKeyDerivedFrom(kKeyParams));
   bridge->RemoveObserver(&observer);
 }
 
@@ -1238,9 +1228,9 @@
       /*packed_keystore_keys=*/std::string());
 
   // Verify that we restored Cryptographer state.
-  const Cryptographer& cryptographer = bridge2->GetCryptographerForTesting();
-  EXPECT_THAT(cryptographer, CanDecryptWith(kKeystoreKeyParams));
-  EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(kKeystoreKeyParams));
+  EXPECT_THAT(*bridge2->GetCryptographer(), CanDecryptWith(kKeystoreKeyParams));
+  EXPECT_THAT(*bridge2->GetCryptographer(),
+              HasDefaultKeyDerivedFrom(kKeystoreKeyParams));
 }
 
 // Commit with keystore Nigori initialization might be not completed before
@@ -1285,9 +1275,9 @@
   EXPECT_EQ(bridge->GetPassphraseTypeForTesting(),
             sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE);
 
-  const Cryptographer& cryptographer = bridge->GetCryptographerForTesting();
-  EXPECT_THAT(cryptographer, CanDecryptWith(kKeystoreKeyParams));
-  EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(kKeystoreKeyParams));
+  EXPECT_THAT(*bridge->GetCryptographer(), CanDecryptWith(kKeystoreKeyParams));
+  EXPECT_THAT(*bridge->GetCryptographer(),
+              HasDefaultKeyDerivedFrom(kKeystoreKeyParams));
 }
 
 // Tests the initial sync with a trusted vault Nigori. Observers should be
@@ -1508,10 +1498,9 @@
               Eq(AlwaysEncryptedUserTypes()));
   EXPECT_FALSE(bridge()->HasPendingKeysForTesting());
 
-  const Cryptographer& cryptographer = bridge()->GetCryptographerForTesting();
-  EXPECT_THAT(cryptographer, CanDecryptWith(kTrustedVaultKeyParams));
-  EXPECT_THAT(cryptographer, CanDecryptWith(kKeystoreKeyParams));
-  EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(kKeystoreKeyParams));
+  EXPECT_THAT(*cryptographer(), CanDecryptWith(kTrustedVaultKeyParams));
+  EXPECT_THAT(*cryptographer(), CanDecryptWith(kKeystoreKeyParams));
+  EXPECT_THAT(*cryptographer(), HasDefaultKeyDerivedFrom(kKeystoreKeyParams));
 }
 
 // Tests processing of remote incremental update that transits from trusted
@@ -1562,10 +1551,9 @@
                                                    PASSPHRASE_BOOTSTRAP_TOKEN));
   bridge()->SetDecryptionPassphrase(kCustomPassphraseKeyParams.password);
 
-  const Cryptographer& cryptographer = bridge()->GetCryptographerForTesting();
-  EXPECT_THAT(cryptographer, CanDecryptWith(kTrustedVaultKeyParams));
-  EXPECT_THAT(cryptographer, CanDecryptWith(kCustomPassphraseKeyParams));
-  EXPECT_THAT(cryptographer,
+  EXPECT_THAT(*cryptographer(), CanDecryptWith(kTrustedVaultKeyParams));
+  EXPECT_THAT(*cryptographer(), CanDecryptWith(kCustomPassphraseKeyParams));
+  EXPECT_THAT(*cryptographer(),
               HasDefaultKeyDerivedFrom(kCustomPassphraseKeyParams));
 }
 
@@ -1744,7 +1732,7 @@
   ASSERT_FALSE(bridge()->HasPendingKeysForTesting());
 
   const CryptographerImpl& cryptographer =
-      bridge()->GetCryptographerForTesting();
+      bridge()->GetCryptographerImplForTesting();
   ASSERT_THAT(cryptographer,
               CanDecryptWith(TrustedVaultKeyParams(kTrustedVaultKey1)));
   EXPECT_THAT(cryptographer,
@@ -1805,11 +1793,12 @@
   EXPECT_THAT(bridge2->ApplySyncChanges(base::nullopt), Eq(base::nullopt));
   EXPECT_THAT(bridge2->GetData(), HasKeystoreNigori());
 
-  // Ensure that |cryptographer| corresponds to full keystore Nigori.
-  const Cryptographer& cryptographer = bridge2->GetCryptographerForTesting();
-  EXPECT_THAT(cryptographer, CanDecryptWith(kKeystoreKeyParams));
-  EXPECT_THAT(cryptographer, CanDecryptWith(kPassphraseKeyParams));
-  EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(kKeystoreKeyParams));
+  // Ensure the cryptographer corresponds to full keystore Nigori.
+  EXPECT_THAT(*bridge2->GetCryptographer(), CanDecryptWith(kKeystoreKeyParams));
+  EXPECT_THAT(*bridge2->GetCryptographer(),
+              CanDecryptWith(kPassphraseKeyParams));
+  EXPECT_THAT(*bridge2->GetCryptographer(),
+              HasDefaultKeyDerivedFrom(kKeystoreKeyParams));
 }
 
 // Tests that upon startup bridge adds keystore keys into cryptographer, so it
@@ -1857,15 +1846,16 @@
       /*packed_explicit_passphrase_key=*/std::string(),
       /*packed_keystore_keys=*/std::string());
 
-  // Ensure that |cryptographer| can decrypt with keystore keys, but still
-  // has default key derived from custom passphrase.
+  // Ensure the cryptographer can decrypt with keystore keys, but still has
+  // default key derived from custom passphrase.
   const KeyParams kPassphraseKeyParams = {
       bridge2->GetCustomPassphraseKeyDerivationParamsForTesting(), kPassphrase};
-  const Cryptographer& cryptographer = bridge2->GetCryptographerForTesting();
-  EXPECT_THAT(cryptographer,
+  EXPECT_THAT(*bridge2->GetCryptographer(),
               CanDecryptWith(KeystoreKeyParams(kRawKeystoreKey)));
-  EXPECT_THAT(cryptographer, CanDecryptWith(kPassphraseKeyParams));
-  EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(kPassphraseKeyParams));
+  EXPECT_THAT(*bridge2->GetCryptographer(),
+              CanDecryptWith(kPassphraseKeyParams));
+  EXPECT_THAT(*bridge2->GetCryptographer(),
+              HasDefaultKeyDerivedFrom(kPassphraseKeyParams));
 }
 
 }  // namespace
diff --git a/components/sync/nigori/pending_local_nigori_commit.cc b/components/sync/nigori/pending_local_nigori_commit.cc
index b9a0af3..c8b1bea 100644
--- a/components/sync/nigori/pending_local_nigori_commit.cc
+++ b/components/sync/nigori/pending_local_nigori_commit.cc
@@ -121,10 +121,12 @@
       return false;
     }
 
+    std::unique_ptr<CryptographerImpl> cryptographer =
+        state->keystore_keys_cryptographer->ToCryptographerImpl();
+    DCHECK(!cryptographer->GetDefaultEncryptionKeyName().empty());
+    state->cryptographer->EmplaceKeysAndSelectDefaultKeyFrom(*cryptographer);
     state->passphrase_type = NigoriSpecifics::KEYSTORE_PASSPHRASE;
     state->keystore_migration_time = base::Time::Now();
-    state->cryptographer =
-        state->keystore_keys_cryptographer->ToCryptographerImpl();
     return true;
   }
 
diff --git a/components/sync/test/engine/fake_cryptographer.cc b/components/sync/test/engine/fake_cryptographer.cc
index b729093..e86a3b6 100644
--- a/components/sync/test/engine/fake_cryptographer.cc
+++ b/components/sync/test/engine/fake_cryptographer.cc
@@ -44,13 +44,6 @@
   default_key_name_.clear();
 }
 
-std::unique_ptr<Cryptographer> FakeCryptographer::Clone() const {
-  auto new_cryptographer = std::make_unique<FakeCryptographer>();
-  new_cryptographer->known_key_names_ = known_key_names_;
-  new_cryptographer->default_key_name_ = default_key_name_;
-  return new_cryptographer;
-}
-
 bool FakeCryptographer::CanEncrypt() const {
   return !default_key_name_.empty();
 }
diff --git a/components/sync/test/engine/fake_cryptographer.h b/components/sync/test/engine/fake_cryptographer.h
index 0754cdd..ed14710 100644
--- a/components/sync/test/engine/fake_cryptographer.h
+++ b/components/sync/test/engine/fake_cryptographer.h
@@ -38,7 +38,6 @@
   void ClearDefaultEncryptionKey();
 
   // Cryptographer implementation.
-  std::unique_ptr<Cryptographer> Clone() const override;
   bool CanEncrypt() const override;
   bool CanDecrypt(const sync_pb::EncryptedData& encrypted) const override;
   std::string GetDefaultEncryptionKeyName() const override;
diff --git a/components/sync/test/engine/fake_sync_engine.cc b/components/sync/test/engine/fake_sync_engine.cc
index 5bce8338..37636265e 100644
--- a/components/sync/test/engine/fake_sync_engine.cc
+++ b/components/sync/test/engine/fake_sync_engine.cc
@@ -30,7 +30,7 @@
 
   initialized_ = success;
 
-  host_->OnEngineInitialized(WeakHandle<JsBackend>(),
+  host_->OnEngineInitialized(ModelTypeSet(), WeakHandle<JsBackend>(),
                              WeakHandle<DataTypeDebugInfoListener>(), success,
                              is_first_time_sync_configure_);
 }
@@ -118,6 +118,9 @@
 void FakeSyncEngine::HasUnsyncedItemsForTest(
     base::OnceCallback<void(bool)> cb) const {}
 
+void FakeSyncEngine::GetThrottledDataTypesForTest(
+    base::OnceCallback<void(ModelTypeSet)> cb) const {}
+
 void FakeSyncEngine::RequestBufferedProtocolEventsAndEnableForwarding() {}
 
 void FakeSyncEngine::DisableProtocolEventForwarding() {}
diff --git a/components/sync/test/engine/fake_sync_engine.h b/components/sync/test/engine/fake_sync_engine.h
index 842cf89a..f5ace28 100644
--- a/components/sync/test/engine/fake_sync_engine.h
+++ b/components/sync/test/engine/fake_sync_engine.h
@@ -93,6 +93,8 @@
 
   void HasUnsyncedItemsForTest(
       base::OnceCallback<void(bool)> cb) const override;
+  void GetThrottledDataTypesForTest(
+      base::OnceCallback<void(ModelTypeSet)> cb) const override;
 
   void RequestBufferedProtocolEventsAndEnableForwarding() override;
   void DisableProtocolEventForwarding() override;
diff --git a/components/sync/test/engine/mock_sync_engine.h b/components/sync/test/engine/mock_sync_engine.h
index 6defa4f..a6c6ba7 100644
--- a/components/sync/test/engine/mock_sync_engine.h
+++ b/components/sync/test/engine/mock_sync_engine.h
@@ -68,6 +68,10 @@
               (base::OnceCallback<void(bool)>),
               (const override));
   MOCK_METHOD(void,
+              GetThrottledDataTypesForTest,
+              (base::OnceCallback<void(ModelTypeSet)>),
+              (const override));
+  MOCK_METHOD(void,
               RequestBufferedProtocolEventsAndEnableForwarding,
               (),
               (override));
diff --git a/components/sync/test/engine/sync_engine_host_stub.cc b/components/sync/test/engine/sync_engine_host_stub.cc
index 86282a2..c9242f25 100644
--- a/components/sync/test/engine/sync_engine_host_stub.cc
+++ b/components/sync/test/engine/sync_engine_host_stub.cc
@@ -10,6 +10,7 @@
 SyncEngineHostStub::~SyncEngineHostStub() = default;
 
 void SyncEngineHostStub::OnEngineInitialized(
+    ModelTypeSet initial_types,
     const WeakHandle<JsBackend>& js_backend,
     const WeakHandle<DataTypeDebugInfoListener>& debug_info_listener,
     bool success,
diff --git a/components/sync/test/engine/sync_engine_host_stub.h b/components/sync/test/engine/sync_engine_host_stub.h
index d598b0a..57a633c 100644
--- a/components/sync/test/engine/sync_engine_host_stub.h
+++ b/components/sync/test/engine/sync_engine_host_stub.h
@@ -18,6 +18,7 @@
 
   // SyncEngineHost implementation.
   void OnEngineInitialized(
+      ModelTypeSet initial_types,
       const WeakHandle<JsBackend>& js_backend,
       const WeakHandle<DataTypeDebugInfoListener>& debug_info_listener,
       bool success,
diff --git a/components/sync/test/fake_sync_encryption_handler.cc b/components/sync/test/fake_sync_encryption_handler.cc
index 3a61407..2385ed3 100644
--- a/components/sync/test/fake_sync_encryption_handler.cc
+++ b/components/sync/test/fake_sync_encryption_handler.cc
@@ -71,4 +71,9 @@
   return this;
 }
 
+Cryptographer* FakeSyncEncryptionHandler::GetCryptographer() {
+  // GetCryptographer() must never return null.
+  return &fake_cryptographer_;
+}
+
 }  // namespace syncer
diff --git a/components/sync/test/fake_sync_encryption_handler.h b/components/sync/test/fake_sync_encryption_handler.h
index 9e2902a..7d9897b 100644
--- a/components/sync/test/fake_sync_encryption_handler.h
+++ b/components/sync/test/fake_sync_encryption_handler.h
@@ -14,6 +14,7 @@
 #include "base/time/time.h"
 #include "components/sync/engine/nigori/keystore_keys_handler.h"
 #include "components/sync/engine/sync_encryption_handler.h"
+#include "components/sync/test/engine/fake_cryptographer.h"
 
 namespace syncer {
 
@@ -39,6 +40,7 @@
       const std::vector<std::vector<uint8_t>>& keys) override;
   base::Time GetKeystoreMigrationTime() const override;
   KeystoreKeysHandler* GetKeystoreKeysHandler() override;
+  Cryptographer* GetCryptographer() override;
 
   // KeystoreKeysHandler implementation.
   bool NeedKeystoreKey() const override;
@@ -47,6 +49,7 @@
  private:
   base::ObserverList<SyncEncryptionHandler::Observer>::Unchecked observers_;
   std::vector<uint8_t> keystore_key_;
+  FakeCryptographer fake_cryptographer_;
 };
 
 }  // namespace syncer
diff --git a/components/user_manager/user.cc b/components/user_manager/user.cc
index b4a65b4..929f8e5 100644
--- a/components/user_manager/user.cc
+++ b/components/user_manager/user.cc
@@ -282,7 +282,15 @@
 }
 
 bool User::IsAffiliated() const {
-  return is_affiliated_;
+  return is_affiliated_.value_or(false);
+}
+
+void User::IsAffiliatedAsync(
+    base::OnceCallback<void(bool)> is_affiliated_callback) {
+  if (is_affiliated_.has_value())
+    std::move(is_affiliated_callback).Run(is_affiliated_.value());
+  else
+    on_affiliation_set_callbacks_.push_back(std::move(is_affiliated_callback));
 }
 
 void User::SetProfileIsCreated() {
@@ -294,6 +302,9 @@
 
 void User::SetAffiliation(bool is_affiliated) {
   is_affiliated_ = is_affiliated;
+  for (auto& callback : on_affiliation_set_callbacks_)
+    std::move(callback).Run(is_affiliated_.value());
+  on_affiliation_set_callbacks_.clear();
 }
 
 bool User::IsDeviceLocalAccount() const {
diff --git a/components/user_manager/user.h b/components/user_manager/user.h
index 4dcee56c..0e89af4 100644
--- a/components/user_manager/user.h
+++ b/components/user_manager/user.h
@@ -111,9 +111,15 @@
   // The displayed (non-canonical) user email.
   virtual std::string display_email() const;
 
-  // True if the user is affiliated to the device.
+  // True if the user is affiliated to the device. Returns false if the
+  // affiliation is not known. Use IsAffiliatedAsync if it's possible the call
+  // is done before affiliation is established.
   virtual bool IsAffiliated() const;
 
+  // Runs the callback immediately if the affiliation is known, otherwise later
+  // when the affiliation is established.
+  void IsAffiliatedAsync(base::OnceCallback<void(bool)> is_affiliated_callback);
+
   // True if the user is a device local account user.
   virtual bool IsDeviceLocalAccount() const;
 
@@ -329,9 +335,11 @@
   bool profile_is_created_ = false;
 
   // True if the user is affiliated to the device.
-  bool is_affiliated_ = false;
+  base::Optional<bool> is_affiliated_;
 
   std::vector<base::OnceClosure> on_profile_created_observers_;
+  std::vector<base::OnceCallback<void(bool is_affiliated)>>
+      on_affiliation_set_callbacks_;
 
   DISALLOW_COPY_AND_ASSIGN(User);
 };
diff --git a/components/viz/service/display/overlay_unittest.cc b/components/viz/service/display/overlay_unittest.cc
index ae1e6e7..d0f4a8c 100644
--- a/components/viz/service/display/overlay_unittest.cc
+++ b/components/viz/service/display/overlay_unittest.cc
@@ -4338,18 +4338,11 @@
           quad_candidate->shared_quad_state->overlay_damage_index.has_value());
     }
 
-    // We have to find the occluder end of our list as it changes each
-    // iteration.
-    auto iter_occluder_end = quad_list.begin();
-    for (size_t j = 0; j < occluder_iter_count; j++) {
-      iter_occluder_end++;
-    }
-
     // Now we test the opaque occlusion provided by 'EstimateOccludedDamage'
     // function.
     candidate.damage_area_estimate = OverlayCandidate::EstimateVisibleDamage(
         quad_candidate, &surface_damage_rect_list, quad_list.begin(),
-        iter_occluder_end);
+        std::next(quad_list.begin(), occluder_iter_count));
 
     ASSERT_EQ(kExpectedDamages[i], candidate.damage_area_estimate);
   }
diff --git a/components/webapps/browser/android/add_to_homescreen_data_fetcher.cc b/components/webapps/browser/android/add_to_homescreen_data_fetcher.cc
index ec31bfc7c..c2a598f 100644
--- a/components/webapps/browser/android/add_to_homescreen_data_fetcher.cc
+++ b/components/webapps/browser/android/add_to_homescreen_data_fetcher.cc
@@ -136,7 +136,7 @@
   auto* web_page_metadata_proxy = metadata_agent.get();
   web_page_metadata_proxy->GetWebPageMetadata(base::BindOnce(
       &AddToHomescreenDataFetcher::OnDidGetWebPageMetadata,
-      weak_ptr_factory_.GetWeakPtr(), base::Passed(&metadata_agent)));
+      weak_ptr_factory_.GetWeakPtr(), std::move(metadata_agent)));
 }
 
 AddToHomescreenDataFetcher::~AddToHomescreenDataFetcher() = default;
diff --git a/content/browser/accessibility/dump_accessibility_browsertest_base.cc b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
index e4e6f26..68c7fb8 100644
--- a/content/browser/accessibility/dump_accessibility_browsertest_base.cc
+++ b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
@@ -448,7 +448,7 @@
                                                  const std::string& value) {
   std::string result;
   if (node.GetHtmlAttribute(attr, &result))
-    return true;
+    return result == value;
 
   if (base::LowerCaseEqualsASCII(attr, "class"))
     return node.GetStringAttribute(ax::mojom::StringAttribute::kClassName) ==
diff --git a/content/browser/accessibility/dump_accessibility_node_browsertest.cc b/content/browser/accessibility/dump_accessibility_node_browsertest.cc
index c727139..efefb77 100644
--- a/content/browser/accessibility/dump_accessibility_node_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_node_browsertest.cc
@@ -8,6 +8,7 @@
 #include "content/public/test/browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
 #include "content/shell/browser/shell.h"
+#include "net/base/escape.h"
 #include "ui/accessibility/accessibility_switches.h"
 
 namespace content {
@@ -55,7 +56,9 @@
 
     std::string contents =
         test_node ? formatter->FormatNode(test_node) : "Test node not found.";
-    return base::SplitString(contents, "\n", base::KEEP_WHITESPACE,
+
+    std::string escaped_contents = net::EscapeNonASCII(contents);
+    return base::SplitString(escaped_contents, "\n", base::KEEP_WHITESPACE,
                              base::SPLIT_WANT_NONEMPTY);
   }
 
@@ -80,6 +83,37 @@
   }
 };
 
+class DumpAccessibilityAccNameTest : public DumpAccessibilityNodeTest {
+ public:
+  std::vector<ui::AXPropertyFilter> DefaultFilters() const override {
+    std::vector<AXPropertyFilter> property_filters;
+    property_filters.emplace_back("name*", AXPropertyFilter::ALLOW_EMPTY);
+    property_filters.emplace_back("description*",
+                                  AXPropertyFilter::ALLOW_EMPTY);
+
+    // Since we normally care about the name and/or description, filter out
+    // various irrelevant states and properties.
+    property_filters.emplace_back("checkable", AXPropertyFilter::DENY);
+    property_filters.emplace_back("clickable", AXPropertyFilter::DENY);
+    property_filters.emplace_back("editable*", AXPropertyFilter::DENY);
+    property_filters.emplace_back("focusable", AXPropertyFilter::DENY);
+    property_filters.emplace_back("horizontal", AXPropertyFilter::DENY);
+    property_filters.emplace_back("multiselectable", AXPropertyFilter::DENY);
+    property_filters.emplace_back("vertical", AXPropertyFilter::DENY);
+    return property_filters;
+  }
+
+  void RunAccNameTest(const base::FilePath::CharType* file_path) {
+    base::FilePath test_path = GetTestFilePath("accessibility", "accname");
+    {
+      base::ScopedAllowBlockingForTesting allow_blocking;
+      ASSERT_TRUE(base::PathExists(test_path)) << test_path.LossyDisplayName();
+    }
+    base::FilePath accname_file = test_path.Append(base::FilePath(file_path));
+    RunTest(accname_file, "accessibility/accname");
+  }
+};
+
 // Parameterize the tests so that each test-pass is run independently.
 struct TestPassToString {
   std::string operator()(
@@ -94,6 +128,12 @@
     ::testing::ValuesIn(DumpAccessibilityTestHelper::TreeTestPasses()),
     TestPassToString());
 
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    DumpAccessibilityAccNameTest,
+    ::testing::ValuesIn(DumpAccessibilityTestHelper::TreeTestPasses()),
+    TestPassToString());
+
 // ARIA tests.
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityNodeTest, AccessibilityAriaScrollbar) {
   RunAriaTest(FILE_PATH_LITERAL("aria-scrollbar.html"));
@@ -105,4 +145,668 @@
   RunHtmlTest(FILE_PATH_LITERAL("table-th-colheader.html"));
 }
 
+// AccName tests.
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, DescComboboxFocusable) {
+  RunAccNameTest(FILE_PATH_LITERAL("desc-combobox-focusable.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       DescFromContentOfDescribedbyElement) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("desc-from-content-of-describedby-element.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       DescImgAltDescribedbyHidden) {
+  RunAccNameTest(FILE_PATH_LITERAL("desc-img-alt-describedby-hidden.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, DescImgAltDescribedby) {
+  RunAccNameTest(FILE_PATH_LITERAL("desc-img-alt-describedby.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       DescImgAltDescribedbyInvalid) {
+  RunAccNameTest(FILE_PATH_LITERAL("desc-img-alt-describedby-invalid.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       DescImgAltDescribedbyNotDisplayed) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("desc-img-alt-describedby-not-displayed.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       DescImgAltDescribedbyPresentational) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("desc-img-alt-describedby-presentational.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, DescImgDescribedby) {
+  RunAccNameTest(FILE_PATH_LITERAL("desc-img-describedby.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       DescImgDescribedbyNotDisplayed) {
+  RunAccNameTest(FILE_PATH_LITERAL("desc-img-describedby-not-displayed.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       DescImgDescribedbyPresentational) {
+  RunAccNameTest(FILE_PATH_LITERAL("desc-img-describedby-presentational.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, DescImgLabelAltTitle) {
+  RunAccNameTest(FILE_PATH_LITERAL("desc-img-label-alt-title.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       DescImgOneValidDescribedby) {
+  RunAccNameTest(FILE_PATH_LITERAL("desc-img-one-valid-describedby.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       DescInputTitleAndDescribedby) {
+  RunAccNameTest(FILE_PATH_LITERAL("desc-input-title-and-describedby.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       DescLinkWithLabelAndTitle) {
+  RunAccNameTest(FILE_PATH_LITERAL("desc-link-with-label-and-title.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameButtonLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-button-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameButtonLabelLabelledby) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-button-label-labelledby.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameButtonLabelledby) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-button-labelledby.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameButtonRoleContentOnly) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-button-role-content-only.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameButtonRoleTitleOnly) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-button-role-title-only.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameButtonValue) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-button-value.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameCheckboxCssAfterInLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-checkbox-css-after-in-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameCheckboxCssBeforeInLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-checkbox-css-before-in-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameCheckboxInputInLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-checkbox-input-in-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameCheckboxInsideLabelWithGeneratedContent) {
+  RunAccNameTest(FILE_PATH_LITERAL(
+      "name-checkbox-inside-label-with-generated-content.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameCheckboxLabelEmbeddedCombobox) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("name-checkbox-label-embedded-combobox.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameCheckboxLabelEmbeddedListbox) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("name-checkbox-label-embedded-listbox.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameCheckboxLabelEmbeddedMenu) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-checkbox-label-embedded-menu.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameCheckboxLabelEmbeddedSelect) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-checkbox-label-embedded-select.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameCheckboxLabelEmbeddedSlider) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-checkbox-label-embedded-slider.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameCheckboxLabelEmbeddedSpinbutton) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("name-checkbox-label-embedded-spinbutton.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameCheckboxLabelEmbeddedTextbox) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("name-checkbox-label-embedded-textbox.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameCheckboxLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-checkbox-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameCheckboxLabelMultipleLabelAlternative) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("name-checkbox-label-multiple-label-alternative.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameCheckboxLabelMultipleLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-checkbox-label-multiple-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameCheckboxLabelWithInput) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-checkbox-label-with-input.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameCheckboxSpinbuttonValuenowInLabel) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("name-checkbox-spinbutton-valuenow-in-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameCheckboxTitle) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-checkbox-title.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameComboboxFocusableAlternative) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-combobox-focusable-alternative.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameComboboxFocusable) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-combobox-focusable.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameDivContentOnly) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-div-content-only.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameDivLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-div-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameDivLabelLabelledby) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-div-label-labelledby.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameDivLabelledby) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-div-labelledby.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameDivMultipleSources) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-div-multiple-sources.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameFileCssAfterInLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-file-css-after-in-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameFileCssBeforeInLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-file-css-before-in-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameFileInLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-file-in-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameFileLabelEmbeddedCombobox) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-file-label-embedded-combobox.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameFileLabelEmbeddedMenu) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-file-label-embedded-menu.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameFileLabelEmbeddedSelect) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-file-label-embedded-select.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameFileLabelEmbeddedSlider) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-file-label-embedded-slider.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameFileLabelEmbeddedSpinbutton) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-file-label-embedded-spinbutton.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameFileLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-file-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameFileLabelInlineBlockElements) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("name-file-label-inline-block-elements.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameFileLabelInlineBlockStyles) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-file-label-inline-block-styles.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameFileLabelInlineHiddenElements) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("name-file-label-inline-hidden-elements.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameFileLabelOwnedCombobox) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-file-label-owned-combobox.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameFileLabelOwnedComboboxOwnedListbox) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("name-file-label-owned-combobox-owned-listbox.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameFileLabelWithInput) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-file-label-with-input.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameFileSpinbuttonValuenowInLabel) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("name-file-spinbutton-valuenow-in-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameFileTitle) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-file-title.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameFromContent) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-from-content.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameFromContentOfLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-from-content-of-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameFromContentOfLabelledbyElement) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("name-from-content-of-labelledby-element.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameFromContentOfLabelledbyElementsOneOfWhichIsHidden) {
+  RunAccNameTest(FILE_PATH_LITERAL(
+      "name-from-content-of-labelledby-elements-one-of-which-is-hidden.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameHeadingComboboxFocusableAlternative) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("name-heading-combobox-focusable-alternative.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameImageCssAfterInLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-image-css-after-in-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameImageCssBeforeInLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-image-css-before-in-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameImageInputAlt) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-image-input-alt.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameImageInputInsideLabelWithGeneratedContent) {
+  RunAccNameTest(FILE_PATH_LITERAL(
+      "name-image-input-inside-label-with-generated-content.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameImageInputLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-image-input-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameImageInputLabelWithInput) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-image-input-label-with-input.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameImageSpinbuttonValuenowInLabel) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("name-image-spinbutton-valuenow-in-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameImageTitle) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-image-title.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameImgLabelAltTitle) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-img-label-alt-title.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameImgLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-img-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameImgLabelledbyInputs) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-img-labelledby-inputs.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameImgLabelledbySelfAndInput) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-img-labelledby-self-and-input.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameImgLabelledbySelfAndTwoInputs) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("name-img-labelledby-self-and-two-inputs.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameImgLabelledbySelf) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-img-labelledby-self.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameImgMultipleSources) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-img-multiple-sources.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameImgMultipleSourcesSomeEmpty) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("name-img-multiple-sources-some-empty.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameImgWithLabelLabelsItself) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-img-with-label-labels-itself.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameLinkContentOnly) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-link-content-only.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameLinkEmptyWithTitle) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-link-empty-with-title.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameLinkLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-link-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameLinkLabelledby) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-link-labelledby.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameLinkLabelledbySelfAndParagraph) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("name-link-labelledby-self-and-paragraph.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameLinkLabelTitle) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-link-label-title.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameLinkMixedContent) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-link-mixed-content.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameLinkMultipleSources) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-link-multiple-sources.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NamePasswordCssAfterInLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-password-css-after-in-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NamePasswordCssBeforeInLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-password-css-before-in-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NamePasswordInputInLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-password-input-in-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NamePasswordInsideLabelWithGeneratedContent) {
+  RunAccNameTest(FILE_PATH_LITERAL(
+      "name-password-inside-label-with-generated-content.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NamePasswordLabelEmbeddedCombobox) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("name-password-label-embedded-combobox.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NamePasswordLabelEmbeddedMenu) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-password-label-embedded-menu.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NamePasswordLabelEmbeddedSelect) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-password-label-embedded-select.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NamePasswordLabelEmbeddedSlider) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-password-label-embedded-slider.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NamePasswordLabelEmbeddedSpinbutton) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("name-password-label-embedded-spinbutton.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NamePasswordLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-password-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NamePasswordLabelWithInput) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-password-label-with-input.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NamePasswordTitle) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-password-title.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameRadioCssAfterInLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-radio-css-after-in-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameRadioCssBeforeInLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-radio-css-before-in-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameRadioInputInLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-radio-input-in-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameRadioInsideLabelWithGeneratedContent) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("name-radio-inside-label-with-generated-content.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameRadioLabelEmbeddedCombobox) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-radio-label-embedded-combobox.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameRadioLabelEmbeddedMenu) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-radio-label-embedded-menu.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameRadioLabelEmbeddedSelect) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-radio-label-embedded-select.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameRadioLabelEmbeddedSlider) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-radio-label-embedded-slider.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameRadioLabelEmbeddedSpinbutton) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("name-radio-label-embedded-spinbutton.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameRadioLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-radio-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameRadioLabelWithInput) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-radio-label-with-input.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameRadioSpinbuttonValuenowInLabel) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("name-radio-spinbutton-valuenow-in-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameRadioTitle) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-radio-title.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameResetButton) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-reset-button.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameTextCssAfterInLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-text-css-after-in-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameTextCssBeforeInLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-text-css-before-in-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameTextInputInLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-text-input-in-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameTextInsideLabelWithGeneratedContent) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("name-text-inside-label-with-generated-content.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameTextLabelEmbeddedCombobox) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-text-label-embedded-combobox.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameTextLabelEmbeddedMenu) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-text-label-embedded-menu.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameTextLabelEmbeddedSelect) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-text-label-embedded-select.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameTextLabelEmbeddedSlider) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-text-label-embedded-slider.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameTextLabelEmbeddedSpinbutton) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-text-label-embedded-spinbutton.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameTextLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-text-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameTextLabelledbyParagraphs) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-text-labelledby-paragraphs.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameTextLabelledbySelfAndDiv) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-text-labelledby-self-and-div.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameTextLabelWithInput) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-text-label-with-input.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameTextSelectInLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-text-select-in-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameTextSpinbuttonValuenowInLabel) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("name-text-spinbutton-valuenow-in-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameTextSpinbuttonValuetextInLabel) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("name-text-spinbutton-valuetext-in-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameTextTitle) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-text-title.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameTextTitleValue) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-text-title-value.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest, NameTextWithLabel) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-text-with-label.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameTextWithValueLabelsImg) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-text-with-value-labels-img.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityAccNameTest,
+                       NameTextWithValueLabelsImgWithLabel) {
+  RunAccNameTest(
+      FILE_PATH_LITERAL("name-text-with-value-labels-img-with-label.html"));
+}
+
 }  // namespace content
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index f705cb2..f957482 100644
--- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -83,6 +83,16 @@
         switches::kDisableAXMenuList, "false");
   }
 
+  void RunAccNameTest(const base::FilePath::CharType* file_path) {
+    base::FilePath test_path = GetTestFilePath("accessibility", "accname");
+    {
+      base::ScopedAllowBlockingForTesting allow_blocking;
+      ASSERT_TRUE(base::PathExists(test_path)) << test_path.LossyDisplayName();
+    }
+    base::FilePath accname_file = test_path.Append(base::FilePath(file_path));
+    RunTest(accname_file, "accessibility/accname", FILE_PATH_LITERAL("tree"));
+  }
+
   void RunAriaTest(const base::FilePath::CharType* file_path) {
     base::FilePath test_path = GetTestFilePath("accessibility", "aria");
     {
@@ -3066,6 +3076,13 @@
 }
 
 //
+// AccName tests where having the full tree is desired.
+//
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, NameImgLabelledbyInputs) {
+  RunAccNameTest(FILE_PATH_LITERAL("name-img-labelledby-inputs.html"));
+}
+
+//
 // These tests cover features of the testing infrastructure itself.
 //
 
diff --git a/content/browser/android/battery_metrics.cc b/content/browser/android/battery_metrics.cc
index 7299612..c09201b2 100644
--- a/content/browser/android/battery_metrics.cc
+++ b/content/browser/android/battery_metrics.cc
@@ -146,13 +146,13 @@
 AndroidBatteryMetrics::AndroidBatteryMetrics()
     : app_visible_(false),
       on_battery_power_(base::PowerMonitor::IsOnBatteryPower()) {
-  base::PowerMonitor::AddObserver(this);
+  base::PowerMonitor::AddPowerStateObserver(this);
   content::ProcessVisibilityTracker::GetInstance()->AddObserver(this);
   UpdateMetricsEnabled();
 }
 
 AndroidBatteryMetrics::~AndroidBatteryMetrics() {
-  base::PowerMonitor::RemoveObserver(this);
+  base::PowerMonitor::RemovePowerStateObserver(this);
 }
 
 void AndroidBatteryMetrics::OnVisibilityChanged(bool visible) {
diff --git a/content/browser/android/battery_metrics.h b/content/browser/android/battery_metrics.h
index 50debeb..927848a 100644
--- a/content/browser/android/battery_metrics.h
+++ b/content/browser/android/battery_metrics.h
@@ -19,7 +19,7 @@
 // while the device is not charging and the app is visible. This class is not
 // thread-safe.
 class AndroidBatteryMetrics
-    : public base::PowerObserver,
+    : public base::PowerStateObserver,
       public ProcessVisibilityTracker::ProcessVisibilityObserver {
  public:
   static AndroidBatteryMetrics* GetInstance();
@@ -32,7 +32,7 @@
   AndroidBatteryMetrics();
   ~AndroidBatteryMetrics() override;
 
-  // base::PowerObserver implementation:
+  // base::PowerStateObserver implementation:
   void OnPowerStateChange(bool on_battery_power) override;
 
   void UpdateMetricsEnabled();
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 72693b82..cbce0e5b0 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -642,11 +642,19 @@
   // PostMainMessageLoopStart() below.
 
   TRACE_EVENT0("startup", "BrowserMainLoop::MainMessageLoopStart");
+
+  base::PlatformThread::SetName("CrBrowserMain");
+
+  // Register the main thread. The main thread's task runner should already have
+  // been initialized but it's not yet known as BrowserThread::UI.
+  DCHECK(base::ThreadTaskRunnerHandle::IsSet());
   DCHECK(base::CurrentUIThread::IsSet());
-  InitializeMainThread();
+  main_thread_.reset(new BrowserThreadImpl(
+      BrowserThread::UI, base::ThreadTaskRunnerHandle::Get()));
 }
 
 void BrowserMainLoop::PostMainMessageLoopStart() {
+  TRACE_EVENT0("startup", "BrowserMainLoop::PostMainMessageLoopStart");
   {
     TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:SystemMonitor");
     system_monitor_.reset(new base::SystemMonitor);
@@ -815,10 +823,6 @@
   return result_code_;
 }
 
-void BrowserMainLoop::PreShutdown() {
-  ui::Clipboard::OnPreShutdownForCurrentThread();
-}
-
 void BrowserMainLoop::CreateStartupTasks() {
   TRACE_EVENT0("startup", "BrowserMainLoop::CreateStartupTasks");
 
@@ -848,10 +852,6 @@
       &BrowserMainLoop::PostCreateThreads, base::Unretained(this));
   startup_task_runner_->AddTask(std::move(post_create_threads));
 
-  StartupTask browser_thread_started = base::BindOnce(
-      &BrowserMainLoop::BrowserThreadsStarted, base::Unretained(this));
-  startup_task_runner_->AddTask(std::move(browser_thread_started));
-
   StartupTask pre_main_message_loop_run = base::BindOnce(
       &BrowserMainLoop::PreMainMessageLoopRun, base::Unretained(this));
   startup_task_runner_->AddTask(std::move(pre_main_message_loop_run));
@@ -925,19 +925,23 @@
 }
 
 int BrowserMainLoop::PostCreateThreads() {
+  TRACE_EVENT0("startup", "BrowserMainLoop::PostCreateThreads");
+
   tracing_controller_ = std::make_unique<content::TracingControllerImpl>();
   content::BackgroundTracingManagerImpl::GetInstance()
       ->AddMetadataGeneratorFunction();
 
-  if (parts_) {
-    TRACE_EVENT0("startup", "BrowserMainLoop::PostCreateThreads");
+  if (parts_)
     parts_->PostCreateThreads();
-  }
+
+  PostCreateThreadsImpl();
 
   return result_code_;
 }
 
 int BrowserMainLoop::PreMainMessageLoopRun() {
+  TRACE_EVENT0("startup", "BrowserMainLoop::PreMainMessageLoopRun");
+
 #if defined(OS_ANDROID)
   bool use_display_wide_color_gamut =
       GetContentClient()->browser()->GetWideColorGamutHeuristic() ==
@@ -946,11 +950,8 @@
   ui::SetScreenAndroid(use_display_wide_color_gamut);
 #endif
 
-  if (parts_) {
-    TRACE_EVENT0("startup", "BrowserMainLoop::PreMainMessageLoopRun");
-
-    parts_->PreMainMessageLoopRun();
-  }
+  if (parts_)
+    result_code_ = parts_->PreMainMessageLoopRun();
 
 #if defined(OS_WIN)
   // ShellBrowserMainParts initializes a ShellBrowserContext with a profile
@@ -972,13 +973,21 @@
   return result_code_;
 }
 
-void BrowserMainLoop::RunMainMessageLoopParts() {
-  bool ran_main_loop = false;
-  if (parts_)
-    ran_main_loop = parts_->MainMessageLoopRun(&result_code_);
+void BrowserMainLoop::RunMainMessageLoop() {
+#if defined(OS_ANDROID)
+  // Android's main message loop is the Java message loop.
+  NOTREACHED();
+#else   // defined(OS_ANDROID)
 
-  if (!ran_main_loop)
-    MainMessageLoopRun();
+  auto main_run_loop = std::make_unique<base::RunLoop>();
+  parts_->WillRunMainMessageLoop(main_run_loop);
+  if (main_run_loop)
+    main_run_loop->Run();
+#endif  // defined(OS_ANDROID)
+}
+
+void BrowserMainLoop::PreShutdown() {
+  ui::Clipboard::OnPreShutdownForCurrentThread();
 }
 
 void BrowserMainLoop::ShutdownThreadsAndCleanUp() {
@@ -1139,20 +1148,8 @@
 #endif
 }
 
-void BrowserMainLoop::InitializeMainThread() {
-  TRACE_EVENT0("startup", "BrowserMainLoop::InitializeMainThread");
-  base::PlatformThread::SetName("CrBrowserMain");
-
-  // Register the main thread. The main thread's task runner should already have
-  // been initialized in MainMessageLoopStart() (or before if
-  // CurrentThread::Get() was externally provided).
-  DCHECK(base::ThreadTaskRunnerHandle::IsSet());
-  main_thread_.reset(new BrowserThreadImpl(
-      BrowserThread::UI, base::ThreadTaskRunnerHandle::Get()));
-}
-
-int BrowserMainLoop::BrowserThreadsStarted() {
-  TRACE_EVENT0("startup", "BrowserMainLoop::BrowserThreadsStarted");
+void BrowserMainLoop::PostCreateThreadsImpl() {
+  TRACE_EVENT0("startup", "BrowserMainLoop::PostCreateThreadsImpl");
 
   // Bring up Mojo IPC and the embedded Service Manager as early as possible.
   // Initializaing mojo requires the IO thread to have been initialized first,
@@ -1227,17 +1224,17 @@
 #endif
 
   {
-    TRACE_EVENT0("startup", "BrowserThreadsStarted::Subsystem:AudioMan");
+    TRACE_EVENT0("startup", "PostCreateThreads::Subsystem:AudioMan");
     InitializeAudio();
   }
 
   {
-    TRACE_EVENT0("startup", "BrowserThreadsStarted::Subsystem:MidiService");
+    TRACE_EVENT0("startup", "PostCreateThreads::Subsystem:MidiService");
     midi_service_.reset(new midi::MidiService);
   }
 
   {
-    TRACE_EVENT0("startup", "BrowserThreadsStarted::Subsystem:Devices");
+    TRACE_EVENT0("startup", "PostCreateThreads::Subsystem:Devices");
     device::GamepadService::GetInstance()->StartUp(
         base::BindRepeating(&BindHidManager));
 #if !defined(OS_ANDROID)
@@ -1268,9 +1265,8 @@
 
   // MediaStreamManager needs the IO thread to be created.
   {
-    TRACE_EVENT0(
-        "startup",
-        "BrowserMainLoop::BrowserThreadsStarted:InitMediaStreamManager");
+    TRACE_EVENT0("startup",
+                 "BrowserMainLoop::PostCreateThreads:InitMediaStreamManager");
 
     scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner =
         audio_manager_ ? audio_manager_->GetTaskRunner() : nullptr;
@@ -1290,24 +1286,22 @@
   }
 
   {
-    TRACE_EVENT0(
-        "startup",
-        "BrowserMainLoop::BrowserThreadsStarted:InitSpeechRecognition");
+    TRACE_EVENT0("startup",
+                 "BrowserMainLoop::PostCreateThreads:InitSpeechRecognition");
     speech_recognition_manager_.reset(new SpeechRecognitionManagerImpl(
         audio_system_.get(), media_stream_manager_.get()));
   }
 
   {
-    TRACE_EVENT0(
-        "startup",
-        "BrowserMainLoop::BrowserThreadsStarted::InitUserInputMonitor");
+    TRACE_EVENT0("startup",
+                 "BrowserMainLoop::PostCreateThreads::InitUserInputMonitor");
     user_input_monitor_ = media::UserInputMonitor::Create(
         io_thread_->task_runner(), base::ThreadTaskRunnerHandle::Get());
   }
 
   {
     TRACE_EVENT0("startup",
-                 "BrowserMainLoop::BrowserThreadsStarted::SaveFileManager");
+                 "BrowserMainLoop::PostCreateThreads::SaveFileManager");
     save_file_manager_ = new SaveFileManager();
   }
 
@@ -1333,7 +1327,7 @@
   }
 
 #if defined(OS_WIN)
-  GpuDataManagerImpl::GetInstance()->OnBrowserThreadsStarted();
+  GpuDataManagerImpl::GetInstance()->PostCreateThreads();
 #endif
 
   if (MediaKeysListenerManager::IsMediaKeysListenerManagerEnabled()) {
@@ -1355,7 +1349,6 @@
 #if defined(ENABLE_IPC_FUZZER)
   SetFileUrlPathAliasForIpcFuzzer();
 #endif
-  return result_code_;
 }
 
 bool BrowserMainLoop::UsingInProcessGpu() const {
@@ -1407,17 +1400,6 @@
   return true;
 }
 
-void BrowserMainLoop::MainMessageLoopRun() {
-#if defined(OS_ANDROID)
-  // Android's main message loop is the Java message loop.
-  NOTREACHED();
-#else
-  base::RunLoop run_loop;
-  parts_->PreDefaultMainMessageLoopRun(run_loop.QuitClosure());
-  run_loop.Run();
-#endif
-}
-
 void BrowserMainLoop::InitializeMojo() {
   if (!parsed_command_line_.HasSwitch(switches::kSingleProcess)) {
     // Disallow mojo sync calls in the browser process. Note that we allow sync
diff --git a/content/browser/browser_main_loop.h b/content/browser/browser_main_loop.h
index fcb63059..ca3a245 100644
--- a/content/browser/browser_main_loop.h
+++ b/content/browser/browser_main_loop.h
@@ -141,18 +141,25 @@
   bool InitializeToolkit();
 
   void PreMainMessageLoopStart();
+  // Creates the main message loop, bringing APIs like
+  // ThreadTaskRunnerHandle::Get() online. TODO(gab): Rename this to
+  // CreateMainMessageLoop() since the message loop isn't actually "started"
+  // here...
   void MainMessageLoopStart();
   void PostMainMessageLoopStart();
-  void PreShutdown();
 
   // Create and start running the tasks we need to complete startup. Note that
   // this can be called more than once (currently only on Android) if we get a
   // request for synchronous startup while the tasks created by asynchronous
-  // startup are still running.
+  // startup are still running. Completes tasks synchronously as part of this
+  // method on non-Android platforms.
   void CreateStartupTasks();
 
-  // Perform the default message loop run logic.
-  void RunMainMessageLoopParts();
+  // Performs the default message loop run logic.
+  void RunMainMessageLoop();
+
+  // Performs the pre-shutdown steps.
+  void PreShutdown();
 
   // Performs the shutdown sequence, starting with PostMainMessageLoopRun
   // through stopping threads to PostDestroyThreads.
@@ -233,8 +240,6 @@
       BrowserMainLoopTest,
       PostTaskToIOThreadBeforeThreadCreationDoesNotRunTask);
 
-  void InitializeMainThread();
-
   // Called just before creating the threads
   int PreCreateThreads();
 
@@ -243,9 +248,7 @@
 
   // Called just after creating the threads.
   int PostCreateThreads();
-
-  // Called right after the browser threads have been started.
-  int BrowserThreadsStarted();
+  void PostCreateThreadsImpl();
 
   int PreMainMessageLoopRun();
 
@@ -266,15 +269,17 @@
   // InitializeToolkit()
   // PreMainMessageLoopStart()
   // MainMessageLoopStart()
-  //   InitializeMainThread()
   // PostMainMessageLoopStart()
   // CreateStartupTasks()
   //   PreCreateThreads()
+  //     InitializeMemoryManagementComponent()
   //   CreateThreads()
   //   PostCreateThreads()
-  //   BrowserThreadsStarted()
-  //     InitializeMojo()
-  //   PreMainMessageLoopRun()
+  //     PostCreateThreadsImpl()
+  //       InitializeMojo()
+  //       InitializeAudio()
+  // PreMainMessageLoopRun()
+  // MainMessageLoopRun()
 
   // Members initialized on construction ---------------------------------------
   const MainFunctionParams& parameters_;
@@ -326,7 +331,7 @@
   // classes constructed in content (but after |main_thread_|).
   std::unique_ptr<BrowserMainParts> parts_;
 
-  // Members initialized in |InitializeMainThread()| ---------------------------
+  // Members initialized in |MainMessageLoopStart()| ---------------------------
   // This must get destroyed before other threads that are created in |parts_|.
   std::unique_ptr<BrowserThreadImpl> main_thread_;
 
diff --git a/content/browser/browser_main_loop_unittest.cc b/content/browser/browser_main_loop_unittest.cc
index 2c8b1c2f..a80a075a0 100644
--- a/content/browser/browser_main_loop_unittest.cc
+++ b/content/browser/browser_main_loop_unittest.cc
@@ -65,8 +65,8 @@
   BrowserMainLoop browser_main_loop(
       main_function_params,
       std::make_unique<base::ThreadPoolInstance::ScopedExecutionFence>());
-  browser_main_loop.MainMessageLoopStart();
   browser_main_loop.Init();
+  browser_main_loop.MainMessageLoopStart();
   browser_main_loop.CreateThreads();
   EXPECT_GE(base::ThreadPoolInstance::Get()
                 ->GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated(
@@ -87,8 +87,8 @@
   BrowserMainLoop browser_main_loop(
       main_function_params,
       std::make_unique<base::ThreadPoolInstance::ScopedExecutionFence>());
-  browser_main_loop.MainMessageLoopStart();
   browser_main_loop.Init();
+  browser_main_loop.MainMessageLoopStart();
 
   StrickMockTask task;
 
diff --git a/content/browser/browser_main_runner_impl.cc b/content/browser/browser_main_runner_impl.cc
index 986c41e..efda461 100644
--- a/content/browser/browser_main_runner_impl.cc
+++ b/content/browser/browser_main_runner_impl.cc
@@ -147,7 +147,7 @@
 int BrowserMainRunnerImpl::Run() {
   DCHECK(initialization_started_);
   DCHECK(!is_shutdown_);
-  main_loop_->RunMainMessageLoopParts();
+  main_loop_->RunMainMessageLoop();
   return main_loop_->GetResultCode();
 }
 
diff --git a/content/browser/gpu/gpu_data_manager_impl.cc b/content/browser/gpu/gpu_data_manager_impl.cc
index f09a5bc..2b70aa2 100644
--- a/content/browser/gpu/gpu_data_manager_impl.cc
+++ b/content/browser/gpu/gpu_data_manager_impl.cc
@@ -225,9 +225,9 @@
   return private_->VulkanRequested();
 }
 
-void GpuDataManagerImpl::OnBrowserThreadsStarted() {
+void GpuDataManagerImpl::PostCreateThreads() {
   base::AutoLock auto_lock(lock_);
-  private_->OnBrowserThreadsStarted();
+  private_->PostCreateThreads();
 }
 
 void GpuDataManagerImpl::TerminateInfoCollectionGpuProcess() {
diff --git a/content/browser/gpu/gpu_data_manager_impl.h b/content/browser/gpu/gpu_data_manager_impl.h
index 23bd3c9..15ee11b 100644
--- a/content/browser/gpu/gpu_data_manager_impl.h
+++ b/content/browser/gpu/gpu_data_manager_impl.h
@@ -100,8 +100,10 @@
   void UpdateVulkanRequestStatus(bool request_continues);
   bool Dx12Requested() const;
   bool VulkanRequested() const;
-  // Called from BrowserMainLoop::BrowserThreadsStarted().
-  void OnBrowserThreadsStarted();
+  // Called from BrowserMainLoop::PostCreateThreads().
+  // TODO(content/browser/gpu/OWNERS): This should probably use a
+  // BrowserMainParts override instead.
+  void PostCreateThreads();
   void TerminateInfoCollectionGpuProcess();
 #endif
   // Update the GPU feature info. This updates the blocklist and enabled status
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc
index 8546a5b6..782c4e27 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private.cc
+++ b/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -1026,7 +1026,7 @@
   return gpu_info_vulkan_requested_;
 }
 
-void GpuDataManagerImplPrivate::OnBrowserThreadsStarted() {
+void GpuDataManagerImplPrivate::PostCreateThreads() {
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   if (command_line->HasSwitch(switches::kNoDelayForDX12VulkanInfoCollection)) {
     // This is for the info collection test of the gpu integration tests.
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.h b/content/browser/gpu/gpu_data_manager_impl_private.h
index 1e5be27d..40b7369 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private.h
+++ b/content/browser/gpu/gpu_data_manager_impl_private.h
@@ -75,7 +75,7 @@
   void UpdateVulkanRequestStatus(bool request_continues);
   bool Dx12Requested() const;
   bool VulkanRequested() const;
-  void OnBrowserThreadsStarted();
+  void PostCreateThreads();
   void TerminateInfoCollectionGpuProcess();
 #endif
   void UpdateGpuFeatureInfo(const gpu::GpuFeatureInfo& gpu_feature_info,
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index d05565a..cf3a090 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -212,7 +212,6 @@
       request_info->client_security_state.Clone();
   new_request->is_main_frame = request_info->is_main_frame;
   new_request->priority = net::HIGHEST;
-  new_request->render_frame_id = frame_tree_node_id;
   new_request->request_initiator =
       request_info->common_params->initiator_origin;
   new_request->referrer = request_info->common_params->referrer->url;
diff --git a/content/browser/net/trust_token_browsertest.cc b/content/browser/net/trust_token_browsertest.cc
index 10fd5629..b48cf3b 100644
--- a/content/browser/net/trust_token_browsertest.cc
+++ b/content/browser/net/trust_token_browsertest.cc
@@ -437,7 +437,13 @@
               request_handler_.hashes_of_redemption_bound_public_keys())))));
 }
 
-IN_PROC_BROWSER_TEST_F(TrustTokenBrowsertest, RecordsTimers) {
+// Flaky on Linux. https://crbug.com/1165862
+#if defined(OS_LINUX)
+#define MAYBE_RecordsTimers DISABLED_RecordsTimers
+#else
+#define MAYBE_RecordsTimers RecordsTimers
+#endif
+IN_PROC_BROWSER_TEST_F(TrustTokenBrowsertest, MAYBE_RecordsTimers) {
   base::HistogramTester histograms;
 
   ProvideRequestHandlerKeyCommitmentsToNetworkService({"a.test"});
diff --git a/content/browser/prerender/prerender_browsertest.cc b/content/browser/prerender/prerender_browsertest.cc
index 4287a7c..75ffab7 100644
--- a/content/browser/prerender/prerender_browsertest.cc
+++ b/content/browser/prerender/prerender_browsertest.cc
@@ -221,7 +221,8 @@
     WaitForPrerenderLoadCompletion(prerendering_url);
   }
 
-  // Navigates to the URL and waits until the completion of navigation.
+  // Navigates the primary page to the URL and waits until the completion of the
+  // navigation.
   //
   // Navigations that could activate a prerendered page on the multiple
   // WebContents architecture (not multiple-pages architecture known as MPArch)
@@ -229,7 +230,7 @@
   // is because the test helper accesses the predecessor WebContents to be
   // destroyed during activation and results in crashes.
   // See https://crbug.com/1154501 for the MPArch migration.
-  void NavigateWithLocation(const GURL& url) {
+  void NavigatePrimaryPage(const GURL& url) {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
     content::TestNavigationObserver observer(shell()->web_contents());
     // Ignore the result of ExecJs().
@@ -243,11 +244,30 @@
     // approach just to ignore it instead of fixing the timing issue. When
     // ExecJs() actually fails, the remaining test steps should fail, so it
     // should be safe to ignore it.
-    ignore_result(
-        ExecJs(shell()->web_contents(), JsReplace("location = $1", url)));
+    ignore_result(ExecJs(shell()->web_contents()->GetMainFrame(),
+                         JsReplace("location = $1", url)));
     observer.Wait();
   }
 
+  // Navigates a prerendered page to the URL.
+  void NavigatePrerenderedPage(PrerenderHost& prerender_host, const GURL& url) {
+    RenderFrameHostImpl* prerender_render_frame_host =
+        prerender_host.GetPrerenderedMainFrameHostForTesting();
+    // Ignore the result of ExecJs().
+    //
+    // Navigation from the prerendered page could cancel prerendering and
+    // destroy the prerendered frame before ExecJs() gets a result from that.
+    // This results in execution failure even when the execution succeeded. See
+    // https://crbug.com/1186584 for details.
+    //
+    // This part will drastically be modified by the MPArch, so we take the
+    // approach just to ignore it instead of fixing the timing issue. When
+    // ExecJs() actually fails, the remaining test steps should fail, so it
+    // should be safe to ignore it.
+    ignore_result(
+        ExecJs(prerender_render_frame_host, JsReplace("location = $1", url)));
+  }
+
   GURL GetUrl(const std::string& path) {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
     return ssl_server_.GetURL("a.test", path);
@@ -319,7 +339,7 @@
     }
 
     // Activate the prerendered page.
-    NavigateWithLocation(prerender_url);
+    NavigatePrimaryPage(prerender_url);
     EXPECT_EQ(shell()->web_contents()->GetURL(), prerender_url);
 
     // The activated page should no longer be in the prerendering state.
@@ -382,7 +402,7 @@
   EXPECT_NE(registry.FindHostByUrlForTesting(kPrerenderingUrl), nullptr);
 
   // Activate the prerendered page.
-  NavigateWithLocation(kPrerenderingUrl);
+  NavigatePrimaryPage(kPrerenderingUrl);
   EXPECT_EQ(shell()->web_contents()->GetURL(), kPrerenderingUrl);
 
   // The prerender host should be consumed.
@@ -422,7 +442,7 @@
   EXPECT_NE(registry.FindHostByUrlForTesting(kPrerenderingUrl2), nullptr);
 
   // Activate the prerendered page.
-  NavigateWithLocation(kPrerenderingUrl2);
+  NavigatePrimaryPage(kPrerenderingUrl2);
   EXPECT_EQ(shell()->web_contents()->GetURL(), kPrerenderingUrl2);
 
   // The prerender hosts should be consumed or destroyed for activation.
@@ -464,7 +484,7 @@
   EXPECT_NE(registry.FindHostByUrlForTesting(kPrerenderingUrl2), nullptr);
 
   // Activate the prerendered page.
-  NavigateWithLocation(kPrerenderingUrl1);
+  NavigatePrimaryPage(kPrerenderingUrl1);
   EXPECT_EQ(shell()->web_contents()->GetURL(), kPrerenderingUrl1);
 
   // The prerender hosts should be consumed or destroyed for activation.
@@ -607,7 +627,7 @@
   ASSERT_EQ(GetRequestCount(kCrossOriginSubframeUrl), 0);
 
   // Activate.
-  NavigateWithLocation(kPrerenderingUrl);
+  NavigatePrimaryPage(kPrerenderingUrl);
   ASSERT_EQ(shell()->web_contents()->GetURL(), kPrerenderingUrl);
   ASSERT_EQ("LOADED",
             EvalJs(prerender_frame_host, JsReplace("wait_iframe_async($1)",
@@ -699,7 +719,7 @@
   // should fail and fallback to network request because the pop-up window
   // exists.
   ASSERT_EQ(GetRequestCount(kPrerenderingUrl), 1);
-  NavigateWithLocation(kPrerenderingUrl);
+  NavigatePrimaryPage(kPrerenderingUrl);
   EXPECT_EQ(shell()->web_contents()->GetURL(), kPrerenderingUrl);
   EXPECT_EQ(GetRequestCount(kPrerenderingUrl), 2);
 
@@ -723,7 +743,7 @@
 
   // Make and activate a prerendered page.
   AddPrerender(kPrerenderingUrl);
-  NavigateWithLocation(kPrerenderingUrl);
+  NavigatePrimaryPage(kPrerenderingUrl);
   EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), kPrerenderingUrl);
 
   // Navigate back to the initial page.
@@ -859,7 +879,7 @@
   }
 
   // Activate the prerendered page.
-  NavigateWithLocation(kPrerenderingUrl);
+  NavigatePrimaryPage(kPrerenderingUrl);
   EXPECT_EQ(shell()->web_contents()->GetURL(), kPrerenderingUrl);
   EXPECT_EQ(test_browser_client.GetDeferReceiverSetSize(), frames.size());
 
@@ -1094,11 +1114,10 @@
             EvalJs(shell()->web_contents(), "document.cookie"));
 }
 
-// TODO(crbug.com/1186584) Test is flaky.
 // Test that a cross-site navigation from prerendering browser context will
 // cancel prerendering.
 IN_PROC_BROWSER_TEST_P(PrerenderBrowserTest,
-                       DISABLED_PrerenderedPageCrossSiteNavigation) {
+                       PrerenderedPageCrossSiteNavigation) {
   base::HistogramTester histogram_tester;
   const GURL kInitialUrl = GetUrl("/prerender/add_prerender.html");
   const GURL kPrerenderingUrl = GetUrl("/empty.html");
@@ -1112,14 +1131,9 @@
   PrerenderHostRegistry& registry = GetPrerenderHostRegistry();
   PrerenderHost* prerender_host =
       registry.FindHostByUrlForTesting(kPrerenderingUrl);
-  ASSERT_TRUE(prerender_host);
-  RenderFrameHostImpl* prerendered_render_frame_host =
-      prerender_host->GetPrerenderedMainFrameHostForTesting();
 
   // Run cross-site navigation from the prerendering browser context.
-  EXPECT_TRUE(ExecJs(
-      prerendered_render_frame_host,
-      JsReplace("window.location.href = $1", kCrossSitePrerenderingUrl)));
+  NavigatePrerenderedPage(*prerender_host, kCrossSitePrerenderingUrl);
 
   // The cross-site navigation should cancel prerendering.
   EXPECT_FALSE(registry.FindHostByUrlForTesting(kPrerenderingUrl));
@@ -1147,14 +1161,9 @@
   PrerenderHostRegistry& registry = GetPrerenderHostRegistry();
   PrerenderHost* prerender_host =
       registry.FindHostByUrlForTesting(kPrerenderingUrl);
-  ASSERT_TRUE(prerender_host);
-  RenderFrameHostImpl* prerendered_render_frame_host =
-      prerender_host->GetPrerenderedMainFrameHostForTesting();
 
   // Navigate same-site from the prerendered page.
-  EXPECT_TRUE(
-      ExecJs(prerendered_render_frame_host,
-             JsReplace("window.location.href = $1", kSameSitePrerenderingUrl)));
+  NavigatePrerenderedPage(*prerender_host, kSameSitePrerenderingUrl);
   prerender_host->WaitForLoadStopForTesting();
 
   // The prerender host should be registered for the initial request URL, not
@@ -1163,7 +1172,7 @@
   EXPECT_FALSE(registry.FindHostByUrlForTesting(kSameSitePrerenderingUrl));
 
   // Activate the prerendered page.
-  NavigateWithLocation(kPrerenderingUrl);
+  NavigatePrimaryPage(kPrerenderingUrl);
   if (IsActivationDisabled()) {
     // Activation is disabled. The navigation should issue a request again
     // pointing to kPrerenderingUrl.
@@ -1211,13 +1220,8 @@
   EXPECT_EQ(LifecycleState::kPrerendering, rfh_a->lifecycle_state());
   EXPECT_EQ(LifecycleState::kPrerendering, rfh_b->lifecycle_state());
 
-  RenderFrameHostImpl* prerendered_render_frame_host =
-      prerender_host->GetPrerenderedMainFrameHostForTesting();
-
   // Navigate same-origin from the prerendered page.
-  EXPECT_TRUE(
-      ExecJs(prerendered_render_frame_host,
-             JsReplace("window.location.href = $1", kPrerenderingUrl2)));
+  NavigatePrerenderedPage(*prerender_host, kPrerenderingUrl2);
   prerender_host->WaitForLoadStopForTesting();
 
   // Open an iframe in the new prerendered page.
@@ -1232,7 +1236,7 @@
   EXPECT_EQ(LifecycleState::kPrerendering, rfh_d->lifecycle_state());
 
   // Activate the prerendered page.
-  NavigateWithLocation(kPrerenderingUrl1);
+  NavigatePrimaryPage(kPrerenderingUrl1);
 
   // Both rfh_c and rfh_d lifecycle state's should be kActive after activation.
   EXPECT_EQ(LifecycleState::kActive, rfh_c->lifecycle_state());
@@ -1476,7 +1480,7 @@
 
   // Inform the prerendered page that it will be activated and activate it.
   EXPECT_TRUE(ExecJs(prerender_render_frame_host, "setWillActivate();"));
-  NavigateWithLocation(kPrerenderingUrl);
+  NavigatePrimaryPage(kPrerenderingUrl);
 
   // `temp_file` should be selected after `willActivate` was set to true,
   // otherwise the prerendered page will throw an error.
@@ -1517,7 +1521,7 @@
   EXPECT_TRUE(data);
 
   // Activate the prerendered page.
-  NavigateWithLocation(kPrerenderingUrl);
+  NavigatePrimaryPage(kPrerenderingUrl);
   EXPECT_EQ(shell()->web_contents()->GetURL(), kPrerenderingUrl);
 
   // The prerender host should be consumed.
@@ -1655,7 +1659,7 @@
 
   // Cancelling the prerendering disables the activation. The navigation
   // should issue a request again.
-  NavigateWithLocation(kPrerenderingUrl);
+  NavigatePrimaryPage(kPrerenderingUrl);
   EXPECT_EQ(GetRequestCount(kPrerenderingUrl), 2);
 }
 
@@ -1699,20 +1703,15 @@
 
   PrerenderHost* prerender_host =
       GetPrerenderHostRegistry().FindHostByUrlForTesting(kPrerenderingUrl);
-  ASSERT_TRUE(prerender_host);
-  RenderFrameHostImpl* prerendered_render_frame_host =
-      prerender_host->GetPrerenderedMainFrameHostForTesting();
 
   // Navigate the Prerender page to a new URL.
-  EXPECT_TRUE(
-      ExecJs(prerendered_render_frame_host,
-             JsReplace("window.location.href = $1", kSameSitePrerenderingUrl)));
+  NavigatePrerenderedPage(*prerender_host, kSameSitePrerenderingUrl);
   prerender_host->WaitForLoadStopForTesting();
 
   prerender_host =
       GetPrerenderHostRegistry().FindHostByUrlForTesting(kPrerenderingUrl);
   ASSERT_TRUE(prerender_host);
-  prerendered_render_frame_host =
+  RenderFrameHostImpl* prerendered_render_frame_host =
       prerender_host->GetPrerenderedMainFrameHostForTesting();
 
   // Go back. The page should not be restored from the bfcache.
diff --git a/content/browser/renderer_host/frame_tree.cc b/content/browser/renderer_host/frame_tree.cc
index 6d51d10..df253f8 100644
--- a/content/browser/renderer_host/frame_tree.cc
+++ b/content/browser/renderer_host/frame_tree.cc
@@ -423,22 +423,30 @@
 
 scoped_refptr<RenderViewHostImpl> FrameTree::GetRenderViewHost(
     SiteInstance* site_instance) {
-  auto it = render_view_host_map_.find(site_instance->GetId());
+  auto it = render_view_host_map_.find(GetRenderViewHostMapId(site_instance));
   if (it == render_view_host_map_.end())
     return nullptr;
 
   return base::WrapRefCounted(it->second);
 }
 
-void FrameTree::RegisterRenderViewHost(SiteInstance* site_instance,
-                                       RenderViewHostImpl* rvh) {
-  CHECK(!base::Contains(render_view_host_map_, site_instance->GetId()));
-  render_view_host_map_[site_instance->GetId()] = rvh;
+FrameTree::RenderViewHostMapId FrameTree::GetRenderViewHostMapId(
+    SiteInstance* site_instance) const {
+  // TODO(acolwell): Change this to use a SiteInstanceGroup ID once
+  // SiteInstanceGroups are implemented so that all SiteInstances within a
+  // group can use the same RenderViewHost.
+  return RenderViewHostMapId::FromUnsafeValue(site_instance->GetId());
 }
 
-void FrameTree::UnregisterRenderViewHost(SiteInstance* site_instance,
+void FrameTree::RegisterRenderViewHost(RenderViewHostMapId id,
+                                       RenderViewHostImpl* rvh) {
+  CHECK(!base::Contains(render_view_host_map_, id));
+  render_view_host_map_[id] = rvh;
+}
+
+void FrameTree::UnregisterRenderViewHost(RenderViewHostMapId id,
                                          RenderViewHostImpl* rvh) {
-  auto it = render_view_host_map_.find(site_instance->GetId());
+  auto it = render_view_host_map_.find(id);
   CHECK(it != render_view_host_map_.end());
   CHECK_EQ(it->second, rvh);
   render_view_host_map_.erase(it);
diff --git a/content/browser/renderer_host/frame_tree.h b/content/browser/renderer_host/frame_tree.h
index cfbb118..d9a39dd0 100644
--- a/content/browser/renderer_host/frame_tree.h
+++ b/content/browser/renderer_host/frame_tree.h
@@ -165,8 +165,12 @@
   RenderFrameHostManager::Delegate* manager_delegate() {
     return manager_delegate_;
   }
-  const std::unordered_map<int /* SiteInstance ID */, RenderViewHostImpl*>&
-  render_view_hosts() const {
+
+  using RenderViewHostMapId = util::IdType32<class RenderViewHostMap>;
+  using RenderViewHostMap = std::unordered_map<RenderViewHostMapId,
+                                               RenderViewHostImpl*,
+                                               RenderViewHostMapId::Hasher>;
+  const RenderViewHostMap& render_view_hosts() const {
     return render_view_host_map_;
   }
 
@@ -265,8 +269,14 @@
   scoped_refptr<RenderViewHostImpl> GetRenderViewHost(
       SiteInstance* site_instance);
 
+  // Returns the ID used for the RenderViewHost associated with |site_instance|.
+  // Note: Callers should not assume that there is a 1:1 mapping between
+  // SiteInstances and IDs returned by this function, since several
+  // SiteInstances may share a RenderViewHost.
+  RenderViewHostMapId GetRenderViewHostMapId(SiteInstance* site_instance) const;
+
   // Registers a RenderViewHost so that it can be reused by other frames
-  // belonging to the same SiteInstance.
+  // whose SiteInstance maps to the same RenderViewHostMapId.
   //
   // This method does not take ownership of|rvh|.
   //
@@ -277,13 +287,12 @@
   // *must* be called for |rvh| when it is destroyed or put into the
   // BackForwardCache, to prevent FrameTree::CreateRenderViewHost from trying to
   // reuse it.
-  void RegisterRenderViewHost(SiteInstance* site_instance,
-                              RenderViewHostImpl* rvh);
+  void RegisterRenderViewHost(RenderViewHostMapId id, RenderViewHostImpl* rvh);
 
   // Unregisters the RenderViewHostImpl that's available for reuse for a
-  // particular SiteInstance. NOTE: This method CHECK fails if it is called for
-  // a |render_view_host| that is not currently set for reuse.
-  void UnregisterRenderViewHost(SiteInstance* site_instance,
+  // particular RenderViewHostMapId. NOTE: This method CHECK fails if it is
+  // called for a |render_view_host| that is not currently set for reuse.
+  void UnregisterRenderViewHost(RenderViewHostMapId id,
                                 RenderViewHostImpl* render_view_host);
 
   // This is called when the frame is about to be removed and started to run
@@ -381,12 +390,11 @@
   // the frame.
   Navigator navigator_;
 
-  // Map of SiteInstance ID to RenderViewHost. This allows us to look up the
+  // Map of RenderViewHostMapId to RenderViewHost. This allows us to look up the
   // RenderViewHost for a given SiteInstance when creating RenderFrameHosts.
   // Each RenderViewHost maintains a refcount and is deleted when there are no
   // more RenderFrameHosts or RenderFrameProxyHosts using it.
-  std::unordered_map<int /* SiteInstance ID */, RenderViewHostImpl*>
-      render_view_host_map_;
+  RenderViewHostMap render_view_host_map_;
 
   // This is an owned ptr to the root FrameTreeNode, which never changes over
   // the lifetime of the FrameTree. It is not a scoped_ptr because we need the
diff --git a/content/browser/renderer_host/input/scroll_latency_browsertest.cc b/content/browser/renderer_host/input/scroll_latency_browsertest.cc
index ec6f719..e0565379 100644
--- a/content/browser/renderer_host/input/scroll_latency_browsertest.cc
+++ b/content/browser/renderer_host/input/scroll_latency_browsertest.cc
@@ -505,8 +505,9 @@
   RunScrollbarButtonLatencyTest();
 }
 
+// Disabled due to flakes; see https://crbug.com/1188553.
 IN_PROC_BROWSER_TEST_F(ScrollLatencyScrollbarBrowserTest,
-                       ScrollbarThumbDragLatency) {
+                       DISABLED_ScrollbarThumbDragLatency) {
   LoadURL();
 
   RunScrollbarThumbDragLatencyTest();
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
index 8de34dc..124454a 100644
--- a/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -790,14 +790,16 @@
 
   audio_service_listener_ = std::make_unique<AudioServiceListener>();
 
-  base::PowerMonitor::AddObserver(this);
+  base::PowerMonitor::AddPowerSuspendObserver(this);
+  base::PowerMonitor::AddPowerThermalObserver(this);
 }
 
 MediaStreamManager::~MediaStreamManager() {
   DCHECK(!BrowserThread::IsThreadInitialized(BrowserThread::IO));
   DCHECK(requests_.empty());
 
-  base::PowerMonitor::RemoveObserver(this);
+  base::PowerMonitor::RemovePowerSuspendObserver(this);
+  base::PowerMonitor::RemovePowerThermalObserver(this);
 }
 
 VideoCaptureManager* MediaStreamManager::video_capture_manager() {
@@ -2151,7 +2153,7 @@
 }
 
 void MediaStreamManager::OnThermalStateChange(
-    base::PowerObserver::DeviceThermalState new_state) {
+    base::PowerThermalObserver::DeviceThermalState new_state) {
   const char* state_name =
       base::PowerMonitorSource::DeviceThermalStateToString(new_state);
   SendLogMessage(base::StringPrintf(
diff --git a/content/browser/renderer_host/media/media_stream_manager.h b/content/browser/renderer_host/media/media_stream_manager.h
index d6652e4a..ccc85b9 100644
--- a/content/browser/renderer_host/media/media_stream_manager.h
+++ b/content/browser/renderer_host/media/media_stream_manager.h
@@ -81,7 +81,8 @@
 class CONTENT_EXPORT MediaStreamManager
     : public MediaStreamProviderListener,
       public base::CurrentThread::DestructionObserver,
-      public base::PowerObserver {
+      public base::PowerSuspendObserver,
+      public base::PowerThermalObserver {
  public:
   // Callback to deliver the result of a media access request.
   using MediaAccessRequestCallback =
@@ -284,11 +285,13 @@
   // webrtcLoggingPrivate API if requested.
   void AddLogMessageOnIOThread(const std::string& message);
 
-  // base::PowerObserver overrides.
+  // base::PowerSuspendObserver overrides.
   void OnSuspend() override;
   void OnResume() override;
+
+  // base::PowerThermalObserver overrides.
   void OnThermalStateChange(
-      base::PowerObserver::DeviceThermalState new_state) override;
+      base::PowerThermalObserver::DeviceThermalState new_state) override;
 
   // Called by the tests to specify a factory for creating
   // FakeMediaStreamUIProxys to be used for generated streams.
diff --git a/content/browser/renderer_host/media/peer_connection_tracker_host.cc b/content/browser/renderer_host/media/peer_connection_tracker_host.cc
index 9208450b..1b28871d 100644
--- a/content/browser/renderer_host/media/peer_connection_tracker_host.cc
+++ b/content/browser/renderer_host/media/peer_connection_tracker_host.cc
@@ -51,14 +51,15 @@
       peer_pid_(frame->GetProcess()->GetProcess().Pid()) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   RegisterHost(this);
-  base::PowerMonitor::AddObserver(this);
+  base::PowerMonitor::AddPowerSuspendObserver(this);
+  base::PowerMonitor::AddPowerThermalObserver(this);
   frame->GetRemoteInterfaces()->GetInterface(
       tracker_.BindNewPipeAndPassReceiver());
   // Ensure that the initial thermal state is known by the |tracker_|.
-  base::PowerObserver::DeviceThermalState initial_thermal_state =
+  base::PowerThermalObserver::DeviceThermalState initial_thermal_state =
       base::PowerMonitor::GetCurrentThermalState();
   if (initial_thermal_state !=
-      base::PowerObserver::DeviceThermalState::kUnknown) {
+      base::PowerThermalObserver::DeviceThermalState::kUnknown) {
     OnThermalStateChange(initial_thermal_state);
   }
 }
@@ -66,7 +67,8 @@
 PeerConnectionTrackerHost::~PeerConnectionTrackerHost() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   RemoveHost(this);
-  base::PowerMonitor::RemoveObserver(this);
+  base::PowerMonitor::RemovePowerSuspendObserver(this);
+  base::PowerMonitor::RemovePowerThermalObserver(this);
 }
 
 void PeerConnectionTrackerHost::AddPeerConnection(
@@ -185,7 +187,7 @@
 }
 
 void PeerConnectionTrackerHost::OnThermalStateChange(
-    base::PowerObserver::DeviceThermalState new_state) {
+    base::PowerThermalObserver::DeviceThermalState new_state) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   tracker_->OnThermalStateChange(
       static_cast<blink::mojom::DeviceThermalState>(new_state));
diff --git a/content/browser/renderer_host/media/peer_connection_tracker_host.h b/content/browser/renderer_host/media/peer_connection_tracker_host.h
index a656cdb..664c2b62 100644
--- a/content/browser/renderer_host/media/peer_connection_tracker_host.h
+++ b/content/browser/renderer_host/media/peer_connection_tracker_host.h
@@ -30,7 +30,8 @@
 // PeerConnectionTracker as IPC messages that it forwards to WebRTCInternals.
 // It also forwards browser process events to PeerConnectionTracker via IPC.
 class PeerConnectionTrackerHost
-    : public base::PowerObserver,
+    : public base::PowerSuspendObserver,
+      public base::PowerThermalObserver,
       public blink::mojom::PeerConnectionTrackerHost {
  public:
   explicit PeerConnectionTrackerHost(RenderFrameHost* rfh);
@@ -38,10 +39,11 @@
 
   static const std::set<PeerConnectionTrackerHost*>& GetAllHosts();
 
-  // base::PowerObserver override.
+  // base::PowerSuspendObserver override.
   void OnSuspend() override;
+  // base::PowerThermalObserver override.
   void OnThermalStateChange(
-      base::PowerObserver::DeviceThermalState new_state) override;
+      base::PowerThermalObserver::DeviceThermalState new_state) override;
 
   // These methods call out to blink::mojom::PeerConnectionManager on renderer
   // side.
diff --git a/content/browser/renderer_host/navigation_controller_impl.cc b/content/browser/renderer_host/navigation_controller_impl.cc
index c93f0a78..e511420 100644
--- a/content/browser/renderer_host/navigation_controller_impl.cc
+++ b/content/browser/renderer_host/navigation_controller_impl.cc
@@ -2507,19 +2507,17 @@
 }
 
 SessionStorageNamespace* NavigationControllerImpl::GetSessionStorageNamespace(
-    SiteInstance* instance) {
-  StoragePartitionId partition_id;
-  if (instance) {
-    // TODO(ajwong): When GetDefaultSessionStorageNamespace() goes away, remove
-    // this if statement so |instance| must not be null.
-    partition_id =
-        static_cast<SiteInstanceImpl*>(instance)->GetStoragePartitionId();
-  }
+    const SiteInfo& site_info) {
+  // TODO(acolwell): Remove partition_id logic once we have successfully
+  // migrated the implementation to be a StoragePartitionConfig. At that point
+  // |site_info| can be replaced with a StoragePartitionConfig.
+  const StoragePartitionId partition_id =
+      site_info.GetStoragePartitionId(browser_context_);
+  const StoragePartitionConfig partition_config =
+      site_info.GetStoragePartitionConfig(browser_context_);
 
-  // TODO(ajwong): Should this use the |partition_id| directly rather than
-  // re-lookup via |instance|?  http://crbug.com/142685
   StoragePartition* partition =
-      BrowserContext::GetStoragePartition(browser_context_, instance);
+      BrowserContext::GetStoragePartition(browser_context_, partition_config);
   DOMStorageContextWrapper* context_wrapper =
       static_cast<DOMStorageContextWrapper*>(partition->GetDOMStorageContext());
 
@@ -2545,8 +2543,7 @@
 
 SessionStorageNamespace*
 NavigationControllerImpl::GetDefaultSessionStorageNamespace() {
-  // TODO(ajwong): Remove if statement in GetSessionStorageNamespace().
-  return GetSessionStorageNamespace(nullptr);
+  return GetSessionStorageNamespace(SiteInfo());
 }
 
 const SessionStorageNamespaceMap&
diff --git a/content/browser/renderer_host/navigation_controller_impl.h b/content/browser/renderer_host/navigation_controller_impl.h
index 6e9d3b1..a4eecdd 100644
--- a/content/browser/renderer_host/navigation_controller_impl.h
+++ b/content/browser/renderer_host/navigation_controller_impl.h
@@ -177,9 +177,10 @@
   // case, we know there is no content displayed in the page.
   bool IsUnmodifiedBlankTab();
 
-  // The session storage namespace that all child RenderViews belonging to
-  // |instance| should use.
-  SessionStorageNamespace* GetSessionStorageNamespace(SiteInstance* instance);
+  // The session storage namespace that all child RenderViews associated with
+  // |site_info| should use.
+  SessionStorageNamespace* GetSessionStorageNamespace(
+      const SiteInfo& site_info);
 
   // Returns the index of the specified entry, or -1 if entry is not contained
   // in this NavigationController.
diff --git a/content/browser/renderer_host/render_view_host_browsertest.cc b/content/browser/renderer_host/render_view_host_browsertest.cc
index 58a4be2..5740e6f8f 100644
--- a/content/browser/renderer_host/render_view_host_browsertest.cc
+++ b/content/browser/renderer_host/render_view_host_browsertest.cc
@@ -127,12 +127,12 @@
   EXPECT_TRUE(ExecuteScript(shell(), "window.open();"));
   Shell* new_shell = new_shell_observer.GetShell();
   new_shell->LoadURL(test_url);
-  SiteInstance* site_instance =
-      new_shell->web_contents()->GetMainFrame()->GetSiteInstance();
+  auto* site_instance = static_cast<SiteInstanceImpl*>(
+      new_shell->web_contents()->GetMainFrame()->GetSiteInstance());
   auto* controller = static_cast<NavigationControllerImpl*>(
       &new_shell->web_contents()->GetController());
   scoped_refptr<SessionStorageNamespace> session_namespace =
-      controller->GetSessionStorageNamespace(site_instance);
+      controller->GetSessionStorageNamespace(site_instance->GetSiteInfo());
   EXPECT_FALSE(session_namespace->HasOneRef());
 
   // Close it, or rather start the close operation. The session namespace
diff --git a/content/browser/renderer_host/render_view_host_delegate.cc b/content/browser/renderer_host/render_view_host_delegate.cc
index 57e1e1a..e5b31f8 100644
--- a/content/browser/renderer_host/render_view_host_delegate.cc
+++ b/content/browser/renderer_host/render_view_host_delegate.cc
@@ -20,11 +20,6 @@
   return nullptr;
 }
 
-SessionStorageNamespace* RenderViewHostDelegate::GetSessionStorageNamespace(
-    SiteInstance* instance) {
-  return nullptr;
-}
-
 SessionStorageNamespaceMap
 RenderViewHostDelegate::GetSessionStorageNamespaceMap() {
   return SessionStorageNamespaceMap();
diff --git a/content/browser/renderer_host/render_view_host_delegate.h b/content/browser/renderer_host/render_view_host_delegate.h
index 32ac484..2770dc3 100644
--- a/content/browser/renderer_host/render_view_host_delegate.h
+++ b/content/browser/renderer_host/render_view_host_delegate.h
@@ -37,8 +37,6 @@
 class RenderViewHost;
 class RenderViewHostImpl;
 class RenderViewHostDelegateView;
-class SessionStorageNamespace;
-class SiteInstance;
 class WebContents;
 
 //
@@ -100,11 +98,6 @@
   // The contents' preferred size changed.
   virtual void UpdatePreferredSize(const gfx::Size& pref_size) {}
 
-  // Returns the SessionStorageNamespace the render view should use. Might
-  // create the SessionStorageNamespace on the fly.
-  virtual SessionStorageNamespace* GetSessionStorageNamespace(
-      SiteInstance* instance);
-
   // Returns a copy of the map of all session storage namespaces related
   // to this view.
   virtual SessionStorageNamespaceMap GetSessionStorageNamespaceMap();
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index a0dc55dc..22c3ed0 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -291,11 +291,12 @@
     bool has_initialized_audio_host)
     : render_widget_host_(std::move(widget)),
       delegate_(delegate),
-      instance_(static_cast<SiteInstanceImpl*>(instance)),
+      render_view_host_map_id_(frame_tree->GetRenderViewHostMapId(instance)),
+      site_info_(static_cast<SiteInstanceImpl*>(instance)
+                     ->GetSiteInfoForRenderViewHost()),
       routing_id_(routing_id),
       main_frame_routing_id_(main_frame_routing_id),
       frame_tree_(frame_tree) {
-  DCHECK(instance_.get());
   DCHECK(delegate_);
   DCHECK_NE(GetRoutingID(), render_widget_host_->GetRoutingID());
 
@@ -334,7 +335,7 @@
                               : blink::mojom::PageVisibilityState::kHidden);
 
   GetWidget()->set_owner_delegate(this);
-  frame_tree_->RegisterRenderViewHost(instance_.get(), this);
+  frame_tree_->RegisterRenderViewHost(render_view_host_map_id_, this);
 }
 
 RenderViewHostImpl::~RenderViewHostImpl() {
@@ -376,7 +377,7 @@
   // If |this| is in the BackForwardCache, then it was already removed from
   // the FrameTree at the time it entered the BackForwardCache.
   if (!is_in_back_forward_cache_)
-    frame_tree_->UnregisterRenderViewHost(instance_.get(), this);
+    frame_tree_->UnregisterRenderViewHost(render_view_host_map_id_, this);
 }
 
 RenderViewHostDelegate* RenderViewHostImpl::GetDelegate() {
@@ -468,15 +469,15 @@
   }
 
   params->session_storage_namespace_id =
-      delegate_->GetSessionStorageNamespace(instance_.get())->id();
+      frame_tree_->controller().GetSessionStorageNamespace(site_info_)->id();
   params->hidden = GetWidget()->delegate()->IsHidden();
   params->never_composited = delegate_->IsNeverComposited();
   params->window_was_created_with_opener = window_was_created_with_opener;
   // GuestViews in the same StoragePartition need to find each other's frames.
-  params->renderer_wide_named_frame_lookup = instance_->IsGuest();
+  params->renderer_wide_named_frame_lookup = site_info_.is_guest();
 
   bool is_portal = delegate_->IsPortal();
-  bool is_guest_view = instance_->IsGuest();
+  bool is_guest_view = site_info_.is_guest();
 
   // A view cannot be inside both a <portal> and inside a <webview>.
   DCHECK(!is_portal || !is_guest_view);
@@ -523,7 +524,7 @@
     will_enter_back_forward_cache_callback_for_testing_.Run();
 
   TRACE_EVENT0("navigation", "RenderViewHostImpl::EnterBackForwardCache");
-  frame_tree_->UnregisterRenderViewHost(instance_.get(), this);
+  frame_tree_->UnregisterRenderViewHost(render_view_host_map_id_, this);
   is_in_back_forward_cache_ = true;
   page_lifecycle_state_manager_->SetIsInBackForwardCache(
       is_in_back_forward_cache_, /*page_restore_params=*/nullptr);
@@ -540,7 +541,7 @@
   TRACE_EVENT0("navigation", "RenderViewHostImpl::LeaveBackForwardCache");
   // At this point, the frames |this| RenderViewHostImpl belongs to are
   // guaranteed to be committed, so it should be reused going forward.
-  frame_tree_->RegisterRenderViewHost(instance_.get(), this);
+  frame_tree_->RegisterRenderViewHost(render_view_host_map_id_, this);
   is_in_back_forward_cache_ = false;
   page_lifecycle_state_manager_->SetIsInBackForwardCache(
       is_in_back_forward_cache_, std::move(page_restore_params));
@@ -639,7 +640,6 @@
 
     // TODO(creis): Should this be moved to Shutdown?  It may not be called for
     // RenderViewHosts that have been swapped out.
-    CHECK_EQ(instance_.get(), GetMainFrame()->GetSiteInstance());
 #if !defined(OS_ANDROID)
     static_cast<HostZoomMapImpl*>(
         HostZoomMap::Get(GetMainFrame()->GetSiteInstance()))
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h
index 1af9066..f0c49cd 100644
--- a/content/browser/renderer_host/render_view_host_impl.h
+++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -22,6 +22,7 @@
 #include "base/process/kill.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
+#include "content/browser/renderer_host/frame_tree.h"
 #include "content/browser/renderer_host/input/input_device_change_observer.h"
 #include "content/browser/renderer_host/page_lifecycle_state_manager.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
@@ -53,7 +54,6 @@
 namespace content {
 
 class AgentSchedulingGroupHost;
-class FrameTree;
 class RenderProcessHost;
 class TimeoutMonitor;
 
@@ -380,10 +380,20 @@
   // Our delegate, which wants to know about changes in the RenderView.
   RenderViewHostDelegate* delegate_;
 
-  // The SiteInstance associated with this RenderViewHost.  All pages drawn
-  // in this RenderViewHost are part of this SiteInstance.  Cannot change
-  // over time.
-  scoped_refptr<SiteInstanceImpl> instance_;
+  // ID to use when registering/unregistering this object with its FrameTree.
+  // This ID is generated by passing a SiteInstance to
+  // FrameTree::GetRenderViewHostMapId(). This RenderViewHost may only be reused
+  // by frames with SiteInstances that generate an ID that matches this field.
+  FrameTree::RenderViewHostMapId render_view_host_map_id_;
+
+  // SiteInfo taken from the SiteInstance passed into the constructor. It is
+  // used to determine if this is a guest view and provides information for
+  // selecting the session storage namespace for this view.
+  //
+  // TODO(acolwell): Replace this with StoragePartitionConfig once we no longer
+  // need a StoragePartitionId and StoragePartitionConfig to lookup a
+  // SessionStorageNamespace.
+  SiteInfo site_info_;
 
   // Routing ID for this RenderViewHost.
   const int routing_id_;
diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc
index 216d9a0..2dc4882 100644
--- a/content/browser/site_instance_impl.cc
+++ b/content/browser/site_instance_impl.cc
@@ -359,6 +359,24 @@
                                                                 site_url_);
 }
 
+StoragePartitionId SiteInfo::GetStoragePartitionId(
+    BrowserContext* browser_context) const {
+  if (site_url().is_empty())
+    return StoragePartitionId();
+
+  return GetContentClient()->browser()->GetStoragePartitionIdForSite(
+      browser_context, site_url());
+}
+
+StoragePartitionConfig SiteInfo::GetStoragePartitionConfig(
+    BrowserContext* browser_context) const {
+  if (site_url().is_empty())
+    return StoragePartitionConfig::CreateDefault(browser_context);
+
+  return GetContentClient()->browser()->GetStoragePartitionConfigForSite(
+      browser_context, site_url());
+}
+
 bool SiteInfo::is_error_page() const {
   return !is_guest_ && site_url_ == GetErrorPageSiteAndLockURL();
 }
@@ -897,22 +915,22 @@
   CHECK_EQ(site_info.coop_coep_cross_origin_isolated_info(),
            browsing_instance_->coop_coep_cross_origin_isolated_info());
 
+  if (verify_storage_partition_info_) {
+    auto* browser_context = browsing_instance_->GetBrowserContext();
+    auto old_partition_id = site_info_.GetStoragePartitionId(browser_context);
+    auto old_partition_config =
+        site_info_.GetStoragePartitionConfig(browser_context);
+    auto new_partition_id = site_info.GetStoragePartitionId(browser_context);
+    auto new_partition_config =
+        site_info.GetStoragePartitionConfig(browser_context);
+    CHECK_EQ(old_partition_id, new_partition_id);
+    CHECK_EQ(old_partition_config, new_partition_config);
+  }
   // Remember that this SiteInstance has been used to load a URL, even if the
   // URL is invalid.
   has_site_ = true;
   site_info_ = site_info;
 
-  auto storage_partition_id = ComputeStoragePartitionId();
-  if (storage_partition_id_.has_value()) {
-    // Verify that setting `site_info_` did not cause the storage_partition_id
-    // to change from the value that was previously computed.
-    CHECK_EQ(storage_partition_id_.value(), storage_partition_id);
-  } else {
-    // The partition ID was never requested before `site_info` was set so
-    // assign it now.
-    storage_partition_id_ = storage_partition_id;
-  }
-
   // Now that we have a site, register it with the BrowsingInstance.  This
   // ensures that we won't create another SiteInstance for this site within
   // the same BrowsingInstance, because all same-site pages within a
@@ -986,6 +1004,19 @@
   return site_info_;
 }
 
+const SiteInfo& SiteInstanceImpl::GetSiteInfoForRenderViewHost() {
+  if (!has_site_) {
+    // Note: `site_info_` has not been set yet. When the RenderViewHost uses
+    // this SiteInfo to generate a partition ID it will be using an empty
+    // SiteInfo. This is ok as long as the ID does not change when `site_info_`
+    // is actually set. Enable the verification code in SetSiteInfoInternal() to
+    // verify that the partition info does not change.
+    verify_storage_partition_info_ = true;
+  }
+
+  return site_info_;
+}
+
 SiteInfo SiteInstanceImpl::DeriveSiteInfo(const UrlInfo& url_info,
                                           bool is_related) {
   if (IsGuest()) {
@@ -1256,23 +1287,6 @@
   return storage_partition->GetPartitionDomain();
 }
 
-const StoragePartitionId& SiteInstanceImpl::GetStoragePartitionId() {
-  if (!storage_partition_id_.has_value()) {
-    // Note: This can get called before `site_info_` is set. This will result
-    // in a partition ID being generated from an empty site URL. This is ok
-    // as long as the ID does not change when `site_info_` is actually set.
-    // There is code in SetSiteInfoInternal() to verify this condition.
-    storage_partition_id_ = ComputeStoragePartitionId();
-  }
-
-  return storage_partition_id_.value();
-}
-
-StoragePartitionId SiteInstanceImpl::ComputeStoragePartitionId() const {
-  return GetContentClient()->browser()->GetStoragePartitionIdForSite(
-      browsing_instance_->GetBrowserContext(), site_info_.site_url());
-}
-
 bool SiteInstanceImpl::IsOriginalUrlSameSite(
     const UrlInfo& dest_url_info,
     bool should_compare_effective_urls) {
diff --git a/content/browser/site_instance_impl.h b/content/browser/site_instance_impl.h
index 95da3d9..a52a337 100644
--- a/content/browser/site_instance_impl.h
+++ b/content/browser/site_instance_impl.h
@@ -260,6 +260,15 @@
   // RenderProcessHost per site for the entire browser context.
   bool ShouldUseProcessPerSite(BrowserContext* browser_context) const;
 
+  // Get the partition ID or StoragePartitionConfig for this object given a
+  // specific `browser_context`. The BrowserContext will affect whether the
+  // partition is forced to be in memory based on whether it is off-the-record
+  // or not.
+  StoragePartitionId GetStoragePartitionId(
+      BrowserContext* browser_context) const;
+  StoragePartitionConfig GetStoragePartitionConfig(
+      BrowserContext* browser_context) const;
+
  private:
   static auto MakeTie(const SiteInfo& site_info);
 
@@ -506,6 +515,18 @@
   // GetSiteURL().
   const SiteInfo& GetSiteInfo();
 
+  // Called when a RenderViewHost was created with this object. It returns the
+  // same information as GetSiteInfo(), but also enables extra checks to ensure
+  // that the StoragePartition info for this object does not change when
+  // |site_info_| is set. This is important to verify if the SiteInfo has not
+  // been explicitly set at the time of this call (e.g. first navigation in a
+  // new tab).
+  // TODO(acolwell) : Remove once RenderViewHost no longer needs to store a
+  // SiteInfo and can store a StoragePartitionConfig instead. Extra verification
+  // should be enabled when the config is fetched and |site_info_| has not been
+  // set yet.
+  const SiteInfo& GetSiteInfoForRenderViewHost();
+
   // Derives a new SiteInfo based on this SiteInstance's current state, and
   // the information provided in |url_info|. This function is slightly different
   // than SiteInfo::Create() because it takes into account information
@@ -542,10 +563,6 @@
   // safe.
   std::string GetPartitionDomain(StoragePartitionImpl* storage_partition);
 
-  // Storage Partition ID to use when associating storage partition namespaces
-  // with this object.
-  const StoragePartitionId& GetStoragePartitionId();
-
   // Set the web site that this SiteInstance is rendering pages for.
   // This includes the scheme and registered domain, but not the port.  If the
   // URL does not have a valid registered domain, then the full hostname is
@@ -736,10 +753,6 @@
   // to be handled by this default SiteInstance.
   void AddSiteInfoToDefault(const SiteInfo& site_info);
 
-  // Helper function that asks the embedder to compute a storage partition ID
-  // based on the current `site_info_`.
-  StoragePartitionId ComputeStoragePartitionId() const;
-
   // Return whether both UrlInfos must share a process to preserve script
   // relationships.  The decision is based on a variety of factors such as
   // the registered domain of the URLs (google.com, bbc.co.uk), the scheme
@@ -833,12 +846,9 @@
   class DefaultSiteInstanceState;
   std::unique_ptr<DefaultSiteInstanceState> default_site_instance_state_;
 
-  // Keeps track of the storage partition ID associated with this object.
-  // It caches the value returned by the embedder so it can ensure consistent
-  // values are returned over the lifetime of this object. This member gets set
-  // by either GetStoragePartitionId() or SetSiteInfoInternal(), whichever is
-  // called first.
-  base::Optional<StoragePartitionId> storage_partition_id_;
+  // Keeps track of whether we need to verify that the StoragePartition
+  // information does not change when `site_info_` is set.
+  bool verify_storage_partition_info_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(SiteInstanceImpl);
 };
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 2952c607..df0a134 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -10222,8 +10222,8 @@
   EXPECT_EQ(foo_url, web_contents()->GetMainFrame()->GetLastCommittedURL());
 }
 
-// The test is flaky on lacros, cf https://crbug.com/1170583.
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
+// The test is flaky on Linux, Chrome OS, etc; cf https://crbug.com/1170583.
+#if defined(OS_POSIX)
 #define MAYBE_CrossProcessInertSubframe DISABLED_CrossProcessInertSubframe
 #else
 #define MAYBE_CrossProcessInertSubframe CrossProcessInertSubframe
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 4094a54..54a40fff 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -3575,7 +3575,10 @@
   auto* source_site_instance =
       static_cast<SiteInstanceImpl*>(opener->GetSiteInstance());
 
-  const auto& partition_id = source_site_instance->GetStoragePartitionId();
+  const auto& partition_id =
+      source_site_instance->GetSiteInfo().GetStoragePartitionId(
+          GetBrowserContext());
+
   {
     StoragePartition* partition = BrowserContext::GetStoragePartition(
         GetBrowserContext(), source_site_instance);
@@ -3998,11 +4001,6 @@
   return delegate_->GetDefaultMediaDeviceID(this, type);
 }
 
-SessionStorageNamespace* WebContentsImpl::GetSessionStorageNamespace(
-    SiteInstance* instance) {
-  return GetController().GetSessionStorageNamespace(instance);
-}
-
 SessionStorageNamespaceMap WebContentsImpl::GetSessionStorageNamespaceMap() {
   return GetController().GetSessionStorageNamespaceMap();
 }
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 1f383df..49468fa 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -837,8 +837,6 @@
                                   blink::mojom::MediaStreamType type) override;
   std::string GetDefaultMediaDeviceID(
       blink::mojom::MediaStreamType type) override;
-  SessionStorageNamespace* GetSessionStorageNamespace(
-      SiteInstance* instance) override;
   SessionStorageNamespaceMap GetSessionStorageNamespaceMap() override;
   bool IsOverridingUserAgent() override;
   bool IsJavaScriptDialogShowing() const override;
diff --git a/content/browser/web_package/signed_exchange_cert_fetcher.cc b/content/browser/web_package/signed_exchange_cert_fetcher.cc
index 33fa86d4..93c6785 100644
--- a/content/browser/web_package/signed_exchange_cert_fetcher.cc
+++ b/content/browser/web_package/signed_exchange_cert_fetcher.cc
@@ -125,7 +125,6 @@
     resource_request_->load_flags |=
         net::LOAD_DISABLE_CACHE | net::LOAD_BYPASS_CACHE;
   }
-  resource_request_->render_frame_id = MSG_ROUTING_NONE;
   if (devtools_proxy_) {
     cert_request_id_ = base::UnguessableToken::Create();
     resource_request_->enable_load_timing = true;
diff --git a/content/browser/web_package/signed_exchange_validity_pinger.cc b/content/browser/web_package/signed_exchange_validity_pinger.cc
index 273233a..39bed13 100644
--- a/content/browser/web_package/signed_exchange_validity_pinger.cc
+++ b/content/browser/web_package/signed_exchange_validity_pinger.cc
@@ -97,7 +97,6 @@
   // (While we don't check the result yet)
   resource_request->load_flags |=
       net::LOAD_DISABLE_CACHE | net::LOAD_BYPASS_CACHE;
-  resource_request->render_frame_id = MSG_ROUTING_NONE;
   resource_request->throttling_profile_id = throttling_profile_id;
 
   url_loader_ = blink::ThrottlingURLLoader::CreateLoaderAndStart(
diff --git a/content/browser/worker_host/worker_script_fetch_initiator.cc b/content/browser/worker_host/worker_script_fetch_initiator.cc
index b4fea28b..e510fd66 100644
--- a/content/browser/worker_host/worker_script_fetch_initiator.cc
+++ b/content/browser/worker_host/worker_script_fetch_initiator.cc
@@ -142,10 +142,6 @@
       outside_fetch_client_settings_object->referrer_policy);
   resource_request->destination = request_destination;
   resource_request->credentials_mode = credentials_mode;
-  if (creator_render_frame_host) {
-    resource_request->render_frame_id =
-        creator_render_frame_host->GetRoutingID();
-  }
 
   // For a classic worker script request:
   // https://html.spec.whatwg.org/C/#fetch-a-classic-worker-script
diff --git a/content/public/browser/browser_main_parts.cc b/content/public/browser/browser_main_parts.cc
index 8980628..e1a07b5 100644
--- a/content/public/browser/browser_main_parts.cc
+++ b/content/public/browser/browser_main_parts.cc
@@ -13,11 +13,11 @@
 }
 
 int BrowserMainParts::PreCreateThreads() {
-  return 0;
+  return RESULT_CODE_NORMAL_EXIT;
 }
 
-bool BrowserMainParts::MainMessageLoopRun(int* result_code) {
-  return false;
+int BrowserMainParts::PreMainMessageLoopRun() {
+  return RESULT_CODE_NORMAL_EXIT;
 }
 
 }  // namespace content
diff --git a/content/public/browser/browser_main_parts.h b/content/public/browser/browser_main_parts.h
index 2bfefad..f888a86 100644
--- a/content/public/browser/browser_main_parts.h
+++ b/content/public/browser/browser_main_parts.h
@@ -5,9 +5,15 @@
 #ifndef CONTENT_PUBLIC_BROWSER_BROWSER_MAIN_PARTS_H_
 #define CONTENT_PUBLIC_BROWSER_BROWSER_MAIN_PARTS_H_
 
+#include <memory>
+
 #include "base/callback.h"
 #include "content/common/content_export.h"
 
+namespace base {
+class RunLoop;
+}
+
 namespace content {
 
 // This class contains different "stages" to be executed by |BrowserMain()|,
@@ -21,15 +27,69 @@
 //    code to be called after the common code.
 //
 // Stages:
+//
 //  - EarlyInitialization: things which should be done as soon as possible on
-//    program start (such as setting up signal handlers) and things to be done
-//    at some generic time before the start of the main message loop.
-//  - MainMessageLoopStart: things beginning with the start of the main message
-//    loop and ending with initialization of the main thread; platform-specific
-//    things which should be done immediately before the start of the main
-//    message loop should go in |PreMainMessageLoopStart()|.
-//  - RunMainMessageLoopParts:  things to be done before and after invoking the
-//    main message loop run method (e.g. CurrentUIThread::Get()->Run()).
+//    program start (such as setting up signal handlers)
+//
+//  - ToolkitInitialized: similar to EarlyInitialization but for the UI toolkit.
+//    Allows an embedder to do any extra toolkit initialization.
+//
+//  - PreMainMessageLoopStart: things to be done at some generic time before the
+//    creation of the main message loop.
+//
+//  - PostMainMessageLoopStart: things that should be done as early as possible
+//    but need the main message loop to be around (i.e. APIs like
+//    ThreadTaskRunnerHandle, BrowserThread::UI are up).
+//
+//  - PreCreateThreads: things that don't need to happen super early but still
+//    need to happen during single-threaded initialization (e.g. immutable
+//    Singletons that are initialized once and read-only from all threads
+//    thereafter).
+//    Note: other threads might exist before this point but no child threads
+//    owned by content. As such, this is still "single-threaded" initialization
+//    as far as content and its embedders are concerned and the right place to
+//    initialize thread-compatible objects:
+//    https://chromium.googlesource.com/chromium/src/+/master/docs/threading_and_tasks.md#threading-lexicon
+//
+//  - PostCreateThreads: things that should be done as early as possible but
+//    need browser process threads to be alive (i.e. APIs like base::ThreadPool
+//    and BrowserThread::IO are up). In other words, core things that must be
+//    initialized before PreMainMessageLoopRun.
+//
+//  - PreMainMessageLoopRun: in doubt, put things here. At this stage all core
+//    APIs have been initialized. Services that must be initialized before the
+//    browser is considered functional can be initialized from here. Ideally
+//    only the frontend is initialized here while the backend takes advantage of
+//    a base::ThreadPool worker to come up asynchronously. Things that must
+//    happen on the main thread eventually but don't need to block startup
+//    should post a BEST_EFFORT task from this stage.
+//
+//  ** End of cross-platform startup stages **
+//    Stages above are run as part of startup stages in
+//    BrowserMainLoop::CreateStartupTasks() and can even be run eagerly (e.g.
+//    Android app warmup attempts to run these async.
+//
+//  - WillRunMainMessageLoop: The main thread's RunLoop will be run
+//    *immediately* upon returning from this method. While PreMainMessageLoopRun
+//    gives that impression, in practice it's part of initialization phases
+//    which are triggered independently from MainMessageLoopRun (and can even
+//    happen async). In browser tests, PreMainMessageLoopRun() will run before
+//    entering test bodies whereas WillRunMainMessageLoop() won't (the control
+//    is given to the test rather running the loop). Furthermore, this is only
+//    called on platforms where BrowserMainLoop::RunMainMessageLoop is called.
+//    Thus, very few things should be done at this stage. It's mostly intended
+//    as a way for embedders to override or cancel the default RunLoop if
+//    needed.
+//
+//  - PostMainMessageLoopRun: stop and cleanup things that can/should be cleaned
+//    up while base::ThreadPool and BrowserThread::IO are still running.
+//    Note: Also see BrowserMainLoop::ShutdownThreadsAndCleanUp() which is often
+//    a good fit to stop services (PostMainMessageLoopRun() is called from it).
+//
+//  - PostDestroyThreads: stop and cleanup things that need to be cleaned up in
+//    the single-threaded teardown phase (i.e. typically things that had to
+//    created in PreCreateThreads()).
+//
 //
 // How to add stuff (to existing parts):
 //  - Figure out when your new code should be executed. What must happen
@@ -37,7 +97,7 @@
 //    running your code at a particular time? Document these things!
 //  - Split out any platform-specific bits. Please avoid #ifdefs it at all
 //    possible. You have two choices for platform-specific code: (1) Execute it
-//    from one of the |Pre/Post...()| methods in a embedder's platform-specific
+//    from one of the |Pre/Post...()| methods in an embedder's platform-specific
 //    override (e.g., ChromeBrowserMainPartsWin::PreMainMessageLoopStart()); do
 //    this if the code is unique to an embedder and platform type. Or (2)
 //    execute it from one of the "stages" (e.g.,
@@ -54,50 +114,26 @@
   BrowserMainParts() {}
   virtual ~BrowserMainParts() {}
 
-  // A return value other than RESULT_CODE_NORMAL_EXIT indicates error and is
-  // used as the exit status.
-  virtual int PreEarlyInitialization();
-
-  virtual void PostEarlyInitialization() {}
-
-  virtual void PreMainMessageLoopStart() {}
-
-  virtual void PostMainMessageLoopStart() {}
-
-  // Allows an embedder to do any extra toolkit initialization.
-  virtual void ToolkitInitialized() {}
-
-  // Called just before any child threads owned by the content
-  // framework are created.
+  // See class comment above for a description of each phase.
   //
-  // The main message loop has been started at this point (but has not
-  // been run), and the toolkit has been initialized. Returns the error code
-  // (or 0 if no error).
+  // A return value other than RESULT_CODE_NORMAL_EXIT on any of these methods
+  // indicates an error, aborts startup, and is used as the exit status.
+  virtual int PreEarlyInitialization();
+  virtual void PostEarlyInitialization() {}
+  virtual void ToolkitInitialized() {}
+  virtual void PreMainMessageLoopStart() {}
+  virtual void PostMainMessageLoopStart() {}
   virtual int PreCreateThreads();
-
-  // This is called right after all child threads owned by the content framework
-  // are created.
   virtual void PostCreateThreads() {}
+  virtual int PreMainMessageLoopRun();
 
-  // This is called just before the main message loop is run.  The
-  // various browser threads have all been created at this point
-  virtual void PreMainMessageLoopRun() {}
+  // This gives BrowserMainParts one last opportunity to tweak the upcoming main
+  // message loop run. The embedder may replace |run_loop| to alter the default
+  // RunLoop about to be run or even reset() it to cancel the upcoming run.
+  virtual void WillRunMainMessageLoop(
+      std::unique_ptr<base::RunLoop>& run_loop) {}
 
-  // Returns true if the message loop was run, false otherwise.
-  // If this returns false, the default implementation will be run.
-  // May set |result_code|, which will be returned by |BrowserMain()|.
-  virtual bool MainMessageLoopRun(int* result_code);
-
-  // Provides an embedder with a Closure which will quit the default main
-  // message loop. This is call only if MainMessageLoopRun returns false.
-  virtual void PreDefaultMainMessageLoopRun(base::OnceClosure quit_closure) {}
-
-  // This happens after the main message loop has stopped, but before
-  // threads are stopped.
   virtual void PostMainMessageLoopRun() {}
-
-  // Called as the very last part of shutdown, after threads have been
-  // stopped and destroyed.
   virtual void PostDestroyThreads() {}
 };
 
diff --git a/content/public/browser/storage_partition_config.cc b/content/public/browser/storage_partition_config.cc
index ee300a4..ad85c3b 100644
--- a/content/public/browser/storage_partition_config.cc
+++ b/content/public/browser/storage_partition_config.cc
@@ -5,6 +5,7 @@
 #include "content/public/browser/storage_partition_config.h"
 
 #include "base/check.h"
+#include "base/strings/string_number_conversions.h"
 #include "content/public/browser/browser_context.h"
 #include "url/gurl.h"
 
@@ -97,4 +98,26 @@
   return !(*this == rhs);
 }
 
+std::ostream& operator<<(std::ostream& out,
+                         const StoragePartitionConfig& config) {
+  out << "{";
+  if (config.is_default()) {
+    out << "default";
+  } else {
+    out << "partition_domain='" << config.partition_domain() << "'";
+    out << " partition_name='" << config.partition_name() << "'";
+
+    if (config.in_memory())
+      out << " in_memory";
+
+    auto fallback_mode = config.fallback_to_partition_domain_for_blob_urls();
+    if (fallback_mode != StoragePartitionConfig::FallbackMode::kNone) {
+      out << " fallback_mode="
+          << base::NumberToString(static_cast<int>(fallback_mode));
+    }
+  }
+  out << "}";
+  return out;
+}
+
 }  // namespace content
diff --git a/content/public/browser/storage_partition_config.h b/content/public/browser/storage_partition_config.h
index 708e067..a26db386 100644
--- a/content/public/browser/storage_partition_config.h
+++ b/content/public/browser/storage_partition_config.h
@@ -96,6 +96,9 @@
       FallbackMode::kNone;
 };
 
+CONTENT_EXPORT std::ostream& operator<<(std::ostream& out,
+                                        const StoragePartitionConfig& config);
+
 // Represents the storage partition ID that is used as the key for the
 // SessionStorageNamespaceMap. This type is to help facilitate migrating the
 // map key away from a string to a StoragePartitionConfig.
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 7d52afb..81e1a34 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -230,7 +230,7 @@
 // media-device enumeration will provide at most one device per type and the
 // device IDs will not be available.
 // TODO(crbug.com/1019176): remove the feature in M89.
-const base::Feature kEnumerateDevicesHideDeviceIDs {
+const base::Feature kEnumerateDevicesHideDeviceIDs{
   "EnumerateDevicesHideDeviceIDs",
 #if defined(OS_ANDROID)
       base::FEATURE_DISABLED_BY_DEFAULT
@@ -401,7 +401,7 @@
     {MBIMode::kLegacy, "legacy"},
     {MBIMode::kEnabledPerRenderProcessHost, "per_render_process_host"},
     {MBIMode::kEnabledPerSiteInstance, "per_site_instance"}};
-const base::FeatureParam<MBIMode> kMBIModeParam {
+const base::FeatureParam<MBIMode> kMBIModeParam{
   &kMBIMode, "mode",
 #if BUILDFLAG(MBI_MODE_PER_RENDER_PROCESS_HOST)
       MBIMode::kEnabledPerRenderProcessHost,
@@ -1030,8 +1030,7 @@
 // On ChromeOS the service must run in the browser process, because parts of the
 // code depend on global objects that are only available in the Browser process.
 // See https://crbug.com/891961.
-#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH) || \
-    BUILDFLAG(IS_CHROMEOS_LACROS)
+#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
   return VideoCaptureServiceConfiguration::kEnabledForBrowserProcess;
 #else
 #if defined(OS_WIN)
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index dbe9cc7..f2315aa 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -3361,13 +3361,11 @@
     network::mojom::URLLoaderFactory* url_loader_factory,
     const GURL& url,
     int load_flags,
-    const base::Optional<url::Origin>& request_initiator = base::nullopt,
-    int render_frame_id = MSG_ROUTING_NONE) {
+    const base::Optional<url::Origin>& request_initiator = base::nullopt) {
   auto request = std::make_unique<network::ResourceRequest>();
   request->url = url;
   request->load_flags = load_flags;
   request->request_initiator = request_initiator;
-  request->render_frame_id = render_frame_id;
   // Allow access to SameSite cookies in tests.
   request->site_for_cookies = net::SiteForCookies::FromUrl(url);
 
@@ -3413,8 +3411,7 @@
       url_loader_factory.BindNewPipeAndPassReceiver());
   return LoadBasicRequest(
       url_loader_factory.get(), url, 0 /* load_flags */,
-      frame->GetLastCommittedOrigin() /* request_initiator */,
-      frame->GetRoutingID());
+      frame->GetLastCommittedOrigin() /* request_initiator */);
 }
 
 void EnsureCookiesFlushed(BrowserContext* browser_context) {
diff --git a/content/renderer/loader/web_worker_fetch_context_impl.cc b/content/renderer/loader/web_worker_fetch_context_impl.cc
index 8704bde76..a16b8ba 100644
--- a/content/renderer/loader/web_worker_fetch_context_impl.cc
+++ b/content/renderer/loader/web_worker_fetch_context_impl.cc
@@ -454,7 +454,6 @@
 
   auto url_request_extra_data =
       base::MakeRefCounted<blink::WebURLRequestExtraData>();
-  url_request_extra_data->set_render_frame_id(ancestor_frame_id_);
   url_request_extra_data->set_frame_request_blocker(frame_request_blocker_);
   if (throttle_provider_) {
     url_request_extra_data->set_url_loader_throttles(
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index e8744f4..ca0f2893 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -4423,7 +4423,6 @@
   auto* url_request_extra_data = static_cast<blink::WebURLRequestExtraData*>(
       request.GetURLRequestExtraData().get());
   url_request_extra_data->set_custom_user_agent(custom_user_agent);
-  url_request_extra_data->set_render_frame_id(routing_id_);
   url_request_extra_data->set_is_main_frame(IsMainFrame());
   url_request_extra_data->set_transition_type(transition_type);
   bool is_for_no_state_prefetch =
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index 42dda49..79334c2 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -384,8 +384,7 @@
           ->renderer()
           ->CreateWebSocketHandshakeThrottleProvider(),
       std::move(preference_watcher_receiver_),
-      std::move(pending_subresource_loader_updater_), service_worker_route_id_,
-      cors_exempt_header_list_);
+      std::move(pending_subresource_loader_updater_), cors_exempt_header_list_);
 }
 
 void ServiceWorkerContextClient::OnNavigationPreloadResponse(
diff --git a/content/renderer/service_worker/service_worker_fetch_context_impl.cc b/content/renderer/service_worker/service_worker_fetch_context_impl.cc
index cb36312..df9ed98 100644
--- a/content/renderer/service_worker/service_worker_fetch_context_impl.cc
+++ b/content/renderer/service_worker/service_worker_fetch_context_impl.cc
@@ -34,7 +34,6 @@
         preference_watcher_receiver,
     mojo::PendingReceiver<blink::mojom::SubresourceLoaderUpdater>
         pending_subresource_loader_updater,
-    int32_t service_worker_route_id,
     const std::vector<std::string>& cors_exempt_header_list)
     : renderer_preferences_(renderer_preferences),
       worker_script_url_(worker_script_url),
@@ -48,7 +47,6 @@
           std::move(preference_watcher_receiver)),
       pending_subresource_loader_updater_(
           std::move(pending_subresource_loader_updater)),
-      service_worker_route_id_(service_worker_route_id),
       cors_exempt_header_list_(cors_exempt_header_list) {}
 
 ServiceWorkerFetchContextImpl::~ServiceWorkerFetchContextImpl() {}
@@ -115,7 +113,6 @@
   auto url_request_extra_data =
       base::MakeRefCounted<blink::WebURLRequestExtraData>();
   url_request_extra_data->set_originated_from_service_worker(true);
-  url_request_extra_data->set_render_frame_id(service_worker_route_id_);
 
   const bool needs_to_skip_throttling =
       static_cast<GURL>(request.Url()) == script_url_to_skip_throttling_ &&
diff --git a/content/renderer/service_worker/service_worker_fetch_context_impl.h b/content/renderer/service_worker/service_worker_fetch_context_impl.h
index e4fe346..9f64fe3 100644
--- a/content/renderer/service_worker/service_worker_fetch_context_impl.h
+++ b/content/renderer/service_worker/service_worker_fetch_context_impl.h
@@ -56,7 +56,6 @@
           preference_watcher_receiver,
       mojo::PendingReceiver<blink::mojom::SubresourceLoaderUpdater>
           pending_subresource_loader_updater,
-      int32_t service_worker_route_id,
       const std::vector<std::string>& cors_exempt_header_list);
 
   // blink::WebServiceWorkerFetchContext implementation:
@@ -142,7 +141,6 @@
 
   blink::AcceptLanguagesWatcher* accept_languages_watcher_ = nullptr;
 
-  int32_t service_worker_route_id_;
   std::vector<std::string> cors_exempt_header_list_;
   bool is_offline_mode_ = false;
 };
diff --git a/content/renderer/service_worker/service_worker_fetch_context_impl_unittest.cc b/content/renderer/service_worker/service_worker_fetch_context_impl_unittest.cc
index 8f95b2d..ada1226 100644
--- a/content/renderer/service_worker/service_worker_fetch_context_impl_unittest.cc
+++ b/content/renderer/service_worker/service_worker_fetch_context_impl_unittest.cc
@@ -50,7 +50,6 @@
       std::make_unique<FakeURLLoaderThrottleProvider>(),
       /*websocket_handshake_throttle_provider=*/nullptr, mojo::NullReceiver(),
       mojo::NullReceiver(),
-      /*service_worker_route_id=*/-1,
       /*cors_exempt_header_list=*/std::vector<std::string>());
 
   {
diff --git a/content/renderer/service_worker/service_worker_subresource_loader.cc b/content/renderer/service_worker/service_worker_subresource_loader.cc
index f5403e9..65e15a0 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader.cc
+++ b/content/renderer/service_worker/service_worker_subresource_loader.cc
@@ -712,7 +712,19 @@
       TRACE_ID_WITH_SCOPE(kServiceWorkerSubresourceLoaderScope,
                           TRACE_ID_LOCAL(request_id_)),
       TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "new_url",
-      redirect_info_->new_url.spec());
+      redirect_info_ ? redirect_info_->new_url.spec() : "(none)");
+
+  // In rare cases, the client seems to call FollowRedirect() when we aren't
+  // expecting it. Just complete with error if we have not already completed.
+  // https://crbug.com/1162035
+  if (!redirect_info_) {
+    if (status_ != Status::kCompleted)
+      CommitCompleted(net::ERR_INVALID_REDIRECT);
+    return;
+  }
+
+  DCHECK_EQ(status_, Status::kSentRedirect);
+
   // TODO(arthursonzogni, juncai): This seems to be correctly implemented, but
   // not used so far. Add tests and remove this DCHECK to support this feature
   // if needed. See https://crbug.com/845683.
@@ -721,7 +733,6 @@
          "https://crbug.com/845683";
   DCHECK(!new_url.has_value()) << "Redirect with modified url was not "
                                   "supported yet. crbug.com/845683";
-  DCHECK(redirect_info_);
 
   bool should_clear_upload = false;
   net::RedirectUtil::UpdateHttpRequest(
diff --git a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
index 2565cd5..73a1651 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
+++ b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
@@ -197,6 +197,9 @@
     blob_range_body_ = body;
   }
 
+  // Tells this controller to not respond to fetch events.
+  void DontRespond() { response_mode_ = ResponseMode::kDontRespond; }
+
   void ReadRequestBody(std::string* out_string) {
     ASSERT_TRUE(request_body_);
     std::vector<network::DataElement>* elements =
@@ -337,13 +340,16 @@
         std::move(callback).Run(
             blink::mojom::ServiceWorkerEventStatus::REJECTED);
         break;
-      case ResponseMode::kRedirectResponse: {
+      case ResponseMode::kRedirectResponse:
         response_callback->OnResponse(
             RedirectResponse(redirect_location_header_), std::move(timing));
         std::move(callback).Run(
             blink::mojom::ServiceWorkerEventStatus::COMPLETED);
         break;
-      }
+      case ResponseMode::kDontRespond:
+        response_callback_ = std::move(response_callback);
+        callback_ = std::move(callback);
+        break;
     }
     if (fetch_event_callback_)
       std::move(fetch_event_callback_).Run();
@@ -377,7 +383,8 @@
     kBlobRange,
     kFallbackResponse,
     kErrorResponse,
-    kRedirectResponse
+    kRedirectResponse,
+    kDontRespond
   };
 
   ResponseMode response_mode_ = ResponseMode::kDefault;
@@ -397,9 +404,14 @@
   // For ResponseMode::kBlobRange.
   std::string blob_range_body_;
 
-  // For ResponseMode::kRedirectResponse
+  // For ResponseMode::kRedirectResponse.
   std::string redirect_location_header_;
 
+  // For ResponseMode::kDontRespond.
+  DispatchFetchEventForSubresourceCallback callback_;
+  mojo::Remote<blink::mojom::ServiceWorkerFetchResponseCallback>
+      response_callback_;
+
   network::mojom::FetchResponseSource response_source_ =
       network::mojom::FetchResponseSource::kUnspecified;
 
@@ -1392,6 +1404,27 @@
                                       net::URLRequest::kMaxRedirects + 1);
 }
 
+TEST_F(ServiceWorkerSubresourceLoaderTest, FollowNonexistentRedirect) {
+  // Delay the response from the service worker indefinitely so the test can
+  // run without races.
+  fake_controller_.DontRespond();
+
+  // Start a request.
+  mojo::Remote<network::mojom::URLLoaderFactory> factory =
+      CreateSubresourceLoaderFactory();
+  network::ResourceRequest request =
+      CreateRequest(GURL("https://www.example.com/foo.png"));
+  mojo::Remote<network::mojom::URLLoader> loader;
+  std::unique_ptr<network::TestURLLoaderClient> client;
+  StartRequest(factory, request, &loader, &client);
+
+  // Tell the loader to follow a non-existent redirect. It should complete
+  // with network error.
+  loader->FollowRedirect({}, {}, {}, base::nullopt);
+  client->RunUntilComplete();
+  EXPECT_EQ(net::ERR_INVALID_REDIRECT, client->completion_status().error_code);
+}
+
 TEST_F(ServiceWorkerSubresourceLoaderTest, FallbackWithRequestBody_String) {
   const std::string kData = "Hi, this is the request body (string)";
   auto request_body = base::MakeRefCounted<network::ResourceRequestBody>();
diff --git a/content/shell/browser/shell_browser_main_parts.cc b/content/shell/browser/shell_browser_main_parts.cc
index df674eb..b70f307b 100644
--- a/content/shell/browser/shell_browser_main_parts.cc
+++ b/content/shell/browser/shell_browser_main_parts.cc
@@ -205,7 +205,7 @@
           performance_manager::Decorators::kMinimal, base::DoNothing());
 }
 
-void ShellBrowserMainParts::PreMainMessageLoopRun() {
+int ShellBrowserMainParts::PreMainMessageLoopRun() {
   InitializeBrowserContexts();
   Shell::Initialize(CreateShellPlatformDelegate());
   net::NetModule::SetResourceProvider(PlatformResourceProvider);
@@ -217,10 +217,16 @@
     delete parameters_.ui_task;
     run_message_loop_ = false;
   }
+
+  return 0;
 }
 
-bool ShellBrowserMainParts::MainMessageLoopRun(int* result_code)  {
-  return !run_message_loop_;
+void ShellBrowserMainParts::WillRunMainMessageLoop(
+    std::unique_ptr<base::RunLoop>& run_loop) {
+  if (run_message_loop_)
+    Shell::SetMainMessageLoopQuitClosure(run_loop->QuitClosure());
+  else
+    run_loop.reset();
 }
 
 void ShellBrowserMainParts::PostMainMessageLoopRun() {
@@ -233,11 +239,6 @@
   performance_manager_lifetime_.reset();
 }
 
-void ShellBrowserMainParts::PreDefaultMainMessageLoopRun(
-    base::OnceClosure quit_closure) {
-  Shell::SetMainMessageLoopQuitClosure(std::move(quit_closure));
-}
-
 void ShellBrowserMainParts::PostDestroyThreads() {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   device::BluetoothAdapterFactory::Shutdown();
diff --git a/content/shell/browser/shell_browser_main_parts.h b/content/shell/browser/shell_browser_main_parts.h
index 65259192..d39242b 100644
--- a/content/shell/browser/shell_browser_main_parts.h
+++ b/content/shell/browser/shell_browser_main_parts.h
@@ -40,9 +40,9 @@
   void PreMainMessageLoopStart() override;
   void PostMainMessageLoopStart() override;
   void ToolkitInitialized() override;
-  void PreMainMessageLoopRun() override;
-  bool MainMessageLoopRun(int* result_code) override;
-  void PreDefaultMainMessageLoopRun(base::OnceClosure quit_closure) override;
+  int PreMainMessageLoopRun() override;
+  void WillRunMainMessageLoop(
+      std::unique_ptr<base::RunLoop>& run_loop) override;
   void PostMainMessageLoopRun() override;
   void PostDestroyThreads() override;
 
diff --git a/content/shell/common/power_monitor_test_impl.cc b/content/shell/common/power_monitor_test_impl.cc
index d0864a0c..f562f84 100644
--- a/content/shell/common/power_monitor_test_impl.cc
+++ b/content/shell/common/power_monitor_test_impl.cc
@@ -20,11 +20,11 @@
 }
 
 PowerMonitorTestImpl::PowerMonitorTestImpl() {
-  base::PowerMonitor::AddObserver(this);
+  base::PowerMonitor::AddPowerStateObserver(this);
 }
 
 PowerMonitorTestImpl::~PowerMonitorTestImpl() {
-  base::PowerMonitor::RemoveObserver(this);
+  base::PowerMonitor::RemovePowerStateObserver(this);
 }
 
 void PowerMonitorTestImpl::QueryNextState(QueryNextStateCallback callback) {
diff --git a/content/shell/common/power_monitor_test_impl.h b/content/shell/common/power_monitor_test_impl.h
index 39d698e..13f7597 100644
--- a/content/shell/common/power_monitor_test_impl.h
+++ b/content/shell/common/power_monitor_test_impl.h
@@ -12,7 +12,7 @@
 
 namespace content {
 
-class PowerMonitorTestImpl : public base::PowerObserver,
+class PowerMonitorTestImpl : public base::PowerStateObserver,
                              public mojom::PowerMonitorTest {
  public:
   static void MakeSelfOwnedReceiver(
@@ -25,10 +25,8 @@
   // mojom::PowerMonitorTest:
   void QueryNextState(QueryNextStateCallback callback) override;
 
-  // base::PowerObserver:
+  // base::PowerStateObserver:
   void OnPowerStateChange(bool on_battery_power) override;
-  void OnSuspend() override {}
-  void OnResume() override {}
 
   void ReportState();
 
diff --git a/content/test/data/accessibility/accname/desc-combobox-focusable-expected-android.txt b/content/test/data/accessibility/accname/desc-combobox-focusable-expected-android.txt
new file mode 100644
index 0000000..9ab123e
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-combobox-focusable-expected-android.txt
@@ -0,0 +1 @@
+android.widget.Spinner
diff --git a/content/test/data/accessibility/accname/desc-combobox-focusable-expected-auralinux.txt b/content/test/data/accessibility/accname/desc-combobox-focusable-expected-auralinux.txt
new file mode 100644
index 0000000..97dc1466
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-combobox-focusable-expected-auralinux.txt
@@ -0,0 +1 @@
+[combo box] description=''
diff --git a/content/test/data/accessibility/accname/desc-combobox-focusable-expected-blink.txt b/content/test/data/accessibility/accname/desc-combobox-focusable-expected-blink.txt
new file mode 100644
index 0000000..2fc9f9dd
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-combobox-focusable-expected-blink.txt
@@ -0,0 +1 @@
+comboBoxMenuButton
diff --git a/content/test/data/accessibility/accname/desc-combobox-focusable-expected-mac.txt b/content/test/data/accessibility/accname/desc-combobox-focusable-expected-mac.txt
new file mode 100644
index 0000000..aa2dff1
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-combobox-focusable-expected-mac.txt
@@ -0,0 +1 @@
+AXComboBox
diff --git a/content/test/data/accessibility/accname/desc-combobox-focusable-expected-win.txt b/content/test/data/accessibility/accname/desc-combobox-focusable-expected-win.txt
new file mode 100644
index 0000000..9820d48
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-combobox-focusable-expected-win.txt
@@ -0,0 +1 @@
+ROLE_SYSTEM_COMBOBOX FOCUSABLE HASPOPUP description=''
diff --git a/content/test/data/accessibility/accname/desc-combobox-focusable.html b/content/test/data/accessibility/accname/desc-combobox-focusable.html
new file mode 100644
index 0000000..283ff9e
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-combobox-focusable.html
@@ -0,0 +1,16 @@
+<!--
+@BLINK-DENY:name*
+@ANDROID-DENY:name*
+@AURALINUX-DENY:name*
+@MAC-DENY:AXDescription*
+@MAC-DENY:AXValue*
+@WIN-DENY:name*
+-->
+<!doctype html>
+<html>
+<body>
+<div id="test" role="combobox" tabindex="0" title="Choose your language.">
+<span> English </span>
+</div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/desc-from-content-of-describedby-element-expected-android.txt b/content/test/data/accessibility/accname/desc-from-content-of-describedby-element-expected-android.txt
new file mode 100644
index 0000000..5fc88c7
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-from-content-of-describedby-element-expected-android.txt
@@ -0,0 +1 @@
+android.widget.EditText hint='Important stuff My name is Eli the weird. (QED) Where are my marbles?' input_type=1
diff --git a/content/test/data/accessibility/accname/desc-from-content-of-describedby-element-expected-auralinux.txt b/content/test/data/accessibility/accname/desc-from-content-of-describedby-element-expected-auralinux.txt
new file mode 100644
index 0000000..8d38264
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-from-content-of-describedby-element-expected-auralinux.txt
@@ -0,0 +1 @@
+[entry] description='My name is Eli the weird. (QED) Where are my marbles?' described-by
diff --git a/content/test/data/accessibility/accname/desc-from-content-of-describedby-element-expected-blink.txt b/content/test/data/accessibility/accname/desc-from-content-of-describedby-element-expected-blink.txt
new file mode 100644
index 0000000..7f445f4b
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-from-content-of-describedby-element-expected-blink.txt
@@ -0,0 +1 @@
+textField description='My name is Eli the weird. (QED) Where are my marbles?' descriptionFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/desc-from-content-of-describedby-element-expected-mac.txt b/content/test/data/accessibility/accname/desc-from-content-of-describedby-element-expected-mac.txt
new file mode 100644
index 0000000..872c1aa
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-from-content-of-describedby-element-expected-mac.txt
@@ -0,0 +1 @@
+AXTextField AXHelp='My name is Eli the weird. (QED) Where are my marbles?'
diff --git a/content/test/data/accessibility/accname/desc-from-content-of-describedby-element-expected-win.txt b/content/test/data/accessibility/accname/desc-from-content-of-describedby-element-expected-win.txt
new file mode 100644
index 0000000..e1b64e8b
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-from-content-of-describedby-element-expected-win.txt
@@ -0,0 +1 @@
+ROLE_SYSTEM_TEXT FOCUSABLE description='My name is Eli the weird. (QED) Where are my marbles?'
diff --git a/content/test/data/accessibility/accname/desc-from-content-of-describedby-element.html b/content/test/data/accessibility/accname/desc-from-content-of-describedby-element.html
new file mode 100644
index 0000000..23ae5ba
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-from-content-of-describedby-element.html
@@ -0,0 +1,36 @@
+<!--
+@BLINK-DENY:name*
+@ANDROID-DENY:name*
+@AURALINUX-DENY:name*
+@MAC-DENY:AXDescription*
+@MAC-DENY:AXValue*
+@WIN-DENY:name*
+-->
+<!doctype html>
+<html>
+<body>
+<style>
+  .hidden { display: none; }
+</style>
+<input id="test" type="text" aria-label="Important stuff" aria-describedby="descId" />
+<div id="descId">
+  <span aria-hidden="true"><i> Hello, </i></span>
+  <span>My</span> name is
+  <div><img src="file.jpg" title="Bryan" alt="" role="presentation" /></div>
+  <span role="presentation" aria-label="Eli">
+    <span aria-label="Garaventa">Zambino</span>
+  </span>
+  <span>the weird.</span>
+  (QED)
+  <span class="hidden"><i><b>and don't you forget it.</b></i></span>
+  <table>
+    <tr>
+      <td>Where</td>
+      <td style="visibility:hidden;"><div>in</div></td>
+      <td><div style="display:none;">the world</div></td>
+      <td>are my marbles?</td>
+    </tr>
+  </table>
+</div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/desc-img-alt-describedby-expected-blink.txt b/content/test/data/accessibility/accname/desc-img-alt-describedby-expected-blink.txt
new file mode 100644
index 0000000..601e4b6
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-img-alt-describedby-expected-blink.txt
@@ -0,0 +1 @@
+image description='foo' descriptionFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/desc-img-alt-describedby-hidden-expected-blink.txt b/content/test/data/accessibility/accname/desc-img-alt-describedby-hidden-expected-blink.txt
new file mode 100644
index 0000000..601e4b6
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-img-alt-describedby-hidden-expected-blink.txt
@@ -0,0 +1 @@
+image description='foo' descriptionFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/desc-img-alt-describedby-hidden.html b/content/test/data/accessibility/accname/desc-img-alt-describedby-hidden.html
new file mode 100644
index 0000000..34a19c6
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-img-alt-describedby-hidden.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:name*
+-->
+<!doctype html>
+<html>
+<body>
+<img src="foo.jpg" id="test" alt="test" aria-describedby="t1">
+<div id="t1" style="visibility:hidden">foo</div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/desc-img-alt-describedby-invalid-expected-blink.txt b/content/test/data/accessibility/accname/desc-img-alt-describedby-invalid-expected-blink.txt
new file mode 100644
index 0000000..773b222
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-img-alt-describedby-invalid-expected-blink.txt
@@ -0,0 +1 @@
+image
diff --git a/content/test/data/accessibility/accname/desc-img-alt-describedby-invalid.html b/content/test/data/accessibility/accname/desc-img-alt-describedby-invalid.html
new file mode 100644
index 0000000..6848506
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-img-alt-describedby-invalid.html
@@ -0,0 +1,9 @@
+<!--
+@BLINK-DENY:name*
+-->
+<!doctype html>
+<html>
+<body>
+<img src="foo.jpg" id="test" alt="test" aria-describedby="t1">
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/desc-img-alt-describedby-not-displayed-expected-blink.txt b/content/test/data/accessibility/accname/desc-img-alt-describedby-not-displayed-expected-blink.txt
new file mode 100644
index 0000000..601e4b6
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-img-alt-describedby-not-displayed-expected-blink.txt
@@ -0,0 +1 @@
+image description='foo' descriptionFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/desc-img-alt-describedby-not-displayed.html b/content/test/data/accessibility/accname/desc-img-alt-describedby-not-displayed.html
new file mode 100644
index 0000000..d87f1a46
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-img-alt-describedby-not-displayed.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:name*
+-->
+<!doctype html>
+<html>
+<body>
+<img src="foo.jpg" id="test" alt="test" aria-describedby="t1">
+<div id="t1" style="display:none">foo</div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/desc-img-alt-describedby-presentational-expected-blink.txt b/content/test/data/accessibility/accname/desc-img-alt-describedby-presentational-expected-blink.txt
new file mode 100644
index 0000000..601e4b6
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-img-alt-describedby-presentational-expected-blink.txt
@@ -0,0 +1 @@
+image description='foo' descriptionFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/desc-img-alt-describedby-presentational.html b/content/test/data/accessibility/accname/desc-img-alt-describedby-presentational.html
new file mode 100644
index 0000000..a6a5052
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-img-alt-describedby-presentational.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:name*
+-->
+<!doctype html>
+<html>
+<body>
+<img src="foo.jpg" id="test" alt="test" aria-describedby="t1">
+<span id="t1" role="presentation">foo</span>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/desc-img-alt-describedby.html b/content/test/data/accessibility/accname/desc-img-alt-describedby.html
new file mode 100644
index 0000000..7b22f55
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-img-alt-describedby.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:name*
+-->
+<!doctype html>
+<html>
+<body>
+<img src="foo.jpg" id="test" alt="test" aria-describedby="t1">
+<div id="t1">foo</div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/desc-img-describedby-expected-blink.txt b/content/test/data/accessibility/accname/desc-img-describedby-expected-blink.txt
new file mode 100644
index 0000000..601e4b6
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-img-describedby-expected-blink.txt
@@ -0,0 +1 @@
+image description='foo' descriptionFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/desc-img-describedby-not-displayed-expected-blink.txt b/content/test/data/accessibility/accname/desc-img-describedby-not-displayed-expected-blink.txt
new file mode 100644
index 0000000..601e4b6
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-img-describedby-not-displayed-expected-blink.txt
@@ -0,0 +1 @@
+image description='foo' descriptionFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/desc-img-describedby-not-displayed.html b/content/test/data/accessibility/accname/desc-img-describedby-not-displayed.html
new file mode 100644
index 0000000..70bb070d
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-img-describedby-not-displayed.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:name*
+-->
+<!doctype html>
+<html>
+<body>
+<img id="test" aria-describedby="ID1" src="test.png">
+<div id="ID1" style="display:none">foo</div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/desc-img-describedby-presentational-expected-blink.txt b/content/test/data/accessibility/accname/desc-img-describedby-presentational-expected-blink.txt
new file mode 100644
index 0000000..601e4b6
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-img-describedby-presentational-expected-blink.txt
@@ -0,0 +1 @@
+image description='foo' descriptionFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/desc-img-describedby-presentational.html b/content/test/data/accessibility/accname/desc-img-describedby-presentational.html
new file mode 100644
index 0000000..c7973bc
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-img-describedby-presentational.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:name*
+-->
+<!doctype html>
+<html>
+<body>
+<img id="test" aria-describedby="ID1" src="test.png">
+<div id="ID1" role="presentation">foo</div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/desc-img-describedby.html b/content/test/data/accessibility/accname/desc-img-describedby.html
new file mode 100644
index 0000000..b52b547e
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-img-describedby.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:name*
+-->
+<!doctype html>
+<html>
+<body>
+<img id="test" aria-describedby="ID1" src="test.png">
+<div id="ID1">foo</div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/desc-img-label-alt-title-expected-blink.txt b/content/test/data/accessibility/accname/desc-img-label-alt-title-expected-blink.txt
new file mode 100644
index 0000000..85d1115e
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-img-label-alt-title-expected-blink.txt
@@ -0,0 +1 @@
+image description='title' descriptionFrom=title
diff --git a/content/test/data/accessibility/accname/desc-img-label-alt-title.html b/content/test/data/accessibility/accname/desc-img-label-alt-title.html
new file mode 100644
index 0000000..ab000a1
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-img-label-alt-title.html
@@ -0,0 +1,9 @@
+<!--
+@BLINK-DENY:name*
+-->
+<!doctype html>
+<html>
+<body>
+<img id="test" src="foo.jpg" aria-label="label" alt="alt" title="title"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/desc-img-one-valid-describedby-expected-blink.txt b/content/test/data/accessibility/accname/desc-img-one-valid-describedby-expected-blink.txt
new file mode 100644
index 0000000..601e4b6
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-img-one-valid-describedby-expected-blink.txt
@@ -0,0 +1 @@
+image description='foo' descriptionFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/desc-img-one-valid-describedby.html b/content/test/data/accessibility/accname/desc-img-one-valid-describedby.html
new file mode 100644
index 0000000..3ef3b90
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-img-one-valid-describedby.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:name*
+-->
+<!doctype html>
+<html>
+<body>
+<img src="foo.jpg" id="test" alt="test" aria-describedby="t1 t2 t3">
+<div id="t2">foo</div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/desc-input-title-and-describedby-expected-blink.txt b/content/test/data/accessibility/accname/desc-input-title-and-describedby-expected-blink.txt
new file mode 100644
index 0000000..cb7709c
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-input-title-and-describedby-expected-blink.txt
@@ -0,0 +1 @@
+textField description='Description' descriptionFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/desc-input-title-and-describedby.html b/content/test/data/accessibility/accname/desc-input-title-and-describedby.html
new file mode 100644
index 0000000..61ac682c
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-input-title-and-describedby.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:name*
+-->
+<!doctype html>
+<html>
+<body>
+<input aria-label="Name" id="test" title="Title" aria-describedby="ID1" type="text">
+<div id="ID1">Description</div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/desc-link-with-label-and-title-expected-blink.txt b/content/test/data/accessibility/accname/desc-link-with-label-and-title-expected-blink.txt
new file mode 100644
index 0000000..4b5a6ad
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-link-with-label-and-title-expected-blink.txt
@@ -0,0 +1 @@
+link description='San Francisco' descriptionFrom=title
diff --git a/content/test/data/accessibility/accname/desc-link-with-label-and-title.html b/content/test/data/accessibility/accname/desc-link-with-label-and-title.html
new file mode 100644
index 0000000..4527e4f
--- /dev/null
+++ b/content/test/data/accessibility/accname/desc-link-with-label-and-title.html
@@ -0,0 +1,9 @@
+<!--
+@BLINK-DENY:name*
+-->
+<!doctype html>
+<html>
+<body>
+<a id="test" href="#" aria-label="California" title="San Francisco">United States</a>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/foo.jpg b/content/test/data/accessibility/accname/foo.jpg
new file mode 100644
index 0000000..7d11a4f
--- /dev/null
+++ b/content/test/data/accessibility/accname/foo.jpg
Binary files differ
diff --git a/content/test/data/accessibility/accname/name-button-label-expected-blink.txt b/content/test/data/accessibility/accname/name-button-label-expected-blink.txt
new file mode 100644
index 0000000..ca873ab
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-button-label-expected-blink.txt
@@ -0,0 +1 @@
+button name='Rich' nameFrom=attribute
diff --git a/content/test/data/accessibility/accname/name-button-label-labelledby-expected-blink.txt b/content/test/data/accessibility/accname/name-button-label-labelledby-expected-blink.txt
new file mode 100644
index 0000000..e2540f9e
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-button-label-labelledby-expected-blink.txt
@@ -0,0 +1 @@
+button name='Rich's button' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-button-label-labelledby.html b/content/test/data/accessibility/accname/name-button-label-labelledby.html
new file mode 100644
index 0000000..66b07d3
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-button-label-labelledby.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="button" aria-label="bar" aria-labelledby="ID1" id="test"/>
+<div id="ID1">Rich's button</div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-button-label.html b/content/test/data/accessibility/accname/name-button-label.html
new file mode 100644
index 0000000..1cf73e5
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-button-label.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+@AURALINUX-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="button" aria-label="Rich" id="test">
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-button-labelledby-expected-blink.txt b/content/test/data/accessibility/accname/name-button-labelledby-expected-blink.txt
new file mode 100644
index 0000000..e2540f9e
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-button-labelledby-expected-blink.txt
@@ -0,0 +1 @@
+button name='Rich's button' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-button-labelledby.html b/content/test/data/accessibility/accname/name-button-labelledby.html
new file mode 100644
index 0000000..c2ae373
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-button-labelledby.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="button" aria-labelledby="ID1" id="test">
+<div id="ID1">Rich's button</div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-button-role-content-only-expected-blink.txt b/content/test/data/accessibility/accname/name-button-role-content-only-expected-blink.txt
new file mode 100644
index 0000000..736e9cc
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-button-role-content-only-expected-blink.txt
@@ -0,0 +1 @@
+button name='foo' nameFrom=contents
diff --git a/content/test/data/accessibility/accname/name-button-role-content-only.html b/content/test/data/accessibility/accname/name-button-role-content-only.html
new file mode 100644
index 0000000..76be8db
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-button-role-content-only.html
@@ -0,0 +1,9 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<div id="test" role="button">foo</div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-button-role-title-only-expected-blink.txt b/content/test/data/accessibility/accname/name-button-role-title-only-expected-blink.txt
new file mode 100644
index 0000000..1a8e0cfb
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-button-role-title-only-expected-blink.txt
@@ -0,0 +1 @@
+button name='Tag' nameFrom=title
diff --git a/content/test/data/accessibility/accname/name-button-role-title-only.html b/content/test/data/accessibility/accname/name-button-role-title-only.html
new file mode 100644
index 0000000..a0b7ac5
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-button-role-title-only.html
@@ -0,0 +1,9 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<div id="test" role="button" title="Tag" style="outline:medium solid black; width:2em; height:1em;"></div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-button-value-expected-blink.txt b/content/test/data/accessibility/accname/name-button-value-expected-blink.txt
new file mode 100644
index 0000000..d1a4be74
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-button-value-expected-blink.txt
@@ -0,0 +1 @@
+button name='foo' nameFrom=value
diff --git a/content/test/data/accessibility/accname/name-button-value.html b/content/test/data/accessibility/accname/name-button-value.html
new file mode 100644
index 0000000..508529d
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-button-value.html
@@ -0,0 +1,9 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="button" id="test" value="foo"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-checkbox-css-after-in-label-expected-blink.txt b/content/test/data/accessibility/accname/name-checkbox-css-after-in-label-expected-blink.txt
new file mode 100644
index 0000000..ee214a6
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-css-after-in-label-expected-blink.txt
@@ -0,0 +1,2 @@
+# BUG: The expected result is 'fancy fruit'
+checkBox name='fancy' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-checkbox-css-after-in-label.html b/content/test/data/accessibility/accname/name-checkbox-css-after-in-label.html
new file mode 100644
index 0000000..83808660
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-css-after-in-label.html
@@ -0,0 +1,12 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<body>
+<style>
+  label:after { content:" fruit"; }
+</style>
+<label for="test">fancy</label>
+<input type="checkbox" id="test"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-checkbox-css-before-in-label-expected-blink.txt b/content/test/data/accessibility/accname/name-checkbox-css-before-in-label-expected-blink.txt
new file mode 100644
index 0000000..ba0ae61
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-css-before-in-label-expected-blink.txt
@@ -0,0 +1,2 @@
+# BUG: The expected result is 'fancy fruit'
+checkBox name='fruit' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-checkbox-css-before-in-label.html b/content/test/data/accessibility/accname/name-checkbox-css-before-in-label.html
new file mode 100644
index 0000000..aa44768
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-css-before-in-label.html
@@ -0,0 +1,13 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<style>
+  label:before { content:"fancy "; }
+</style>
+<label for="test">fruit</label>
+<input type="checkbox" id="test"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-checkbox-input-in-label-expected-blink.txt b/content/test/data/accessibility/accname/name-checkbox-input-in-label-expected-blink.txt
new file mode 100644
index 0000000..5e42251
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-input-in-label-expected-blink.txt
@@ -0,0 +1 @@
+checkBox name='foo David' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-checkbox-input-in-label.html b/content/test/data/accessibility/accname/name-checkbox-input-in-label.html
new file mode 100644
index 0000000..41aa9f2
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-input-in-label.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<label for="test">foo<input type="text" value="David"/></label>
+<input type="checkbox" id="test"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-checkbox-inside-label-with-generated-content-expected-blink.txt b/content/test/data/accessibility/accname/name-checkbox-inside-label-with-generated-content-expected-blink.txt
new file mode 100644
index 0000000..fefe262
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-inside-label-with-generated-content-expected-blink.txt
@@ -0,0 +1,2 @@
+# BUG: The expected result is 'foo baz'
+checkBox name=' bar ' nameFrom=title
diff --git a/content/test/data/accessibility/accname/name-checkbox-inside-label-with-generated-content.html b/content/test/data/accessibility/accname/name-checkbox-inside-label-with-generated-content.html
new file mode 100644
index 0000000..a933bcd2
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-inside-label-with-generated-content.html
@@ -0,0 +1,17 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<style type="text/css">
+  label:before { content: "foo"; }
+  label:after { content: "baz"; }
+</style>
+<form>
+<label for="test">
+<input id="test" type="checkbox" name="test" title=" bar ">
+</label>
+</form>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-checkbox-label-embedded-combobox-expected-blink.txt b/content/test/data/accessibility/accname/name-checkbox-label-embedded-combobox-expected-blink.txt
new file mode 100644
index 0000000..b1aaa7b
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-label-embedded-combobox-expected-blink.txt
@@ -0,0 +1 @@
+checkBox name='Flash the screen 1 times.' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-checkbox-label-embedded-combobox.html b/content/test/data/accessibility/accname/name-checkbox-label-embedded-combobox.html
new file mode 100644
index 0000000..7f49e480
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-label-embedded-combobox.html
@@ -0,0 +1,20 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="checkbox" id="test" />
+<label for="test">Flash the screen
+  <div role="combobox">
+    <div role="textbox"></div>
+    <ul role="listbox" style="list-style-type: none;">
+      <li role="option" aria-selected="true">1</li>
+      <li role="option">2</li>
+      <li role="option">3</li>
+    </ul>
+  </div>
+  times.
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-checkbox-label-embedded-listbox-expected-blink.txt b/content/test/data/accessibility/accname/name-checkbox-label-embedded-listbox-expected-blink.txt
new file mode 100644
index 0000000..b1aaa7b
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-label-embedded-listbox-expected-blink.txt
@@ -0,0 +1 @@
+checkBox name='Flash the screen 1 times.' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-checkbox-label-embedded-listbox.html b/content/test/data/accessibility/accname/name-checkbox-label-embedded-listbox.html
new file mode 100644
index 0000000..85189f7
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-label-embedded-listbox.html
@@ -0,0 +1,17 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="checkbox" id="test" />
+<label for="test">Flash the screen
+  <ul role="listbox" style="list-style-type: none;">
+    <li role="option" aria-selected="true">1</li>
+    <li role="option">2</li>
+    <li role="option">3</li>
+  </ul>
+  times.
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-checkbox-label-embedded-menu-expected-blink.txt b/content/test/data/accessibility/accname/name-checkbox-label-embedded-menu-expected-blink.txt
new file mode 100644
index 0000000..99e1051f
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-label-embedded-menu-expected-blink.txt
@@ -0,0 +1 @@
+checkBox name='Flash the screen times.' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-checkbox-label-embedded-menu.html b/content/test/data/accessibility/accname/name-checkbox-label-embedded-menu.html
new file mode 100644
index 0000000..33e4471f
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-label-embedded-menu.html
@@ -0,0 +1,17 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="checkbox" id="test" />
+<label for="test">Flash the screen
+  <span role="menu">
+    <span role="menuitem" aria-selected="true">1</span>
+    <span role="menuitem" hidden>2</span>
+    <span role="menuitem" hidden>3</span>
+  </span>
+  times.
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-checkbox-label-embedded-select-expected-blink.txt b/content/test/data/accessibility/accname/name-checkbox-label-embedded-select-expected-blink.txt
new file mode 100644
index 0000000..b1aaa7b
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-label-embedded-select-expected-blink.txt
@@ -0,0 +1 @@
+checkBox name='Flash the screen 1 times.' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-checkbox-label-embedded-select.html b/content/test/data/accessibility/accname/name-checkbox-label-embedded-select.html
new file mode 100644
index 0000000..1fbcfc2
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-label-embedded-select.html
@@ -0,0 +1,17 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="checkbox" id="test" />
+<label for="test">Flash the screen
+  <select size="1">
+    <option selected="selected">1</option>
+    <option>2</option>
+    <option>3</option>
+  </select>
+  times.
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-checkbox-label-embedded-slider-expected-blink.txt b/content/test/data/accessibility/accname/name-checkbox-label-embedded-slider-expected-blink.txt
new file mode 100644
index 0000000..85a37615
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-label-embedded-slider-expected-blink.txt
@@ -0,0 +1 @@
+checkBox name='foo 5 baz' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-checkbox-label-embedded-slider.html b/content/test/data/accessibility/accname/name-checkbox-label-embedded-slider.html
new file mode 100644
index 0000000..de82702
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-label-embedded-slider.html
@@ -0,0 +1,19 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="checkbox" id="test" />
+<label for="test">foo
+<input role="slider"
+       type="range"
+       value="5"
+       min="1"
+       max="10"
+       aria-valuenow="5"
+       aria-valuemin="1"
+       aria-valuemax="10"> baz
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-checkbox-label-embedded-spinbutton-expected-blink.txt b/content/test/data/accessibility/accname/name-checkbox-label-embedded-spinbutton-expected-blink.txt
new file mode 100644
index 0000000..85a37615
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-label-embedded-spinbutton-expected-blink.txt
@@ -0,0 +1 @@
+checkBox name='foo 5 baz' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-checkbox-label-embedded-spinbutton.html b/content/test/data/accessibility/accname/name-checkbox-label-embedded-spinbutton.html
new file mode 100644
index 0000000..66c28e9
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-label-embedded-spinbutton.html
@@ -0,0 +1,21 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="checkbox" id="test" />
+<label for="test">
+  foo
+  <input role="spinbutton"
+	 type="number"
+	 value="5"
+	 min="1"
+	 max="10"
+	 aria-valuenow="5"
+	 aria-valuemin="1"
+	 aria-valuemax="10">
+  baz
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-checkbox-label-embedded-textbox-expected-blink.txt b/content/test/data/accessibility/accname/name-checkbox-label-embedded-textbox-expected-blink.txt
new file mode 100644
index 0000000..b1aaa7b
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-label-embedded-textbox-expected-blink.txt
@@ -0,0 +1 @@
+checkBox name='Flash the screen 1 times.' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-checkbox-label-embedded-textbox.html b/content/test/data/accessibility/accname/name-checkbox-label-embedded-textbox.html
new file mode 100644
index 0000000..dc9f65c
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-label-embedded-textbox.html
@@ -0,0 +1,13 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="checkbox" id="test" />
+<label for="test">Flash the screen
+  <div role="textbox" contenteditable>1</div>
+  times.
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-checkbox-label-expected-blink.txt b/content/test/data/accessibility/accname/name-checkbox-label-expected-blink.txt
new file mode 100644
index 0000000..491d6d2f
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-label-expected-blink.txt
@@ -0,0 +1 @@
+checkBox name='foo' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-checkbox-label-multiple-label-alternative-expected-blink.txt b/content/test/data/accessibility/accname/name-checkbox-label-multiple-label-alternative-expected-blink.txt
new file mode 100644
index 0000000..b12d918
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-label-multiple-label-alternative-expected-blink.txt
@@ -0,0 +1 @@
+checkBox name='a test This is' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-checkbox-label-multiple-label-alternative.html b/content/test/data/accessibility/accname/name-checkbox-label-multiple-label-alternative.html
new file mode 100644
index 0000000..4514611
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-label-multiple-label-alternative.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<label for="test">a test</label>
+<label>This <input type="checkbox" id="test" /> is</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-checkbox-label-multiple-label-expected-blink.txt b/content/test/data/accessibility/accname/name-checkbox-label-multiple-label-expected-blink.txt
new file mode 100644
index 0000000..4dd6e76
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-label-multiple-label-expected-blink.txt
@@ -0,0 +1 @@
+checkBox name='This is a test' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-checkbox-label-multiple-label.html b/content/test/data/accessibility/accname/name-checkbox-label-multiple-label.html
new file mode 100644
index 0000000..51da066
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-label-multiple-label.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<label>This <input type="checkbox" id="test" /> is</label>
+<label for="test">a test</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-checkbox-label-with-input-expected-blink.txt b/content/test/data/accessibility/accname/name-checkbox-label-with-input-expected-blink.txt
new file mode 100644
index 0000000..8b60a0a
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-label-with-input-expected-blink.txt
@@ -0,0 +1 @@
+checkBox name='foo bar baz' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-checkbox-label-with-input.html b/content/test/data/accessibility/accname/name-checkbox-label-with-input.html
new file mode 100644
index 0000000..ae1bbbbc
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-label-with-input.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="checkbox" id="test">
+<label for="test">foo<input type="text" value="bar">baz</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-checkbox-label.html b/content/test/data/accessibility/accname/name-checkbox-label.html
new file mode 100644
index 0000000..6441eaf
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-label.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="checkbox" id="test">
+<label for="test">foo</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-checkbox-spinbutton-valuenow-in-label-expected-blink.txt b/content/test/data/accessibility/accname/name-checkbox-spinbutton-valuenow-in-label-expected-blink.txt
new file mode 100644
index 0000000..b60d084a
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-spinbutton-valuenow-in-label-expected-blink.txt
@@ -0,0 +1 @@
+checkBox name='silly 4' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-checkbox-spinbutton-valuenow-in-label.html b/content/test/data/accessibility/accname/name-checkbox-spinbutton-valuenow-in-label.html
new file mode 100644
index 0000000..d5794a7
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-spinbutton-valuenow-in-label.html
@@ -0,0 +1,13 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<label for="test">silly
+<div role="spinbutton" aria-valuemin="1" aria-valuemax="7" aria-valuenow="4">
+</div>
+</label>
+<input type="checkbox" id="test"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-checkbox-title-expected-blink.txt b/content/test/data/accessibility/accname/name-checkbox-title-expected-blink.txt
new file mode 100644
index 0000000..e6d04c8
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-title-expected-blink.txt
@@ -0,0 +1 @@
+checkBox name='foo' nameFrom=title
diff --git a/content/test/data/accessibility/accname/name-checkbox-title.html b/content/test/data/accessibility/accname/name-checkbox-title.html
new file mode 100644
index 0000000..08ca8fb
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-checkbox-title.html
@@ -0,0 +1,9 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="checkbox" id="test" title="foo" />
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-combobox-focusable-alternative-expected-blink.txt b/content/test/data/accessibility/accname/name-combobox-focusable-alternative-expected-blink.txt
new file mode 100644
index 0000000..4d066c7
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-combobox-focusable-alternative-expected-blink.txt
@@ -0,0 +1 @@
+textFieldWithComboBox name='Choose your language' nameFrom=title
diff --git a/content/test/data/accessibility/accname/name-combobox-focusable-alternative.html b/content/test/data/accessibility/accname/name-combobox-focusable-alternative.html
new file mode 100644
index 0000000..67d8dd1
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-combobox-focusable-alternative.html
@@ -0,0 +1,9 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input id="test" role="combobox" type="text" title="Choose your language" value="English">
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-combobox-focusable-expected-android.txt b/content/test/data/accessibility/accname/name-combobox-focusable-expected-android.txt
new file mode 100644
index 0000000..c4d799a
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-combobox-focusable-expected-android.txt
@@ -0,0 +1 @@
+android.widget.Spinner name='Choose your language.'
diff --git a/content/test/data/accessibility/accname/name-combobox-focusable-expected-auralinux.txt b/content/test/data/accessibility/accname/name-combobox-focusable-expected-auralinux.txt
new file mode 100644
index 0000000..3b8270ed
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-combobox-focusable-expected-auralinux.txt
@@ -0,0 +1 @@
+[combo box] name='Choose your language.'
diff --git a/content/test/data/accessibility/accname/name-combobox-focusable-expected-blink.txt b/content/test/data/accessibility/accname/name-combobox-focusable-expected-blink.txt
new file mode 100644
index 0000000..4e1ae7cc
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-combobox-focusable-expected-blink.txt
@@ -0,0 +1 @@
+comboBoxMenuButton name='Choose your language.' nameFrom=title
diff --git a/content/test/data/accessibility/accname/name-combobox-focusable-expected-mac.txt b/content/test/data/accessibility/accname/name-combobox-focusable-expected-mac.txt
new file mode 100644
index 0000000..b3f35806
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-combobox-focusable-expected-mac.txt
@@ -0,0 +1 @@
+AXComboBox AXDescription='Choose your language.'
diff --git a/content/test/data/accessibility/accname/name-combobox-focusable-expected-win.txt b/content/test/data/accessibility/accname/name-combobox-focusable-expected-win.txt
new file mode 100644
index 0000000..b20fec8
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-combobox-focusable-expected-win.txt
@@ -0,0 +1 @@
+ROLE_SYSTEM_COMBOBOX name='Choose your language.' FOCUSABLE HASPOPUP
diff --git a/content/test/data/accessibility/accname/name-combobox-focusable.html b/content/test/data/accessibility/accname/name-combobox-focusable.html
new file mode 100644
index 0000000..eb61f2b
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-combobox-focusable.html
@@ -0,0 +1,16 @@
+<!--
+@BLINK-DENY:descri*
+@ANDROID-DENY:descri*
+@AURALINUX-DENY:descri*
+@MAC-DENY:AXHelp*
+@MAC-DENY:AXValue*
+@WIN-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<div id="test" role="combobox" tabindex="0" title="Choose your language.">
+<span> English </span>
+</div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-div-content-only-expected-android.txt b/content/test/data/accessibility/accname/name-div-content-only-expected-android.txt
new file mode 100644
index 0000000..200af8b82
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-div-content-only-expected-android.txt
@@ -0,0 +1 @@
+android.view.View name='Div with text'
diff --git a/content/test/data/accessibility/accname/name-div-content-only-expected-auralinux.txt b/content/test/data/accessibility/accname/name-div-content-only-expected-auralinux.txt
new file mode 100644
index 0000000..399727c
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-div-content-only-expected-auralinux.txt
@@ -0,0 +1 @@
+[section]
diff --git a/content/test/data/accessibility/accname/name-div-content-only-expected-blink.txt b/content/test/data/accessibility/accname/name-div-content-only-expected-blink.txt
new file mode 100644
index 0000000..e23ea37
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-div-content-only-expected-blink.txt
@@ -0,0 +1 @@
+genericContainer
diff --git a/content/test/data/accessibility/accname/name-div-content-only-expected-mac.txt b/content/test/data/accessibility/accname/name-div-content-only-expected-mac.txt
new file mode 100644
index 0000000..7a0cd62
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-div-content-only-expected-mac.txt
@@ -0,0 +1 @@
+AXGroup
diff --git a/content/test/data/accessibility/accname/name-div-content-only-expected-win.txt b/content/test/data/accessibility/accname/name-div-content-only-expected-win.txt
new file mode 100644
index 0000000..2980cc5
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-div-content-only-expected-win.txt
@@ -0,0 +1 @@
+IA2_ROLE_SECTION
diff --git a/content/test/data/accessibility/accname/name-div-content-only.html b/content/test/data/accessibility/accname/name-div-content-only.html
new file mode 100644
index 0000000..6aa80bf
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-div-content-only.html
@@ -0,0 +1,14 @@
+<!--
+@BLINK-DENY:descri*
+@ANDROID-DENY:descri*
+@AURALINUX-DENY:descri*
+@MAC-DENY:AXHelp*
+@MAC-DENY:AXValue*
+@WIN-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<div id="test">Div with text</div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-div-label-expected-blink.txt b/content/test/data/accessibility/accname/name-div-label-expected-blink.txt
new file mode 100644
index 0000000..a7ebc52
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-div-label-expected-blink.txt
@@ -0,0 +1 @@
+genericContainer name='Tag' nameFrom=attribute
diff --git a/content/test/data/accessibility/accname/name-div-label-labelledby-expected-blink.txt b/content/test/data/accessibility/accname/name-div-label-labelledby-expected-blink.txt
new file mode 100644
index 0000000..8893d70
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-div-label-labelledby-expected-blink.txt
@@ -0,0 +1 @@
+genericContainer name='bar' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-div-label-labelledby.html b/content/test/data/accessibility/accname/name-div-label-labelledby.html
new file mode 100644
index 0000000..58a3359
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-div-label-labelledby.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<div id="test" aria-labelledby="ID1" aria-label="Tag">foo</div>
+<span id="ID1">bar</span>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-div-label.html b/content/test/data/accessibility/accname/name-div-label.html
new file mode 100644
index 0000000..4efbb93
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-div-label.html
@@ -0,0 +1,9 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<div id="test" aria-label="Tag">foo</div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-div-labelledby-expected-blink.txt b/content/test/data/accessibility/accname/name-div-labelledby-expected-blink.txt
new file mode 100644
index 0000000..8893d70
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-div-labelledby-expected-blink.txt
@@ -0,0 +1 @@
+genericContainer name='bar' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-div-labelledby.html b/content/test/data/accessibility/accname/name-div-labelledby.html
new file mode 100644
index 0000000..824a7ea
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-div-labelledby.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<div id="test" aria-labelledby="ID1">foo</div>
+<span id="ID1">bar</span>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-div-multiple-sources-expected-blink.txt b/content/test/data/accessibility/accname/name-div-multiple-sources-expected-blink.txt
new file mode 100644
index 0000000..76fa8098
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-div-multiple-sources-expected-blink.txt
@@ -0,0 +1 @@
+genericContainer name='bar baz' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-div-multiple-sources.html b/content/test/data/accessibility/accname/name-div-multiple-sources.html
new file mode 100644
index 0000000..ff945ffa
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-div-multiple-sources.html
@@ -0,0 +1,11 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<div id="test" aria-labelledby="ID0 ID1" aria-label="Tag">foo</div>
+<span id="ID0">bar</span>
+<span id="ID1">baz</span>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-file-css-after-in-label-expected-blink.txt b/content/test/data/accessibility/accname/name-file-css-after-in-label-expected-blink.txt
new file mode 100644
index 0000000..8e319ea
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-css-after-in-label-expected-blink.txt
@@ -0,0 +1,2 @@
+# BUG: The expected result is 'fancy fruit'
+button name='fancy' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-file-css-after-in-label.html b/content/test/data/accessibility/accname/name-file-css-after-in-label.html
new file mode 100644
index 0000000..5d20fb9e
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-css-after-in-label.html
@@ -0,0 +1,12 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<body>
+<style>
+  label:after { content:" fruit"; }
+</style>
+<label for="test">fancy</label>
+<input type="file" id="test"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-file-css-before-in-label-expected-blink.txt b/content/test/data/accessibility/accname/name-file-css-before-in-label-expected-blink.txt
new file mode 100644
index 0000000..9703459
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-css-before-in-label-expected-blink.txt
@@ -0,0 +1,2 @@
+# BUG: The expected result is 'fancy fruit'
+button name='fruit' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-file-css-before-in-label.html b/content/test/data/accessibility/accname/name-file-css-before-in-label.html
new file mode 100644
index 0000000..3e4fcdd
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-css-before-in-label.html
@@ -0,0 +1,13 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<style>
+  label:before { content:"fancy "; }
+</style>
+<label for="test">fruit</label>
+<input type="file" id="test"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-file-in-label-expected-blink.txt b/content/test/data/accessibility/accname/name-file-in-label-expected-blink.txt
new file mode 100644
index 0000000..bf0d4beb
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-in-label-expected-blink.txt
@@ -0,0 +1 @@
+button name='foo David' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-file-in-label.html b/content/test/data/accessibility/accname/name-file-in-label.html
new file mode 100644
index 0000000..46b4357
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-in-label.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<label for="test">foo<input type="text" value="David"/></label>
+<input type="file" id="test"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-file-label-embedded-combobox-expected-blink.txt b/content/test/data/accessibility/accname/name-file-label-embedded-combobox-expected-blink.txt
new file mode 100644
index 0000000..774ae30
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-label-embedded-combobox-expected-blink.txt
@@ -0,0 +1 @@
+button name='Flash the screen 1 times.' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-file-label-embedded-combobox.html b/content/test/data/accessibility/accname/name-file-label-embedded-combobox.html
new file mode 100644
index 0000000..cff8c93
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-label-embedded-combobox.html
@@ -0,0 +1,20 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="file" id="test" />
+<label for="test">Flash the screen
+  <div role="combobox">
+    <div role="textbox"></div>
+    <ul role="listbox" style="list-style-type: none;">
+      <li role="option" aria-selected="true">1</li>
+      <li role="option">2</li>
+      <li role="option">3</li>
+    </ul>
+  </div>
+  times.
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-file-label-embedded-menu-expected-blink.txt b/content/test/data/accessibility/accname/name-file-label-embedded-menu-expected-blink.txt
new file mode 100644
index 0000000..ebfa5ae0
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-label-embedded-menu-expected-blink.txt
@@ -0,0 +1 @@
+button name='Flash the screen times.' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-file-label-embedded-menu.html b/content/test/data/accessibility/accname/name-file-label-embedded-menu.html
new file mode 100644
index 0000000..2c645a72
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-label-embedded-menu.html
@@ -0,0 +1,17 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="file" id="test" />
+<label for="test">Flash the screen
+  <span role="menu">
+    <span role="menuitem" aria-selected="true">1</span>
+    <span role="menuitem" hidden>2</span>
+    <span role="menuitem" hidden>3</span>
+  </span>
+  times.
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-file-label-embedded-select-expected-blink.txt b/content/test/data/accessibility/accname/name-file-label-embedded-select-expected-blink.txt
new file mode 100644
index 0000000..774ae30
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-label-embedded-select-expected-blink.txt
@@ -0,0 +1 @@
+button name='Flash the screen 1 times.' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-file-label-embedded-select.html b/content/test/data/accessibility/accname/name-file-label-embedded-select.html
new file mode 100644
index 0000000..0202be9
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-label-embedded-select.html
@@ -0,0 +1,17 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="file" id="test" />
+<label for="test">Flash the screen
+  <select size="1">
+    <option selected="selected">1</option>
+    <option>2</option>
+    <option>3</option>
+  </select>
+  times.
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-file-label-embedded-slider-expected-blink.txt b/content/test/data/accessibility/accname/name-file-label-embedded-slider-expected-blink.txt
new file mode 100644
index 0000000..845b73e
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-label-embedded-slider-expected-blink.txt
@@ -0,0 +1 @@
+button name='foo 5 baz' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-file-label-embedded-slider.html b/content/test/data/accessibility/accname/name-file-label-embedded-slider.html
new file mode 100644
index 0000000..e840e85
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-label-embedded-slider.html
@@ -0,0 +1,19 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="file" id="test" />
+<label for="test">foo
+<input role="slider"
+       type="range"
+       value="5"
+       min="1"
+       max="10"
+       aria-valuenow="5"
+       aria-valuemin="1"
+       aria-valuemax="10"> baz
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-file-label-embedded-spinbutton-expected-blink.txt b/content/test/data/accessibility/accname/name-file-label-embedded-spinbutton-expected-blink.txt
new file mode 100644
index 0000000..845b73e
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-label-embedded-spinbutton-expected-blink.txt
@@ -0,0 +1 @@
+button name='foo 5 baz' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-file-label-embedded-spinbutton.html b/content/test/data/accessibility/accname/name-file-label-embedded-spinbutton.html
new file mode 100644
index 0000000..c66efcc8
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-label-embedded-spinbutton.html
@@ -0,0 +1,21 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="file" id="test" />
+<label for="test">
+  foo
+  <input role="spinbutton"
+	 type="number"
+	 value="5"
+	 min="1"
+	 max="10"
+	 aria-valuenow="5"
+	 aria-valuemin="1"
+	 aria-valuemax="10">
+  baz
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-file-label-expected-blink.txt b/content/test/data/accessibility/accname/name-file-label-expected-blink.txt
new file mode 100644
index 0000000..357abc73
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-label-expected-blink.txt
@@ -0,0 +1 @@
+button name='foo' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-file-label-inline-block-elements-expected-blink.txt b/content/test/data/accessibility/accname/name-file-label-inline-block-elements-expected-blink.txt
new file mode 100644
index 0000000..50322dfa
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-label-inline-block-elements-expected-blink.txt
@@ -0,0 +1 @@
+button name='What is your name?' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-file-label-inline-block-elements.html b/content/test/data/accessibility/accname/name-file-label-inline-block-elements.html
new file mode 100644
index 0000000..a611720
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-label-inline-block-elements.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="file" id="test" />
+<label for="test">W<i>h<b>a</b></i>t<br>is<div>your<div>name<b>?</b></div></div></label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-file-label-inline-block-styles-expected-blink.txt b/content/test/data/accessibility/accname/name-file-label-inline-block-styles-expected-blink.txt
new file mode 100644
index 0000000..5e16bce62
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-label-inline-block-styles-expected-blink.txt
@@ -0,0 +1,2 @@
+# BUG: The expected result is 'This is a test'
+textField name='is a test' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-file-label-inline-block-styles.html b/content/test/data/accessibility/accname/name-file-label-inline-block-styles.html
new file mode 100644
index 0000000..06bf78e
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-label-inline-block-styles.html
@@ -0,0 +1,14 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<style>
+  label:before { content: "This"; display: block; }
+  label:after { content: "."; }
+</style>
+<label for="test">is a test</label>
+<input type="text" id="test"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-file-label-inline-hidden-elements-expected-blink.txt b/content/test/data/accessibility/accname/name-file-label-inline-hidden-elements-expected-blink.txt
new file mode 100644
index 0000000..1582d3e0
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-label-inline-hidden-elements-expected-blink.txt
@@ -0,0 +1,2 @@
+# BUG: The expected result is: '2 4 6 8 10'
+button name='2468 9 10' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-file-label-inline-hidden-elements.html b/content/test/data/accessibility/accname/name-file-label-inline-hidden-elements.html
new file mode 100644
index 0000000..882a312b
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-label-inline-hidden-elements.html
@@ -0,0 +1,19 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<style>
+  .hidden { display: none; }
+</style>
+<input type="file" id="test" />
+<label for="test">
+  <span class="hidden">1</span><span>2</span>
+  <span style="visibility: hidden;">3</span><span>4</span>
+  <span hidden>5</span><span>6</span>
+  <span aria-hidden="true">7</span><span>8</span>
+  <span aria-hidden="false" class="hidden">9</span><span>10</span>
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-file-label-owned-combobox-expected-blink.txt b/content/test/data/accessibility/accname/name-file-label-owned-combobox-expected-blink.txt
new file mode 100644
index 0000000..774ae30
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-label-owned-combobox-expected-blink.txt
@@ -0,0 +1 @@
+button name='Flash the screen 1 times.' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-file-label-owned-combobox-owned-listbox-expected-blink.txt b/content/test/data/accessibility/accname/name-file-label-owned-combobox-owned-listbox-expected-blink.txt
new file mode 100644
index 0000000..ec093e07
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-label-owned-combobox-owned-listbox-expected-blink.txt
@@ -0,0 +1 @@
+button name='Flash the screen 2 times.' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-file-label-owned-combobox-owned-listbox.html b/content/test/data/accessibility/accname/name-file-label-owned-combobox-owned-listbox.html
new file mode 100644
index 0000000..252a686d
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-label-owned-combobox-owned-listbox.html
@@ -0,0 +1,22 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="file" id="test" />
+<label for="test">Flash <span aria-owns="id1">the screen</span> times.</label>
+<div>
+  <div id="id1" role="combobox" aria-owns="id2">
+    <div role="textbox"></div>
+  </div>
+</div>
+<div>
+  <ul id="id2" role="listbox" style="list-style-type: none;">
+    <li role="option" >1 </li>
+    <li role="option" aria-selected="true">2 </li>
+    <li role="option">3 </li>
+  </ul>
+</div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-file-label-owned-combobox.html b/content/test/data/accessibility/accname/name-file-label-owned-combobox.html
new file mode 100644
index 0000000..3ac4117
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-label-owned-combobox.html
@@ -0,0 +1,20 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="file" id="test" />
+<label for="test">Flash <span aria-owns="id1">the screen</span> times.</label>
+<div id="id1">
+  <div role="combobox">
+    <div role="textbox"></div>
+    <ul role="listbox" style="list-style-type: none;">
+      <li role="option" aria-selected="true">1 </li>
+      <li role="option">2 </li>
+      <li role="option">3 </li>
+    </ul>
+  </div>
+</div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-file-label-with-input-expected-blink.txt b/content/test/data/accessibility/accname/name-file-label-with-input-expected-blink.txt
new file mode 100644
index 0000000..2c85b8b
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-label-with-input-expected-blink.txt
@@ -0,0 +1 @@
+button name='foo bar baz' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-file-label-with-input.html b/content/test/data/accessibility/accname/name-file-label-with-input.html
new file mode 100644
index 0000000..803fd0f
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-label-with-input.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="file" id="test">
+<label for="test">foo <input type="text" value="bar"> baz</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-file-label.html b/content/test/data/accessibility/accname/name-file-label.html
new file mode 100644
index 0000000..e3638d8
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-label.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="file" id="test">
+<label for="test">foo</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-file-spinbutton-valuenow-in-label-expected-blink.txt b/content/test/data/accessibility/accname/name-file-spinbutton-valuenow-in-label-expected-blink.txt
new file mode 100644
index 0000000..782c02e
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-spinbutton-valuenow-in-label-expected-blink.txt
@@ -0,0 +1 @@
+button name='silly 4' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-file-spinbutton-valuenow-in-label.html b/content/test/data/accessibility/accname/name-file-spinbutton-valuenow-in-label.html
new file mode 100644
index 0000000..d26c0165
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-spinbutton-valuenow-in-label.html
@@ -0,0 +1,11 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<label for="test">silly
+<div role="spinbutton" aria-valuemin="1" aria-valuemax="7" aria-valuenow="4"></div>
+<input type="file" id="test"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-file-title-expected-blink.txt b/content/test/data/accessibility/accname/name-file-title-expected-blink.txt
new file mode 100644
index 0000000..a11fb43a
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-title-expected-blink.txt
@@ -0,0 +1,2 @@
+# BUG? The expected result is 'foo'
+button name='No file chosen, Choose File' nameFrom=value
diff --git a/content/test/data/accessibility/accname/name-file-title.html b/content/test/data/accessibility/accname/name-file-title.html
new file mode 100644
index 0000000..0846864
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-file-title.html
@@ -0,0 +1,9 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="file" id="test" title="foo" />
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-from-content-expected-blink.txt b/content/test/data/accessibility/accname/name-from-content-expected-blink.txt
new file mode 100644
index 0000000..d761f61
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-from-content-expected-blink.txt
@@ -0,0 +1 @@
+link name='My name is Eli the weird. (QED) Where are my marbles?' nameFrom=contents
diff --git a/content/test/data/accessibility/accname/name-from-content-of-label-expected-blink.txt b/content/test/data/accessibility/accname/name-from-content-of-label-expected-blink.txt
new file mode 100644
index 0000000..e99812ac
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-from-content-of-label-expected-blink.txt
@@ -0,0 +1 @@
+textField name='My name is Eli the weird. (QED) Where are my marbles?' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-from-content-of-label.html b/content/test/data/accessibility/accname/name-from-content-of-label.html
new file mode 100644
index 0000000..bcb1fba8
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-from-content-of-label.html
@@ -0,0 +1,31 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<style>
+  .hidden { display: none; }
+</style>
+<input type="text" id="test" />
+<label for="test" id="label">
+  <span aria-hidden="true"><i> Hello, </i></span>
+  <span>My</span> name is
+  <div><img src="file.jpg" title="Bryan" alt="" role="presentation" /></div>
+  <span role="presentation" aria-label="Eli">
+    <span aria-label="Garaventa">Zambino</span>
+  </span>
+  <span>the weird.</span>
+  (QED)
+  <span class="hidden"><i><b>and don't you forget it.</b></i></span>
+  <table>
+    <tr>
+      <td>Where</td>
+      <td style="visibility:hidden;"><div>in</div></td>
+      <td><div style="display:none;">the world</div></td>
+      <td>are my marbles?</td>
+    </tr>
+  </table>
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-from-content-of-labelledby-element-expected-blink.txt b/content/test/data/accessibility/accname/name-from-content-of-labelledby-element-expected-blink.txt
new file mode 100644
index 0000000..e99812ac
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-from-content-of-labelledby-element-expected-blink.txt
@@ -0,0 +1 @@
+textField name='My name is Eli the weird. (QED) Where are my marbles?' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-from-content-of-labelledby-element.html b/content/test/data/accessibility/accname/name-from-content-of-labelledby-element.html
new file mode 100644
index 0000000..3790514
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-from-content-of-labelledby-element.html
@@ -0,0 +1,31 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<style>
+  .hidden { display: none; }
+</style>
+<input id="test" type="text" aria-labelledby="lblId" />
+<div id="lblId" >
+  <span aria-hidden="true"><i> Hello, </i></span>
+  <span>My</span> name is
+  <div><img src="file.jpg" title="Bryan" alt="" role="presentation" /></div>
+  <span role="presentation" aria-label="Eli">
+    <span aria-label="Garaventa">Zambino</span>
+  </span>
+  <span>the weird.</span>
+  (QED)
+  <span class="hidden"><i><b>and don't you forget it.</b></i></span>
+  <table>
+    <tr>
+      <td>Where</td>
+      <td style="visibility:hidden;"><div>in</div></td>
+      <td><div style="display:none;">the world</div></td>
+      <td>are my marbles?</td>
+    </tr>
+  </table>
+</div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-from-content-of-labelledby-elements-one-of-which-is-hidden-expected-blink.txt b/content/test/data/accessibility/accname/name-from-content-of-labelledby-elements-one-of-which-is-hidden-expected-blink.txt
new file mode 100644
index 0000000..3fa3ffc2
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-from-content-of-labelledby-elements-one-of-which-is-hidden-expected-blink.txt
@@ -0,0 +1 @@
+textField name='Important stuff' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-from-content-of-labelledby-elements-one-of-which-is-hidden.html b/content/test/data/accessibility/accname/name-from-content-of-labelledby-elements-one-of-which-is-hidden.html
new file mode 100644
index 0000000..6e65e0ab
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-from-content-of-labelledby-elements-one-of-which-is-hidden.html
@@ -0,0 +1,38 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<style>
+  .hidden { display: none; }
+</style>
+<input id="test" type="text" aria-labelledby="lbl1 lbl2" aria-describedby="descId" />
+<span>
+  <span aria-hidden="true" id="lbl1">Important</span>
+  <span class="hidden">
+    <span aria-hidden="true" id="lbl2">stuff</span>
+  </span>
+</span>
+<div class="hidden">
+  <div id="descId">
+    <span aria-hidden="true"><i> Hello, </i></span>
+    <span>My</span> name is
+    <div><img src="file.jpg" title="Bryan" alt="" role="presentation" /></div>
+    <span role="presentation" aria-label="Eli">
+      <span aria-label="Garaventa">Zambino</span>
+    </span>
+    <span>the weird.</span>
+    (QED)
+    <span class="hidden"><i><b>and don't you forget it.</b></i></span>
+    <table>
+      <tr>
+        <td>Where</td>
+        <td style="visibility:hidden;"><div>in</div></td>
+        <td><div style="display:none;">the world</div></td>
+        <td>are my marbles?</td>
+      </tr>
+    </table>
+  </div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-from-content.html b/content/test/data/accessibility/accname/name-from-content.html
new file mode 100644
index 0000000..65007d0
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-from-content.html
@@ -0,0 +1,30 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<style>
+  .hidden { display: none; }
+</style>
+<div id="test" role="link" tabindex="0">
+  <span aria-hidden="true"><i> Hello, </i></span>
+  <span>My</span> name is
+  <div><img src="file.jpg" title="Bryan" alt="" role="presentation" /></div>
+  <span role="presentation" aria-label="Eli">
+    <span aria-label="Garaventa">Zambino</span>
+  </span>
+  <span>the weird.</span>
+  (QED)
+  <span class="hidden"><i><b>and don't you forget it.</b></i></span>
+  <table>
+    <tr>
+      <td>Where</td>
+      <td style="visibility:hidden;"><div>in</div></td>
+      <td><div style="display:none;">the world</div></td>
+      <td>are my marbles?</td>
+    </tr>
+  </table>
+</div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-heading-combobox-focusable-alternative-expected-blink.txt b/content/test/data/accessibility/accname/name-heading-combobox-focusable-alternative-expected-blink.txt
new file mode 100644
index 0000000..12d551f
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-heading-combobox-focusable-alternative-expected-blink.txt
@@ -0,0 +1 @@
+heading name='Country of origin: United States' nameFrom=contents
diff --git a/content/test/data/accessibility/accname/name-heading-combobox-focusable-alternative.html b/content/test/data/accessibility/accname/name-heading-combobox-focusable-alternative.html
new file mode 100644
index 0000000..c478460
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-heading-combobox-focusable-alternative.html
@@ -0,0 +1,11 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<h2 id="test">Country of origin:
+<input role="combobox" type="text" title="Choose your country." value="United States">
+</h2>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-image-css-after-in-label-expected-blink.txt b/content/test/data/accessibility/accname/name-image-css-after-in-label-expected-blink.txt
new file mode 100644
index 0000000..8e319ea
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-image-css-after-in-label-expected-blink.txt
@@ -0,0 +1,2 @@
+# BUG: The expected result is 'fancy fruit'
+button name='fancy' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-image-css-after-in-label.html b/content/test/data/accessibility/accname/name-image-css-after-in-label.html
new file mode 100644
index 0000000..d207055
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-image-css-after-in-label.html
@@ -0,0 +1,12 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<body>
+<style>
+  label:after { content:" fruit"; }
+</style>
+<label for="test">fancy</label>
+<input type="image" src="foo.jpg" id="test"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-image-css-before-in-label-expected-blink.txt b/content/test/data/accessibility/accname/name-image-css-before-in-label-expected-blink.txt
new file mode 100644
index 0000000..9703459
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-image-css-before-in-label-expected-blink.txt
@@ -0,0 +1,2 @@
+# BUG: The expected result is 'fancy fruit'
+button name='fruit' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-image-css-before-in-label.html b/content/test/data/accessibility/accname/name-image-css-before-in-label.html
new file mode 100644
index 0000000..d0112612
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-image-css-before-in-label.html
@@ -0,0 +1,13 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<style>
+  label:before { content:"fancy "; }
+</style>
+<label for="test">fruit</label>
+<input type="image" src="foo.jpg" id="test"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-image-input-alt-expected-blink.txt b/content/test/data/accessibility/accname/name-image-input-alt-expected-blink.txt
new file mode 100644
index 0000000..be0ad16
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-image-input-alt-expected-blink.txt
@@ -0,0 +1 @@
+button name='foo' nameFrom=attribute
diff --git a/content/test/data/accessibility/accname/name-image-input-alt.html b/content/test/data/accessibility/accname/name-image-input-alt.html
new file mode 100644
index 0000000..ccb1f193
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-image-input-alt.html
@@ -0,0 +1,9 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input src="baz.html" type="image" id="test" alt="foo"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-image-input-inside-label-with-generated-content-expected-blink.txt b/content/test/data/accessibility/accname/name-image-input-inside-label-with-generated-content-expected-blink.txt
new file mode 100644
index 0000000..c0350ec
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-image-input-inside-label-with-generated-content-expected-blink.txt
@@ -0,0 +1,2 @@
+# BUG: The expected result is 'foo baz'
+button name='bar' nameFrom=title
diff --git a/content/test/data/accessibility/accname/name-image-input-inside-label-with-generated-content.html b/content/test/data/accessibility/accname/name-image-input-inside-label-with-generated-content.html
new file mode 100644
index 0000000..d09f3a57
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-image-input-inside-label-with-generated-content.html
@@ -0,0 +1,15 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<style type="text/css">
+  label:before { content: "foo"; }
+  label:after { content: "baz"; }
+</style>
+<label for="test">
+<input id="test" type="image" src="foo.jpg" name="test" title="bar">
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-image-input-label-expected-blink.txt b/content/test/data/accessibility/accname/name-image-input-label-expected-blink.txt
new file mode 100644
index 0000000..357abc73
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-image-input-label-expected-blink.txt
@@ -0,0 +1 @@
+button name='foo' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-image-input-label-with-input-expected-blink.txt b/content/test/data/accessibility/accname/name-image-input-label-with-input-expected-blink.txt
new file mode 100644
index 0000000..2c85b8b
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-image-input-label-with-input-expected-blink.txt
@@ -0,0 +1 @@
+button name='foo bar baz' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-image-input-label-with-input.html b/content/test/data/accessibility/accname/name-image-input-label-with-input.html
new file mode 100644
index 0000000..d92282a
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-image-input-label-with-input.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="image" id="test" src="foo.jpg"/>
+<label for="test">foo<input type="text" value="bar">baz</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-image-input-label.html b/content/test/data/accessibility/accname/name-image-input-label.html
new file mode 100644
index 0000000..e9a22b5
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-image-input-label.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="image" id="test">
+<label for="test">foo</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-image-spinbutton-valuenow-in-label-expected-blink.txt b/content/test/data/accessibility/accname/name-image-spinbutton-valuenow-in-label-expected-blink.txt
new file mode 100644
index 0000000..782c02e
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-image-spinbutton-valuenow-in-label-expected-blink.txt
@@ -0,0 +1 @@
+button name='silly 4' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-image-spinbutton-valuenow-in-label.html b/content/test/data/accessibility/accname/name-image-spinbutton-valuenow-in-label.html
new file mode 100644
index 0000000..f6f32c2
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-image-spinbutton-valuenow-in-label.html
@@ -0,0 +1,12 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<label for="test">silly
+<div role="spinbutton" aria-valuemin="1" aria-valuemax="7" aria-valuenow="4"></div>
+</label>
+<input type="image" src="foo.jpg" id="test"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-image-title-expected-blink.txt b/content/test/data/accessibility/accname/name-image-title-expected-blink.txt
new file mode 100644
index 0000000..56ddd59
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-image-title-expected-blink.txt
@@ -0,0 +1 @@
+button name='foo' nameFrom=title
diff --git a/content/test/data/accessibility/accname/name-image-title.html b/content/test/data/accessibility/accname/name-image-title.html
new file mode 100644
index 0000000..f0c44fb
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-image-title.html
@@ -0,0 +1,9 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="image" src="test.png" id="test" title="foo" />
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-img-label-alt-title-expected-blink.txt b/content/test/data/accessibility/accname/name-img-label-alt-title-expected-blink.txt
new file mode 100644
index 0000000..3adb397
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-img-label-alt-title-expected-blink.txt
@@ -0,0 +1 @@
+image name='label' nameFrom=attribute
diff --git a/content/test/data/accessibility/accname/name-img-label-alt-title.html b/content/test/data/accessibility/accname/name-img-label-alt-title.html
new file mode 100644
index 0000000..d65f8188
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-img-label-alt-title.html
@@ -0,0 +1,9 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<img id="test" src="foo.jpg" aria-label="label" alt="alt" title="title"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-img-label-expected-blink.txt b/content/test/data/accessibility/accname/name-img-label-expected-blink.txt
new file mode 100644
index 0000000..3adb397
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-img-label-expected-blink.txt
@@ -0,0 +1 @@
+image name='label' nameFrom=attribute
diff --git a/content/test/data/accessibility/accname/name-img-label.html b/content/test/data/accessibility/accname/name-img-label.html
new file mode 100644
index 0000000..07957402
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-img-label.html
@@ -0,0 +1,9 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<img id="test" src="foo.jpg" aria-label="label"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-img-labelledby-inputs-expected-blink.txt b/content/test/data/accessibility/accname/name-img-labelledby-inputs-expected-blink.txt
new file mode 100644
index 0000000..48d98d6
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-img-labelledby-inputs-expected-blink.txt
@@ -0,0 +1 @@
+image name='peanuts popcorn apple jacks' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-img-labelledby-inputs-tree-expected-blink.txt b/content/test/data/accessibility/accname/name-img-labelledby-inputs-tree-expected-blink.txt
new file mode 100644
index 0000000..f92c92d2
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-img-labelledby-inputs-tree-expected-blink.txt
@@ -0,0 +1,16 @@
+rootWebArea
+++genericContainer ignored
+++++genericContainer
+++++++textField value='peanuts'
+++++++++genericContainer
+++++++++++staticText name='peanuts'
+++++++++++++inlineTextBox name='peanuts'
+++++++textField value='popcorn'
+++++++++genericContainer
+++++++++++staticText name='popcorn'
+++++++++++++inlineTextBox name='popcorn'
+++++++textField value='apple jacks'
+++++++++genericContainer
+++++++++++staticText name='apple jacks'
+++++++++++++inlineTextBox name='apple jacks'
+++++++image name='peanuts popcorn apple jacks'
diff --git a/content/test/data/accessibility/accname/name-img-labelledby-inputs.html b/content/test/data/accessibility/accname/name-img-labelledby-inputs.html
new file mode 100644
index 0000000..5d8c81244
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-img-labelledby-inputs.html
@@ -0,0 +1,12 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="text" value="peanuts" id="ID1">
+<input type="text" value="popcorn" id="ID2">
+<input type="text" value="apple jacks" id="ID3">
+<img aria-labelledby="ID1 ID2 ID3" id="test" src="foo.jpg"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-img-labelledby-self-and-input-expected-blink.txt b/content/test/data/accessibility/accname/name-img-labelledby-self-and-input-expected-blink.txt
new file mode 100644
index 0000000..4dca2dc
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-img-labelledby-self-and-input-expected-blink.txt
@@ -0,0 +1 @@
+image name='label peanuts' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-img-labelledby-self-and-input.html b/content/test/data/accessibility/accname/name-img-labelledby-self-and-input.html
new file mode 100644
index 0000000..5e73501
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-img-labelledby-self-and-input.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="text" value="peanuts" id="ID1">
+<img id="test" aria-label="label" aria-labelledby="test ID1" src="foo.jpg"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-img-labelledby-self-and-two-inputs-expected-blink.txt b/content/test/data/accessibility/accname/name-img-labelledby-self-and-two-inputs-expected-blink.txt
new file mode 100644
index 0000000..915f3df
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-img-labelledby-self-and-two-inputs-expected-blink.txt
@@ -0,0 +1 @@
+image name='label peanuts popcorn' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-img-labelledby-self-and-two-inputs.html b/content/test/data/accessibility/accname/name-img-labelledby-self-and-two-inputs.html
new file mode 100644
index 0000000..2b8bb71
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-img-labelledby-self-and-two-inputs.html
@@ -0,0 +1,11 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="text" value="peanuts" id="ID1">
+<input type="text" value="popcorn" id="ID2">
+<img id="test" aria-label="label" aria-labelledby="test ID1 ID2" src="foo.jpg"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-img-labelledby-self-expected-blink.txt b/content/test/data/accessibility/accname/name-img-labelledby-self-expected-blink.txt
new file mode 100644
index 0000000..773b222
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-img-labelledby-self-expected-blink.txt
@@ -0,0 +1 @@
+image
diff --git a/content/test/data/accessibility/accname/name-img-labelledby-self.html b/content/test/data/accessibility/accname/name-img-labelledby-self.html
new file mode 100644
index 0000000..4a894a02
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-img-labelledby-self.html
@@ -0,0 +1,9 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<img id="test" aria-labelledby="test" src="foo.jpg"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-img-multiple-sources-expected-blink.txt b/content/test/data/accessibility/accname/name-img-multiple-sources-expected-blink.txt
new file mode 100644
index 0000000..84ce93b
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-img-multiple-sources-expected-blink.txt
@@ -0,0 +1 @@
+image name='label peanuts popcorn apple jacks' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-img-multiple-sources-some-empty-expected-blink.txt b/content/test/data/accessibility/accname/name-img-multiple-sources-some-empty-expected-blink.txt
new file mode 100644
index 0000000..2d8ee1c
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-img-multiple-sources-some-empty-expected-blink.txt
@@ -0,0 +1,2 @@
+# BUG? The expected result is 'title peanuts popcorn apple jacks'
+image name='peanuts popcorn apple jacks' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-img-multiple-sources-some-empty.html b/content/test/data/accessibility/accname/name-img-multiple-sources-some-empty.html
new file mode 100644
index 0000000..9438134
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-img-multiple-sources-some-empty.html
@@ -0,0 +1,12 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="text" value="peanuts" id="ID1">
+<input type="text" value="popcorn" id="ID2">
+<input type="text" value="apple jacks" id="ID3">
+<img id="test" aria-label="" aria-labelledby="test ID1 ID2 ID3" alt="" title="title" src="foo.jpg"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-img-multiple-sources.html b/content/test/data/accessibility/accname/name-img-multiple-sources.html
new file mode 100644
index 0000000..c7066ea6
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-img-multiple-sources.html
@@ -0,0 +1,17 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="text" value="peanuts" id="ID1">
+<input type="text" value="popcorn" id="ID2">
+<input type="text" value="apple jacks" id="ID3">
+<img id="test"
+     aria-label="label"
+     aria-labelledby="test ID1 ID2 ID3"
+     alt= "alt"
+     title="title"
+     src="foo.jpg"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-img-with-label-labels-itself-expected-blink.txt b/content/test/data/accessibility/accname/name-img-with-label-labels-itself-expected-blink.txt
new file mode 100644
index 0000000..eb443e14
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-img-with-label-labels-itself-expected-blink.txt
@@ -0,0 +1 @@
+image name='label' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-img-with-label-labels-itself.html b/content/test/data/accessibility/accname/name-img-with-label-labels-itself.html
new file mode 100644
index 0000000..0b836b5a
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-img-with-label-labels-itself.html
@@ -0,0 +1,9 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<img id="test" aria-labelledby="test" aria-label="label" src="foo.jpg"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-link-content-only-expected-blink.txt b/content/test/data/accessibility/accname/name-link-content-only-expected-blink.txt
new file mode 100644
index 0000000..b1d321d
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-link-content-only-expected-blink.txt
@@ -0,0 +1 @@
+link name='ABC' nameFrom=contents
diff --git a/content/test/data/accessibility/accname/name-link-content-only.html b/content/test/data/accessibility/accname/name-link-content-only.html
new file mode 100644
index 0000000..3286cd6
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-link-content-only.html
@@ -0,0 +1,9 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<a href="test.html" id="test">ABC</a>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-link-empty-with-title-expected-blink.txt b/content/test/data/accessibility/accname/name-link-empty-with-title-expected-blink.txt
new file mode 100644
index 0000000..508a08c
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-link-empty-with-title-expected-blink.txt
@@ -0,0 +1 @@
+link name='Tag' nameFrom=title
diff --git a/content/test/data/accessibility/accname/name-link-empty-with-title.html b/content/test/data/accessibility/accname/name-link-empty-with-title.html
new file mode 100644
index 0000000..f81d0ec4
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-link-empty-with-title.html
@@ -0,0 +1,9 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<a href="test.html" id="test" title="Tag"></a>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-link-label-expected-blink.txt b/content/test/data/accessibility/accname/name-link-label-expected-blink.txt
new file mode 100644
index 0000000..4e110bc
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-link-label-expected-blink.txt
@@ -0,0 +1 @@
+link name='Tag' nameFrom=attribute
diff --git a/content/test/data/accessibility/accname/name-link-label-title-expected-blink.txt b/content/test/data/accessibility/accname/name-link-label-title-expected-blink.txt
new file mode 100644
index 0000000..5aa9c6d
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-link-label-title-expected-blink.txt
@@ -0,0 +1 @@
+link name='California' nameFrom=attribute
diff --git a/content/test/data/accessibility/accname/name-link-label-title.html b/content/test/data/accessibility/accname/name-link-label-title.html
new file mode 100644
index 0000000..c2c9e73
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-link-label-title.html
@@ -0,0 +1,9 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<a id="test" href="#" aria-label="California" title="San Francisco">United States</a>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-link-label.html b/content/test/data/accessibility/accname/name-link-label.html
new file mode 100644
index 0000000..ecc73ef
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-link-label.html
@@ -0,0 +1,9 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<a id="test" href="test.html" aria-label="Tag">ABC</a>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-link-labelledby-expected-blink.txt b/content/test/data/accessibility/accname/name-link-labelledby-expected-blink.txt
new file mode 100644
index 0000000..7b84bd99
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-link-labelledby-expected-blink.txt
@@ -0,0 +1 @@
+link name='foo' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-link-labelledby-self-and-paragraph-expected-blink.txt b/content/test/data/accessibility/accname/name-link-labelledby-self-and-paragraph-expected-blink.txt
new file mode 100644
index 0000000..03c86856
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-link-labelledby-self-and-paragraph-expected-blink.txt
@@ -0,0 +1 @@
+link name='Tag foo' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-link-labelledby-self-and-paragraph.html b/content/test/data/accessibility/accname/name-link-labelledby-self-and-paragraph.html
new file mode 100644
index 0000000..001e4015
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-link-labelledby-self-and-paragraph.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<a href="test.html" id="test" aria-labelledby="test ID1" aria-label="Tag"></a>
+<p id="ID1">foo</p>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-link-labelledby.html b/content/test/data/accessibility/accname/name-link-labelledby.html
new file mode 100644
index 0000000..ed7d2ba
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-link-labelledby.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<div id="ID1">foo</div>
+<a id="test" href="test.html" aria-labelledby="ID1">bar</a>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-link-mixed-content-expected-blink.txt b/content/test/data/accessibility/accname/name-link-mixed-content-expected-blink.txt
new file mode 100644
index 0000000..7bb9ae20
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-link-mixed-content-expected-blink.txt
@@ -0,0 +1 @@
+link name='My name is Eli the weird. (QED)' nameFrom=contents
diff --git a/content/test/data/accessibility/accname/name-link-mixed-content.html b/content/test/data/accessibility/accname/name-link-mixed-content.html
new file mode 100644
index 0000000..d34462a
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-link-mixed-content.html
@@ -0,0 +1,20 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<style>
+  .hidden { display: none; }
+</style>
+<div id="test" role="link" tabindex="0">
+  <span aria-hidden="true"><i> Hello, </i></span>
+  <span>My</span> name is
+  <div><img src="file.jpg" title="Bryan" alt="" role="presentation" /></div>
+  <span role="presentation" aria-label="Eli"><span aria-label="Garaventa">Zambino</span></span>
+  <span>the weird.</span>
+  (QED)
+  <span class="hidden"><i><b>and don't you forget it.</b></i></span>
+</div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-link-multiple-sources-expected-blink.txt b/content/test/data/accessibility/accname/name-link-multiple-sources-expected-blink.txt
new file mode 100644
index 0000000..959e708
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-link-multiple-sources-expected-blink.txt
@@ -0,0 +1 @@
+link name='bar' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-link-multiple-sources.html b/content/test/data/accessibility/accname/name-link-multiple-sources.html
new file mode 100644
index 0000000..5b0a394
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-link-multiple-sources.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<a href="test.html" id="test" aria-labelledby="ID1" aria-label="Tag">foo</a>
+<p id="ID1">bar</p>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-password-css-after-in-label-expected-blink.txt b/content/test/data/accessibility/accname/name-password-css-after-in-label-expected-blink.txt
new file mode 100644
index 0000000..594ed1c4
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-password-css-after-in-label-expected-blink.txt
@@ -0,0 +1,2 @@
+# BUG: The expected result is 'fancy fruit'
+textField protected name='fancy' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-password-css-after-in-label.html b/content/test/data/accessibility/accname/name-password-css-after-in-label.html
new file mode 100644
index 0000000..72e9778
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-password-css-after-in-label.html
@@ -0,0 +1,12 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<body>
+<style>
+  label:after { content:" fruit"; }
+</style>
+<label for="test">fancy</label>
+<input type="password" id="test"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-password-css-before-in-label-expected-blink.txt b/content/test/data/accessibility/accname/name-password-css-before-in-label-expected-blink.txt
new file mode 100644
index 0000000..f23a2892
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-password-css-before-in-label-expected-blink.txt
@@ -0,0 +1,2 @@
+# BUG: The expected result is 'fancy fruit'
+textField protected name='fruit' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-password-css-before-in-label.html b/content/test/data/accessibility/accname/name-password-css-before-in-label.html
new file mode 100644
index 0000000..f20cb41
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-password-css-before-in-label.html
@@ -0,0 +1,13 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<style>
+  label:before { content:"fancy "; }
+</style>
+<label for="test">fruit</label>
+<input type="password" id="test"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-password-input-in-label-expected-blink.txt b/content/test/data/accessibility/accname/name-password-input-in-label-expected-blink.txt
new file mode 100644
index 0000000..12ebdd8
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-password-input-in-label-expected-blink.txt
@@ -0,0 +1 @@
+textField protected name='foo David' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-password-input-in-label.html b/content/test/data/accessibility/accname/name-password-input-in-label.html
new file mode 100644
index 0000000..f0c116a
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-password-input-in-label.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<label for="test">foo<input type="text" value="David"/></label>
+<input type="password" id="test" value="baz"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-password-inside-label-with-generated-content-expected-blink.txt b/content/test/data/accessibility/accname/name-password-inside-label-with-generated-content-expected-blink.txt
new file mode 100644
index 0000000..c69e358
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-password-inside-label-with-generated-content-expected-blink.txt
@@ -0,0 +1,2 @@
+# BUG: The expected result is 'foo bar baz'
+textField protected name='bar' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-password-inside-label-with-generated-content.html b/content/test/data/accessibility/accname/name-password-inside-label-with-generated-content.html
new file mode 100644
index 0000000..dee3282
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-password-inside-label-with-generated-content.html
@@ -0,0 +1,15 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<style type="text/css">
+  label:before { content: "foo"; }
+  label:after { content: "baz"; }
+</style>
+<label for="test" title="bar">
+<input id="test" type="password" name="test" title="buz">
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-password-label-embedded-combobox-expected-blink.txt b/content/test/data/accessibility/accname/name-password-label-embedded-combobox-expected-blink.txt
new file mode 100644
index 0000000..0685e46
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-password-label-embedded-combobox-expected-blink.txt
@@ -0,0 +1 @@
+textField protected name='Flash the screen 1 times.' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-password-label-embedded-combobox.html b/content/test/data/accessibility/accname/name-password-label-embedded-combobox.html
new file mode 100644
index 0000000..76c17cd4
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-password-label-embedded-combobox.html
@@ -0,0 +1,20 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="password" id="test" />
+<label for="test">Flash the screen
+  <div role="combobox">
+    <div role="textbox"></div>
+    <ul role="listbox" style="list-style-type: none;">
+      <li role="option" aria-selected="true">1</li>
+      <li role="option">2</li>
+      <li role="option">3</li>
+    </ul>
+  </div>
+  times.
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-password-label-embedded-menu-expected-blink.txt b/content/test/data/accessibility/accname/name-password-label-embedded-menu-expected-blink.txt
new file mode 100644
index 0000000..55ba6df
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-password-label-embedded-menu-expected-blink.txt
@@ -0,0 +1 @@
+textField protected name='Flash the screen times.' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-password-label-embedded-menu.html b/content/test/data/accessibility/accname/name-password-label-embedded-menu.html
new file mode 100644
index 0000000..1c5cbe89
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-password-label-embedded-menu.html
@@ -0,0 +1,17 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="password" id="test" />
+<label for="test">Flash the screen
+  <span role="menu">
+    <span role="menuitem" aria-selected="true">1</span>
+    <span role="menuitem" hidden>2</span>
+    <span role="menuitem" hidden>3</span>
+  </span>
+  times.
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-password-label-embedded-select-expected-blink.txt b/content/test/data/accessibility/accname/name-password-label-embedded-select-expected-blink.txt
new file mode 100644
index 0000000..0685e46
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-password-label-embedded-select-expected-blink.txt
@@ -0,0 +1 @@
+textField protected name='Flash the screen 1 times.' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-password-label-embedded-select.html b/content/test/data/accessibility/accname/name-password-label-embedded-select.html
new file mode 100644
index 0000000..4aa39987
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-password-label-embedded-select.html
@@ -0,0 +1,17 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="password" id="test" />
+<label for="test">Flash the screen
+  <select size="1">
+    <option selected="selected">1</option>
+    <option>2</option>
+    <option>3</option>
+  </select>
+  times.
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-password-label-embedded-slider-expected-blink.txt b/content/test/data/accessibility/accname/name-password-label-embedded-slider-expected-blink.txt
new file mode 100644
index 0000000..707640d
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-password-label-embedded-slider-expected-blink.txt
@@ -0,0 +1 @@
+textField protected name='foo 5 baz' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-password-label-embedded-slider.html b/content/test/data/accessibility/accname/name-password-label-embedded-slider.html
new file mode 100644
index 0000000..e325bbe1
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-password-label-embedded-slider.html
@@ -0,0 +1,19 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="password" id="test" />
+<label for="test">foo
+<input role="slider"
+       type="range"
+       value="5"
+       min="1"
+       max="10"
+       aria-valuenow="5"
+       aria-valuemin="1"
+       aria-valuemax="10"> baz
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-password-label-embedded-spinbutton-expected-blink.txt b/content/test/data/accessibility/accname/name-password-label-embedded-spinbutton-expected-blink.txt
new file mode 100644
index 0000000..707640d
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-password-label-embedded-spinbutton-expected-blink.txt
@@ -0,0 +1 @@
+textField protected name='foo 5 baz' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-password-label-embedded-spinbutton.html b/content/test/data/accessibility/accname/name-password-label-embedded-spinbutton.html
new file mode 100644
index 0000000..fecb67d9
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-password-label-embedded-spinbutton.html
@@ -0,0 +1,21 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="password" id="test" />
+<label for="test">
+  foo
+  <input role="spinbutton"
+	 type="number"
+	 value="5"
+	 min="1"
+	 max="10"
+	 aria-valuenow="5"
+	 aria-valuemin="1"
+	 aria-valuemax="10">
+  baz
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-password-label-expected-blink.txt b/content/test/data/accessibility/accname/name-password-label-expected-blink.txt
new file mode 100644
index 0000000..7d79a9a
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-password-label-expected-blink.txt
@@ -0,0 +1 @@
+textField protected name='foo' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-password-label-with-input-expected-blink.txt b/content/test/data/accessibility/accname/name-password-label-with-input-expected-blink.txt
new file mode 100644
index 0000000..b87bee0b
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-password-label-with-input-expected-blink.txt
@@ -0,0 +1 @@
+textField protected name='foo bar baz' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-password-label-with-input.html b/content/test/data/accessibility/accname/name-password-label-with-input.html
new file mode 100644
index 0000000..e493a80
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-password-label-with-input.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="password" id="test">
+<label for="test">foo<input type="text" value="bar">baz</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-password-label.html b/content/test/data/accessibility/accname/name-password-label.html
new file mode 100644
index 0000000..0214398
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-password-label.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="password" id="test">
+<label for="test">foo</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-password-title-expected-blink.txt b/content/test/data/accessibility/accname/name-password-title-expected-blink.txt
new file mode 100644
index 0000000..112afa3d
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-password-title-expected-blink.txt
@@ -0,0 +1 @@
+textField protected name='foo' nameFrom=title
diff --git a/content/test/data/accessibility/accname/name-password-title.html b/content/test/data/accessibility/accname/name-password-title.html
new file mode 100644
index 0000000..f08755cb
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-password-title.html
@@ -0,0 +1,9 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="password" id="test" title="foo" />
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-radio-css-after-in-label-expected-blink.txt b/content/test/data/accessibility/accname/name-radio-css-after-in-label-expected-blink.txt
new file mode 100644
index 0000000..c794150
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-css-after-in-label-expected-blink.txt
@@ -0,0 +1,2 @@
+# BUG: The expected result is 'fancy fruit'
+radioButton name='fancy' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-radio-css-after-in-label.html b/content/test/data/accessibility/accname/name-radio-css-after-in-label.html
new file mode 100644
index 0000000..2819a88e
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-css-after-in-label.html
@@ -0,0 +1,12 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<body>
+<style>
+  label:after { content:" fruit"; }
+</style>
+<label for="test">fancy</label>
+<input type="radio" id="test"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-radio-css-before-in-label-expected-blink.txt b/content/test/data/accessibility/accname/name-radio-css-before-in-label-expected-blink.txt
new file mode 100644
index 0000000..1af1fcf
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-css-before-in-label-expected-blink.txt
@@ -0,0 +1,2 @@
+# BUG: The expected result is 'fancy fruit'
+radioButton name='fruit' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-radio-css-before-in-label.html b/content/test/data/accessibility/accname/name-radio-css-before-in-label.html
new file mode 100644
index 0000000..96816af
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-css-before-in-label.html
@@ -0,0 +1,13 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<style>
+  label:before { content:"fancy "; }
+</style>
+<label for="test">fruit</label>
+<input type="radio" id="test"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-radio-input-in-label-expected-blink.txt b/content/test/data/accessibility/accname/name-radio-input-in-label-expected-blink.txt
new file mode 100644
index 0000000..85081a1
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-input-in-label-expected-blink.txt
@@ -0,0 +1 @@
+radioButton name='foo David' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-radio-input-in-label.html b/content/test/data/accessibility/accname/name-radio-input-in-label.html
new file mode 100644
index 0000000..dda7068
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-input-in-label.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<label for="test">foo<input type="text" value="David"/></label>
+<input type="radio" id="test"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-radio-inside-label-with-generated-content-expected-blink.txt b/content/test/data/accessibility/accname/name-radio-inside-label-with-generated-content-expected-blink.txt
new file mode 100644
index 0000000..b05f25d
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-inside-label-with-generated-content-expected-blink.txt
@@ -0,0 +1,2 @@
+# BUG: The expected result is 'foo baz'
+radioButton name=' bar ' nameFrom=title
diff --git a/content/test/data/accessibility/accname/name-radio-inside-label-with-generated-content.html b/content/test/data/accessibility/accname/name-radio-inside-label-with-generated-content.html
new file mode 100644
index 0000000..182e888c
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-inside-label-with-generated-content.html
@@ -0,0 +1,15 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<style type="text/css">
+  label:before { content: "foo"; }
+  label:after { content: "baz"; }
+</style>
+<label for="test">
+<input id="test" type="radio" name="test" title=" bar ">
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-radio-label-embedded-combobox-expected-blink.txt b/content/test/data/accessibility/accname/name-radio-label-embedded-combobox-expected-blink.txt
new file mode 100644
index 0000000..673d7b6
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-label-embedded-combobox-expected-blink.txt
@@ -0,0 +1 @@
+radioButton name='Flash the screen 1 times.' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-radio-label-embedded-combobox.html b/content/test/data/accessibility/accname/name-radio-label-embedded-combobox.html
new file mode 100644
index 0000000..12c6f6ad
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-label-embedded-combobox.html
@@ -0,0 +1,20 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="radio" id="test" />
+<label for="test">Flash the screen
+  <div role="combobox">
+    <div role="textbox"></div>
+    <ul role="listbox" style="list-style-type: none;">
+      <li role="option" aria-selected="true">1</li>
+      <li role="option">2</li>
+      <li role="option">3</li>
+    </ul>
+  </div>
+  times.
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-radio-label-embedded-menu-expected-blink.txt b/content/test/data/accessibility/accname/name-radio-label-embedded-menu-expected-blink.txt
new file mode 100644
index 0000000..df025a5
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-label-embedded-menu-expected-blink.txt
@@ -0,0 +1 @@
+radioButton name='Flash the screen times.' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-radio-label-embedded-menu.html b/content/test/data/accessibility/accname/name-radio-label-embedded-menu.html
new file mode 100644
index 0000000..00fcf35d
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-label-embedded-menu.html
@@ -0,0 +1,17 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="radio" id="test" />
+<label for="test">Flash the screen
+  <span role="menu">
+    <span role="menuitem" aria-selected="true">1</span>
+    <span role="menuitem" hidden>2</span>
+    <span role="menuitem" hidden>3</span>
+  </span>
+  times.
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-radio-label-embedded-select-expected-blink.txt b/content/test/data/accessibility/accname/name-radio-label-embedded-select-expected-blink.txt
new file mode 100644
index 0000000..673d7b6
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-label-embedded-select-expected-blink.txt
@@ -0,0 +1 @@
+radioButton name='Flash the screen 1 times.' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-radio-label-embedded-select.html b/content/test/data/accessibility/accname/name-radio-label-embedded-select.html
new file mode 100644
index 0000000..7d7dd47
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-label-embedded-select.html
@@ -0,0 +1,17 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="radio" id="test" />
+<label for="test">Flash the screen
+  <select size="1">
+    <option selected="selected">1</option>
+    <option>2</option>
+    <option>3</option>
+  </select>
+  times.
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-radio-label-embedded-slider-expected-blink.txt b/content/test/data/accessibility/accname/name-radio-label-embedded-slider-expected-blink.txt
new file mode 100644
index 0000000..f911a1a
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-label-embedded-slider-expected-blink.txt
@@ -0,0 +1 @@
+radioButton name='foo 5 baz' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-radio-label-embedded-slider.html b/content/test/data/accessibility/accname/name-radio-label-embedded-slider.html
new file mode 100644
index 0000000..c5bcf95
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-label-embedded-slider.html
@@ -0,0 +1,19 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="radio" id="test" />
+<label for="test">foo
+<input role="slider"
+       type="range"
+       value="5"
+       min="1"
+       max="10"
+       aria-valuenow="5"
+       aria-valuemin="1"
+       aria-valuemax="10"> baz
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-radio-label-embedded-spinbutton-expected-blink.txt b/content/test/data/accessibility/accname/name-radio-label-embedded-spinbutton-expected-blink.txt
new file mode 100644
index 0000000..f911a1a
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-label-embedded-spinbutton-expected-blink.txt
@@ -0,0 +1 @@
+radioButton name='foo 5 baz' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-radio-label-embedded-spinbutton.html b/content/test/data/accessibility/accname/name-radio-label-embedded-spinbutton.html
new file mode 100644
index 0000000..7e79dcfe
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-label-embedded-spinbutton.html
@@ -0,0 +1,21 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="radio" id="test" />
+<label for="test">
+  foo
+  <input role="spinbutton"
+	 type="number"
+	 value="5"
+	 min="1"
+	 max="10"
+	 aria-valuenow="5"
+	 aria-valuemin="1"
+	 aria-valuemax="10">
+  baz
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-radio-label-expected-blink.txt b/content/test/data/accessibility/accname/name-radio-label-expected-blink.txt
new file mode 100644
index 0000000..b5c1293
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-label-expected-blink.txt
@@ -0,0 +1 @@
+radioButton name='foo' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-radio-label-with-input-expected-blink.txt b/content/test/data/accessibility/accname/name-radio-label-with-input-expected-blink.txt
new file mode 100644
index 0000000..83f9fc64
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-label-with-input-expected-blink.txt
@@ -0,0 +1 @@
+radioButton name='foo bar baz' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-radio-label-with-input.html b/content/test/data/accessibility/accname/name-radio-label-with-input.html
new file mode 100644
index 0000000..f6e9f966
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-label-with-input.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="radio" id="test">
+<label for="test">foo<input type="text" value="bar">baz</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-radio-label.html b/content/test/data/accessibility/accname/name-radio-label.html
new file mode 100644
index 0000000..5a6f3d0
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-label.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="radio" id="test">
+<label for="test">foo</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-radio-spinbutton-valuenow-in-label-expected-blink.txt b/content/test/data/accessibility/accname/name-radio-spinbutton-valuenow-in-label-expected-blink.txt
new file mode 100644
index 0000000..10b6186
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-spinbutton-valuenow-in-label-expected-blink.txt
@@ -0,0 +1 @@
+radioButton name='silly 4' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-radio-spinbutton-valuenow-in-label.html b/content/test/data/accessibility/accname/name-radio-spinbutton-valuenow-in-label.html
new file mode 100644
index 0000000..9df426b
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-spinbutton-valuenow-in-label.html
@@ -0,0 +1,12 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<label for="test">silly
+<div role="spinbutton" aria-valuemin="1" aria-valuemax="7" aria-valuenow="4"></div>
+</label>
+<input type="radio" id="test"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-radio-title-expected-blink.txt b/content/test/data/accessibility/accname/name-radio-title-expected-blink.txt
new file mode 100644
index 0000000..f76330f5
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-title-expected-blink.txt
@@ -0,0 +1 @@
+radioButton name='foo' nameFrom=title
diff --git a/content/test/data/accessibility/accname/name-radio-title.html b/content/test/data/accessibility/accname/name-radio-title.html
new file mode 100644
index 0000000..5e58e91
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-radio-title.html
@@ -0,0 +1,9 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="radio" id="test" title="foo" />
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-reset-button-expected-blink.txt b/content/test/data/accessibility/accname/name-reset-button-expected-blink.txt
new file mode 100644
index 0000000..be102b5
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-reset-button-expected-blink.txt
@@ -0,0 +1 @@
+button name='Reset' nameFrom=contents
diff --git a/content/test/data/accessibility/accname/name-reset-button.html b/content/test/data/accessibility/accname/name-reset-button.html
new file mode 100644
index 0000000..02f07246
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-reset-button.html
@@ -0,0 +1,9 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="reset" id="test"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-text-css-after-in-label-expected-blink.txt b/content/test/data/accessibility/accname/name-text-css-after-in-label-expected-blink.txt
new file mode 100644
index 0000000..6240250c
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-css-after-in-label-expected-blink.txt
@@ -0,0 +1,2 @@
+# BUG: The expected result is 'text content'
+textField
diff --git a/content/test/data/accessibility/accname/name-text-css-after-in-label.html b/content/test/data/accessibility/accname/name-text-css-after-in-label.html
new file mode 100644
index 0000000..2b89820
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-css-after-in-label.html
@@ -0,0 +1,13 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+  <style type="text/css">
+  [data-after]:after { content: attr(data-after); }
+</style>
+<label for="test" data-after="test content"></label>
+<input type="text" id="test">
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-text-css-before-in-label-expected-blink.txt b/content/test/data/accessibility/accname/name-text-css-before-in-label-expected-blink.txt
new file mode 100644
index 0000000..8c8c3c6a9
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-css-before-in-label-expected-blink.txt
@@ -0,0 +1,2 @@
+# BUG: The expected result is 'fancy fruit'
+textField name='fruit' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-text-css-before-in-label.html b/content/test/data/accessibility/accname/name-text-css-before-in-label.html
new file mode 100644
index 0000000..25feb6e1
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-css-before-in-label.html
@@ -0,0 +1,13 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<style>
+  label:before { content:"fancy "; }
+</style>
+<label for="test">fruit</label>
+<input type="text" id="test"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-text-input-in-label-expected-blink.txt b/content/test/data/accessibility/accname/name-text-input-in-label-expected-blink.txt
new file mode 100644
index 0000000..6362e49
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-input-in-label-expected-blink.txt
@@ -0,0 +1 @@
+textField name='foo David' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-text-input-in-label.html b/content/test/data/accessibility/accname/name-text-input-in-label.html
new file mode 100644
index 0000000..b1a1ff1
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-input-in-label.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<label for="test">foo<input type="text" value="David"/></label>
+<input type="text" id="test" value="baz"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-text-inside-label-with-generated-content-expected-blink.txt b/content/test/data/accessibility/accname/name-text-inside-label-with-generated-content-expected-blink.txt
new file mode 100644
index 0000000..65aa2bc
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-inside-label-with-generated-content-expected-blink.txt
@@ -0,0 +1,2 @@
+# BUG: The expected result is 'foo bar baz'
+textField name='bar' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-text-inside-label-with-generated-content.html b/content/test/data/accessibility/accname/name-text-inside-label-with-generated-content.html
new file mode 100644
index 0000000..e03592c
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-inside-label-with-generated-content.html
@@ -0,0 +1,15 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<style type="text/css">
+  label:before { content: "foo"; }
+  label:after { content: "baz"; }
+</style>
+<label for="test" title="bar">
+<input id="test" type="text" name="test" title="buz">
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-text-label-embedded-combobox-expected-blink.txt b/content/test/data/accessibility/accname/name-text-label-embedded-combobox-expected-blink.txt
new file mode 100644
index 0000000..ebdccef
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-label-embedded-combobox-expected-blink.txt
@@ -0,0 +1 @@
+textField name='Flash the screen 1 times.' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-text-label-embedded-combobox.html b/content/test/data/accessibility/accname/name-text-label-embedded-combobox.html
new file mode 100644
index 0000000..7f1072c9
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-label-embedded-combobox.html
@@ -0,0 +1,20 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="test" id="test" />
+<label for="test">Flash the screen
+  <div role="combobox">
+    <div role="textbox"></div>
+    <ul role="listbox" style="list-style-type: none;">
+      <li role="option" aria-selected="true">1</li>
+      <li role="option">2</li>
+      <li role="option">3</li>
+    </ul>
+  </div>
+  times.
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-text-label-embedded-menu-expected-blink.txt b/content/test/data/accessibility/accname/name-text-label-embedded-menu-expected-blink.txt
new file mode 100644
index 0000000..17f2bddc
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-label-embedded-menu-expected-blink.txt
@@ -0,0 +1 @@
+textField name='Flash the screen times.' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-text-label-embedded-menu.html b/content/test/data/accessibility/accname/name-text-label-embedded-menu.html
new file mode 100644
index 0000000..80b6e668
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-label-embedded-menu.html
@@ -0,0 +1,17 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="text" id="test" />
+<label for="test">Flash the screen
+  <span role="menu">
+    <span role="menuitem" aria-selected="true">1</span>
+    <span role="menuitem" hidden>2</span>
+    <span role="menuitem" hidden>3</span>
+  </span>
+  times.
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-text-label-embedded-select-expected-blink.txt b/content/test/data/accessibility/accname/name-text-label-embedded-select-expected-blink.txt
new file mode 100644
index 0000000..ebdccef
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-label-embedded-select-expected-blink.txt
@@ -0,0 +1 @@
+textField name='Flash the screen 1 times.' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-text-label-embedded-select.html b/content/test/data/accessibility/accname/name-text-label-embedded-select.html
new file mode 100644
index 0000000..86a30cb
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-label-embedded-select.html
@@ -0,0 +1,17 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="text" id="test" />
+<label for="test">Flash the screen
+  <select size="1">
+    <option selected="selected">1</option>
+    <option>2</option>
+    <option>3</option>
+  </select>
+  times.
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-text-label-embedded-slider-expected-blink.txt b/content/test/data/accessibility/accname/name-text-label-embedded-slider-expected-blink.txt
new file mode 100644
index 0000000..8cbc91c1
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-label-embedded-slider-expected-blink.txt
@@ -0,0 +1 @@
+textField name='foo 5 baz' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-text-label-embedded-slider.html b/content/test/data/accessibility/accname/name-text-label-embedded-slider.html
new file mode 100644
index 0000000..9689b28
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-label-embedded-slider.html
@@ -0,0 +1,19 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="text" id="test" />
+<label for="test">foo
+<input role="slider"
+       type="range"
+       value="5"
+       min="1"
+       max="10"
+       aria-valuenow="5"
+       aria-valuemin="1"
+       aria-valuemax="10"> baz
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-text-label-embedded-spinbutton-expected-blink.txt b/content/test/data/accessibility/accname/name-text-label-embedded-spinbutton-expected-blink.txt
new file mode 100644
index 0000000..8cbc91c1
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-label-embedded-spinbutton-expected-blink.txt
@@ -0,0 +1 @@
+textField name='foo 5 baz' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-text-label-embedded-spinbutton.html b/content/test/data/accessibility/accname/name-text-label-embedded-spinbutton.html
new file mode 100644
index 0000000..7527313
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-label-embedded-spinbutton.html
@@ -0,0 +1,21 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="text" id="test" />
+<label for="test">
+  foo
+  <input role="spinbutton"
+	 type="number"
+	 value="5"
+	 min="1"
+	 max="10"
+	 aria-valuenow="5"
+	 aria-valuemin="1"
+	 aria-valuemax="10">
+  baz
+</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-text-label-expected-blink.txt b/content/test/data/accessibility/accname/name-text-label-expected-blink.txt
new file mode 100644
index 0000000..ac00307
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-label-expected-blink.txt
@@ -0,0 +1 @@
+textField name='foo' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-text-label-with-input-expected-blink.txt b/content/test/data/accessibility/accname/name-text-label-with-input-expected-blink.txt
new file mode 100644
index 0000000..044a728
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-label-with-input-expected-blink.txt
@@ -0,0 +1 @@
+textField name='foo bar baz' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-text-label-with-input.html b/content/test/data/accessibility/accname/name-text-label-with-input.html
new file mode 100644
index 0000000..41299497
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-label-with-input.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="text" id="test">
+<label for="test">foo<input type="text" value="bar">baz</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-text-label.html b/content/test/data/accessibility/accname/name-text-label.html
new file mode 100644
index 0000000..37dec27
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-label.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input id="test" type="text"/>
+<label for="test">foo</label>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-text-labelledby-paragraphs-expected-blink.txt b/content/test/data/accessibility/accname/name-text-labelledby-paragraphs-expected-blink.txt
new file mode 100644
index 0000000..044a728
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-labelledby-paragraphs-expected-blink.txt
@@ -0,0 +1 @@
+textField name='foo bar baz' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-text-labelledby-paragraphs.html b/content/test/data/accessibility/accname/name-text-labelledby-paragraphs.html
new file mode 100644
index 0000000..637f0d5
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-labelledby-paragraphs.html
@@ -0,0 +1,12 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input id="test" type="text" aria-labelledby="ID1 ID2 ID3">
+<p id="ID1">foo</p>
+<p id="ID2">bar</p>
+<p id="ID3">baz</p>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-text-labelledby-self-and-div-expected-blink.txt b/content/test/data/accessibility/accname/name-text-labelledby-self-and-div-expected-blink.txt
new file mode 100644
index 0000000..f6ebc2f
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-labelledby-self-and-div-expected-blink.txt
@@ -0,0 +1 @@
+textField name='foo bar' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-text-labelledby-self-and-div.html b/content/test/data/accessibility/accname/name-text-labelledby-self-and-div.html
new file mode 100644
index 0000000..c56b412
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-labelledby-self-and-div.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input id="test" type="text" aria-label="bar" aria-labelledby="ID1 test">
+<div id="ID1">foo</div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-text-select-in-label-expected-blink.txt b/content/test/data/accessibility/accname/name-text-select-in-label-expected-blink.txt
new file mode 100644
index 0000000..8ccba44
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-select-in-label-expected-blink.txt
@@ -0,0 +1 @@
+textField name='silly' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-text-select-in-label.html b/content/test/data/accessibility/accname/name-text-select-in-label.html
new file mode 100644
index 0000000..ef3a0f4
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-select-in-label.html
@@ -0,0 +1,15 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<label for="test">silly
+  <select name="member" size="1" role="menu" tabindex="0">
+    <option role="menuitem" value="beard" selected="true">clown</option>
+    <option role="menuitem" value="scuba">rich</option>
+  </select>
+</label>
+<input type="text" id="test" value="baz"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-text-spinbutton-valuenow-in-label-expected-blink.txt b/content/test/data/accessibility/accname/name-text-spinbutton-valuenow-in-label-expected-blink.txt
new file mode 100644
index 0000000..4e1f3db9
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-spinbutton-valuenow-in-label-expected-blink.txt
@@ -0,0 +1 @@
+textField name='silly 4' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-text-spinbutton-valuenow-in-label.html b/content/test/data/accessibility/accname/name-text-spinbutton-valuenow-in-label.html
new file mode 100644
index 0000000..3a09837
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-spinbutton-valuenow-in-label.html
@@ -0,0 +1,12 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<label for="test">silly
+<div role="spinbutton" aria-valuemin="1" aria-valuemax="7" aria-valuenow="4"></div>
+</label>
+<input type="text" id="test" value="baz"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-text-spinbutton-valuetext-in-label-expected-blink.txt b/content/test/data/accessibility/accname/name-text-spinbutton-valuetext-in-label-expected-blink.txt
new file mode 100644
index 0000000..944e1fc2
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-spinbutton-valuetext-in-label-expected-blink.txt
@@ -0,0 +1 @@
+textField name='silly Monday' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-text-spinbutton-valuetext-in-label.html b/content/test/data/accessibility/accname/name-text-spinbutton-valuetext-in-label.html
new file mode 100644
index 0000000..c47c31b
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-spinbutton-valuetext-in-label.html
@@ -0,0 +1,17 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<label for="test">silly
+<div role="spinbutton"
+     aria-valuetext="Monday"
+     aria-valuemin="1"
+     aria-valuemax="7"
+     aria-valuenow="4">
+</div>
+</label>
+<input type="text" id="test" value="baz"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-text-title-expected-blink.txt b/content/test/data/accessibility/accname/name-text-title-expected-blink.txt
new file mode 100644
index 0000000..20db99c
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-title-expected-blink.txt
@@ -0,0 +1 @@
+textField name='foo' nameFrom=title
diff --git a/content/test/data/accessibility/accname/name-text-title-value-expected-blink.txt b/content/test/data/accessibility/accname/name-text-title-value-expected-blink.txt
new file mode 100644
index 0000000..f21a1e04
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-title-value-expected-blink.txt
@@ -0,0 +1 @@
+textField name='silly' nameFrom=title
diff --git a/content/test/data/accessibility/accname/name-text-title-value.html b/content/test/data/accessibility/accname/name-text-title-value.html
new file mode 100644
index 0000000..a416e5b4
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-title-value.html
@@ -0,0 +1,9 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="text" id="test" title="silly" value="baz"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-text-title.html b/content/test/data/accessibility/accname/name-text-title.html
new file mode 100644
index 0000000..f3e6b93
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-title.html
@@ -0,0 +1,9 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="text" id="test" title="foo" />
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-text-with-label-expected-blink.txt b/content/test/data/accessibility/accname/name-text-with-label-expected-blink.txt
new file mode 100644
index 0000000..fb4152d
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-with-label-expected-blink.txt
@@ -0,0 +1 @@
+textField name='States:' nameFrom=relatedElement
diff --git a/content/test/data/accessibility/accname/name-text-with-label.html b/content/test/data/accessibility/accname/name-text-with-label.html
new file mode 100644
index 0000000..019cb07
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-with-label.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<label for="test">States:</label>
+<input type="text" id="test"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-text-with-value-labels-img-expected-blink.txt b/content/test/data/accessibility/accname/name-text-with-value-labels-img-expected-blink.txt
new file mode 100644
index 0000000..2afe6a1
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-with-value-labels-img-expected-blink.txt
@@ -0,0 +1 @@
+textField
diff --git a/content/test/data/accessibility/accname/name-text-with-value-labels-img-with-label-expected-blink.txt b/content/test/data/accessibility/accname/name-text-with-value-labels-img-with-label-expected-blink.txt
new file mode 100644
index 0000000..2afe6a1
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-with-value-labels-img-with-label-expected-blink.txt
@@ -0,0 +1 @@
+textField
diff --git a/content/test/data/accessibility/accname/name-text-with-value-labels-img-with-label.html b/content/test/data/accessibility/accname/name-text-with-value-labels-img-with-label.html
new file mode 100644
index 0000000..68717dd8
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-with-value-labels-img-with-label.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="text" value="peanuts" id="test">
+<img aria-labelledby="test" aria-label="label" src="foo.jpg"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/name-text-with-value-labels-img.html b/content/test/data/accessibility/accname/name-text-with-value-labels-img.html
new file mode 100644
index 0000000..eb1eb78
--- /dev/null
+++ b/content/test/data/accessibility/accname/name-text-with-value-labels-img.html
@@ -0,0 +1,10 @@
+<!--
+@BLINK-DENY:descri*
+-->
+<!doctype html>
+<html>
+<body>
+<input type="text" value="peanuts" id="test">
+<img aria-labelledby="test" src="foo.jpg"/>
+</body>
+</html>
diff --git a/content/test/data/accessibility/accname/test.png b/content/test/data/accessibility/accname/test.png
new file mode 100644
index 0000000..85cfa35f
--- /dev/null
+++ b/content/test/data/accessibility/accname/test.png
Binary files differ
diff --git a/extensions/browser/api/alarms/alarms_api_unittest.cc b/extensions/browser/api/alarms/alarms_api_unittest.cc
index 906b767..5de01d5 100644
--- a/extensions/browser/api/alarms/alarms_api_unittest.cc
+++ b/extensions/browser/api/alarms/alarms_api_unittest.cc
@@ -590,8 +590,9 @@
 }
 
 TEST_F(ExtensionAlarmsSchedulingTest, ReleasedExtensionPollsInfrequently) {
-  set_extension(
-      ExtensionBuilder("Test").SetLocation(Manifest::INTERNAL).Build());
+  set_extension(ExtensionBuilder("Test")
+                    .SetLocation(mojom::ManifestLocation::kInternal)
+                    .Build());
   test_clock_.SetNow(base::Time::FromJsTime(300000));
   CreateAlarm("[\"a\", {\"when\": 300010}]");
   CreateAlarm("[\"b\", {\"when\": 340000}]");
@@ -624,8 +625,9 @@
 }
 
 TEST_F(ExtensionAlarmsSchedulingTest, MinimumGranularity) {
-  set_extension(
-      ExtensionBuilder("Test").SetLocation(Manifest::INTERNAL).Build());
+  set_extension(ExtensionBuilder("Test")
+                    .SetLocation(mojom::ManifestLocation::kInternal)
+                    .Build());
   test_clock_.SetNow(base::Time::FromJsTime(0));
   CreateAlarm("[\"a\", {\"periodInMinutes\": 2}]");
   test_clock_.Advance(base::TimeDelta::FromSeconds(1));
@@ -652,8 +654,9 @@
   // CreateAlarm() uses extension_, so keep a ref of the old one around, and
   // repopulate extension_.
   scoped_refptr<const Extension> extension2(extension_ref());
-  set_extension(
-      ExtensionBuilder("Test").SetLocation(Manifest::INTERNAL).Build());
+  set_extension(ExtensionBuilder("Test")
+                    .SetLocation(mojom::ManifestLocation::kInternal)
+                    .Build());
 
   CreateAlarm("[\"b\", {\"periodInMinutes\": 2}]");
 
diff --git a/extensions/browser/api/bluetooth_socket/bluetooth_socket_api_unittest.cc b/extensions/browser/api/bluetooth_socket/bluetooth_socket_api_unittest.cc
index 7513e82..d1e80d3 100644
--- a/extensions/browser/api/bluetooth_socket/bluetooth_socket_api_unittest.cc
+++ b/extensions/browser/api/bluetooth_socket/bluetooth_socket_api_unittest.cc
@@ -52,7 +52,7 @@
                                     .Build())
                            .Build())
                   .Build())
-          .SetLocation(Manifest::COMPONENT)
+          .SetLocation(mojom::ManifestLocation::kComponent)
           .Build();
 
   ASSERT_TRUE(extension_with_socket_permitted);
diff --git a/extensions/browser/api/runtime/restart_after_delay_api_unittest.cc b/extensions/browser/api/runtime/restart_after_delay_api_unittest.cc
index 030edb0..07612a47 100644
--- a/extensions/browser/api/runtime/restart_after_delay_api_unittest.cc
+++ b/extensions/browser/api/runtime/restart_after_delay_api_unittest.cc
@@ -202,7 +202,7 @@
   // failure.
   scoped_refptr<const Extension> test_extension =
       ExtensionBuilder("Another App", ExtensionBuilder::Type::PLATFORM_APP)
-          .SetLocation(Manifest::INTERNAL)
+          .SetLocation(mojom::ManifestLocation::kInternal)
           .Build();
   RunRestartAfterDelayFunctionForExtention(
       "[5]", test_extension.get(), "Not the first extension to call this API.");
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc
index 8bda951..ca28d75 100644
--- a/extensions/browser/api/web_request/web_request_api.cc
+++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -33,6 +33,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/child_process_host.h"
@@ -751,10 +752,12 @@
               browser_context_));
   WebRequestProxyingURLLoaderFactory::StartProxying(
       browser_context, is_navigation ? -1 : render_process_id,
-      frame ? frame->GetRoutingID() : MSG_ROUTING_NONE, &request_id_generator_,
-      std::move(navigation_ui_data), std::move(navigation_id), ukm_source_id,
-      std::move(proxied_receiver), std::move(target_factory_remote),
-      std::move(header_client_receiver), proxies_.get(), type);
+      frame ? frame->GetRoutingID() : MSG_ROUTING_NONE,
+      frame ? frame->GetRenderViewHost()->GetRoutingID() : MSG_ROUTING_NONE,
+      &request_id_generator_, std::move(navigation_ui_data),
+      std::move(navigation_id), ukm_source_id, std::move(proxied_receiver),
+      std::move(target_factory_remote), std::move(header_client_receiver),
+      proxies_.get(), type);
   return true;
 }
 
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
index aaa4e49..48ad49a 100644
--- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
+++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
@@ -1102,6 +1102,7 @@
     content::BrowserContext* browser_context,
     int render_process_id,
     int frame_routing_id,
+    int view_routing_id,
     WebRequestAPI::RequestIDGenerator* request_id_generator,
     std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data,
     base::Optional<int64_t> navigation_id,
@@ -1115,6 +1116,7 @@
     : browser_context_(browser_context),
       render_process_id_(render_process_id),
       frame_routing_id_(frame_routing_id),
+      view_routing_id_(view_routing_id),
       request_id_generator_(request_id_generator),
       navigation_ui_data_(std::move(navigation_ui_data)),
       navigation_id_(std::move(navigation_id)),
@@ -1148,6 +1150,7 @@
     content::BrowserContext* browser_context,
     int render_process_id,
     int frame_routing_id,
+    int view_routing_id,
     WebRequestAPI::RequestIDGenerator* request_id_generator,
     std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data,
     base::Optional<int64_t> navigation_id,
@@ -1161,7 +1164,7 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   auto proxy = std::make_unique<WebRequestProxyingURLLoaderFactory>(
-      browser_context, render_process_id, frame_routing_id,
+      browser_context, render_process_id, frame_routing_id, view_routing_id,
       request_id_generator, std::move(navigation_ui_data),
       std::move(navigation_id), ukm_source_id, std::move(loader_receiver),
       std::move(target_factory_remote), std::move(header_client_receiver),
@@ -1192,7 +1195,7 @@
   // request ID may be the same as a previous request if the previous
   // request was redirected to a URL that required a different loader.
   const uint64_t web_request_id =
-      request_id_generator_->Generate(routing_id, request_id);
+      request_id_generator_->Generate(view_routing_id_, request_id);
 
   if (request_id) {
     // Only requests with a non-zero request ID can have their proxy
@@ -1208,7 +1211,7 @@
   auto result = requests_.emplace(
       web_request_id,
       std::make_unique<InProgressRequest>(
-          this, web_request_id, request_id, routing_id, frame_routing_id_,
+          this, web_request_id, request_id, view_routing_id_, frame_routing_id_,
           options, ukm_source_id_, request, traffic_annotation,
           std::move(loader_receiver), std::move(client)));
   result.first->second->Restart();
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
index 988a33e2..33a63836 100644
--- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
+++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
@@ -252,6 +252,7 @@
       content::BrowserContext* browser_context,
       int render_process_id,
       int frame_routing_id,
+      int view_routing_id,
       WebRequestAPI::RequestIDGenerator* request_id_generator,
       std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data,
       base::Optional<int64_t> navigation_id,
@@ -270,6 +271,7 @@
       content::BrowserContext* browser_context,
       int render_process_id,
       int frame_routing_id,
+      int view_routing_id,
       WebRequestAPI::RequestIDGenerator* request_id_generator,
       std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data,
       base::Optional<int64_t> navigation_id,
@@ -329,6 +331,7 @@
   content::BrowserContext* const browser_context_;
   const int render_process_id_;
   const int frame_routing_id_;
+  const int view_routing_id_;
   WebRequestAPI::RequestIDGenerator* const request_id_generator_;
   std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data_;
   base::Optional<int64_t> navigation_id_;
diff --git a/extensions/browser/event_router_unittest.cc b/extensions/browser/event_router_unittest.cc
index 24772c7b..a3e5663 100644
--- a/extensions/browser/event_router_unittest.cc
+++ b/extensions/browser/event_router_unittest.cc
@@ -119,7 +119,7 @@
   manifest->SetBoolean("background.persistent", persistent);
   builder.SetManifest(std::move(manifest));
   if (component)
-    builder.SetLocation(Manifest::Location::COMPONENT);
+    builder.SetLocation(mojom::ManifestLocation::kComponent);
 
   return builder.Build();
 }
diff --git a/extensions/browser/extension_host.cc b/extensions/browser/extension_host.cc
index 1a61bef..4613d5c 100644
--- a/extensions/browser/extension_host.cc
+++ b/extensions/browser/extension_host.cc
@@ -145,10 +145,6 @@
 }
 
 void ExtensionHost::Close() {
-  content::NotificationService::current()->Notify(
-      extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
-      content::Source<BrowserContext>(browser_context_),
-      content::Details<ExtensionHost>(this));
   for (auto& observer : observer_list_)
     observer.OnExtensionHostShouldClose(this);
 }
@@ -238,6 +234,9 @@
       extensions::NOTIFICATION_EXTENSION_PROCESS_TERMINATED,
       content::Source<BrowserContext>(browser_context_),
       content::Details<ExtensionHost>(this));
+
+  ProcessManager::Get(browser_context_)
+      ->NotifyExtensionProcessTerminated(extension_);
 }
 
 void ExtensionHost::DidStopLoading() {
diff --git a/extensions/browser/notification_types.h b/extensions/browser/notification_types.h
index ad1e4b1..af1a39e 100644
--- a/extensions/browser/notification_types.h
+++ b/extensions/browser/notification_types.h
@@ -84,12 +84,6 @@
   // TODO(https://crbug.com/1174741): Remove.
   NOTIFICATION_EXTENSION_HOST_DID_STOP_FIRST_LOAD,
 
-  // Sent by an ExtensionHost* when its render view requests closing through
-  // window.close(). The details are an ExtensionHost* and the source is a
-  // BrowserContext*.
-  // TODO(https://crbug.com/1174742): Remove.
-  NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
-
   // Sent when extension render process ends (whether it crashes or closes). The
   // details are an ExtensionHost* and the source is a BrowserContext*. Not sent
   // during browser shutdown.
diff --git a/extensions/browser/process_manager.cc b/extensions/browser/process_manager.cc
index 60f41c975..5c42b69 100644
--- a/extensions/browser/process_manager.cc
+++ b/extensions/browser/process_manager.cc
@@ -529,6 +529,13 @@
     DecrementLazyKeepaliveCount(extension->id(), activity_type, extra_data);
 }
 
+void ProcessManager::NotifyExtensionProcessTerminated(
+    const Extension* extension) {
+  DCHECK(extension);
+  for (auto& observer : observer_list_)
+    observer.OnExtensionProcessTerminated(extension);
+}
+
 ProcessManager::ActivitiesMultiset ProcessManager::GetLazyKeepaliveActivities(
     const Extension* extension) {
   ProcessManager::ActivitiesMultiset result;
diff --git a/extensions/browser/process_manager.h b/extensions/browser/process_manager.h
index 99f92711..73fb40f 100644
--- a/extensions/browser/process_manager.h
+++ b/extensions/browser/process_manager.h
@@ -147,6 +147,9 @@
                                    Activity::Type activity_type,
                                    const std::string& extra_data);
 
+  // Sends out notification to observers when the extension process is gone.
+  void NotifyExtensionProcessTerminated(const Extension* extension);
+
   // Methods to increment or decrement the ref-count of a specified service
   // worker with id |worker_id|.
   // The increment method returns the guid that needs to be passed to the
diff --git a/extensions/browser/process_manager_observer.h b/extensions/browser/process_manager_observer.h
index cb752c7..daf3ee4 100644
--- a/extensions/browser/process_manager_observer.h
+++ b/extensions/browser/process_manager_observer.h
@@ -52,6 +52,9 @@
 
   // Called when the observed ProcessManager is shutting down.
   virtual void OnProcessManagerShutdown(ProcessManager* manager) {}
+
+  // Called when the renderer process has gone.
+  virtual void OnExtensionProcessTerminated(const Extension* extension) {}
 };
 
 }  // namespace extensions
diff --git a/extensions/browser/sandboxed_unpacker.cc b/extensions/browser/sandboxed_unpacker.cc
index 5b7be8bf..883d111 100644
--- a/extensions/browser/sandboxed_unpacker.cc
+++ b/extensions/browser/sandboxed_unpacker.cc
@@ -387,7 +387,12 @@
                 "CRX_HEADER_VERIFIED_CONTENTS_UNCOMPRESSING_FAILURE")));
     return;
   }
-  if (!StoreVerifiedContentsInExtensionDir(result.value.value().byte_span()))
+  // Make a copy, since |result| may store data in shared memory, accessible by
+  // some other processes.
+  std::vector<uint8_t> verified_contents(
+      result.value.value().byte_span().begin(),
+      result.value.value().byte_span().end());
+  if (!StoreVerifiedContentsInExtensionDir(std::move(verified_contents)))
     return;
   Unpack(unzip_dir);
 }
diff --git a/extensions/browser/updater/update_data_provider_unittest.cc b/extensions/browser/updater/update_data_provider_unittest.cc
index 8d4d7f8..8a6da73 100644
--- a/extensions/browser/updater/update_data_provider_unittest.cc
+++ b/extensions/browser/updater/update_data_provider_unittest.cc
@@ -27,6 +27,8 @@
 #include "extensions/browser/updater/extension_installer.h"
 #include "extensions/common/extension_builder.h"
 
+using extensions::mojom::ManifestLocation;
+
 namespace extensions {
 
 namespace {
@@ -91,7 +93,7 @@
                     const std::string& version,
                     bool enabled,
                     int disable_reasons,
-                    Manifest::Location location) {
+                    ManifestLocation location) {
     AddExtension(extension_id, version, "", enabled, disable_reasons, location);
   }
 
@@ -100,7 +102,7 @@
                     const std::string& fingerprint,
                     bool enabled,
                     int disable_reasons,
-                    Manifest::Location location) {
+                    ManifestLocation location) {
     base::ScopedTempDir temp_dir;
     ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
     ASSERT_TRUE(base::PathExists(temp_dir.GetPath()));
@@ -162,9 +164,11 @@
   const std::string version = "0.1.2.3";
   const std::string fingerprint = "1.0123456789abcdef";
   AddExtension(kExtensionId1, version, true,
-               disable_reason::DisableReason::DISABLE_NONE, Manifest::INTERNAL);
+               disable_reason::DisableReason::DISABLE_NONE,
+               ManifestLocation::kInternal);
   AddExtension(kExtensionId2, version, fingerprint, true,
-               disable_reason::DisableReason::DISABLE_NONE, Manifest::INTERNAL);
+               disable_reason::DisableReason::DISABLE_NONE,
+               ManifestLocation::kInternal);
 
   ExtensionUpdateDataMap update_data;
   update_data[kExtensionId1] = {};
@@ -187,7 +191,8 @@
 
   const std::string version = "0.1.2.3";
   AddExtension(kExtensionId1, version, true,
-               disable_reason::DisableReason::DISABLE_NONE, Manifest::INTERNAL);
+               disable_reason::DisableReason::DISABLE_NONE,
+               ManifestLocation::kInternal);
 
   ExtensionUpdateDataMap update_data;
   update_data[kExtensionId1] = {};
@@ -209,7 +214,7 @@
   const std::string version = "0.1.2.3";
   AddExtension(kExtensionId1, version, true,
                disable_reason::DisableReason::DISABLE_NONE,
-               Manifest::EXTERNAL_PREF);
+               ManifestLocation::kExternalPref);
 
   ExtensionUpdateDataMap update_data;
   auto& info = update_data[kExtensionId1];
@@ -234,7 +239,7 @@
   const std::string version = "0.1.2.3";
   AddExtension(kExtensionId1, version, false,
                disable_reason::DisableReason::DISABLE_NONE,
-               Manifest::EXTERNAL_REGISTRY);
+               ManifestLocation::kExternalRegistry);
 
   ExtensionUpdateDataMap update_data;
   update_data[kExtensionId1] = {};
@@ -258,7 +263,7 @@
   const std::string version = "0.1.2.3";
   AddExtension(kExtensionId1, version, false,
                disable_reason::DisableReason::DISABLE_REASON_LAST,
-               Manifest::COMMAND_LINE);
+               ManifestLocation::kCommandLine);
 
   ExtensionUpdateDataMap update_data;
   update_data[kExtensionId1] = {};
@@ -283,7 +288,7 @@
   AddExtension(kExtensionId1, version, false,
                disable_reason::DisableReason::DISABLE_USER_ACTION |
                    disable_reason::DisableReason::DISABLE_CORRUPTED,
-               Manifest::EXTERNAL_POLICY_DOWNLOAD);
+               ManifestLocation::kExternalPolicyDownload);
 
   ExtensionUpdateDataMap update_data;
   update_data[kExtensionId1] = {};
@@ -312,7 +317,7 @@
                disable_reason::DisableReason::DISABLE_USER_ACTION |
                    disable_reason::DisableReason::DISABLE_CORRUPTED |
                    disable_reason::DisableReason::DISABLE_REASON_LAST,
-               Manifest::EXTERNAL_PREF_DOWNLOAD);
+               ManifestLocation::kExternalPrefDownload);
 
   ExtensionUpdateDataMap update_data;
   update_data[kExtensionId1] = {};
@@ -342,9 +347,10 @@
   const std::string version2 = "9.8.7.6";
   AddExtension(kExtensionId1, version1, true,
                disable_reason::DisableReason::DISABLE_NONE,
-               Manifest::EXTERNAL_REGISTRY);
+               ManifestLocation::kExternalRegistry);
   AddExtension(kExtensionId2, version2, true,
-               disable_reason::DisableReason::DISABLE_NONE, Manifest::UNPACKED);
+               disable_reason::DisableReason::DISABLE_NONE,
+               ManifestLocation::kUnpacked);
 
   ExtensionUpdateDataMap update_data;
   update_data[kExtensionId1] = {};
@@ -374,10 +380,10 @@
   const std::string version2 = "9.8.7.6";
   AddExtension(kExtensionId1, version1, false,
                disable_reason::DisableReason::DISABLE_CORRUPTED,
-               Manifest::INTERNAL);
+               ManifestLocation::kInternal);
   AddExtension(kExtensionId2, version2, true,
                disable_reason::DisableReason::DISABLE_NONE,
-               Manifest::EXTERNAL_PREF_DOWNLOAD);
+               ManifestLocation::kExternalPrefDownload);
 
   ExtensionUpdateDataMap update_data;
   update_data[kExtensionId1] = {};
@@ -410,7 +416,7 @@
   const std::string version = "0.1.2.3";
   AddExtension(kExtensionId1, version, true,
                disable_reason::DisableReason::DISABLE_NONE,
-               Manifest::COMPONENT);
+               ManifestLocation::kComponent);
 
   ExtensionUpdateDataMap update_data;
   update_data[kExtensionId1] = {};
@@ -441,10 +447,10 @@
   const std::string initial_version = "0.0.0.0";
   AddExtension(kExtensionId1, version1, true,
                disable_reason::DisableReason::DISABLE_NONE,
-               Manifest::EXTERNAL_COMPONENT);
+               ManifestLocation::kExternalComponent);
   AddExtension(kExtensionId2, version2, true,
                disable_reason::DisableReason::DISABLE_NONE,
-               Manifest::EXTERNAL_POLICY);
+               ManifestLocation::kExternalPolicy);
 
   ExtensionUpdateDataMap update_data;
   auto& info1 = update_data[kExtensionId1];
@@ -475,7 +481,8 @@
   // Verify that GetData propagtes install_immediately correctly to the crx
   // installer.
   AddExtension(kExtensionId1, "0.1.1.3", true,
-               disable_reason::DisableReason::DISABLE_NONE, Manifest::INTERNAL);
+               disable_reason::DisableReason::DISABLE_NONE,
+               ManifestLocation::kInternal);
 
   scoped_refptr<UpdateDataProvider> data_provider =
       base::MakeRefCounted<UpdateDataProvider>(browser_context());
diff --git a/extensions/common/BUILD.gn b/extensions/common/BUILD.gn
index 6f9bfa7..991535f 100644
--- a/extensions/common/BUILD.gn
+++ b/extensions/common/BUILD.gn
@@ -48,6 +48,7 @@
       "mojom/guest_view.mojom",
       "mojom/host_id.mojom",
       "mojom/keep_alive.mojom",
+      "mojom/manifest.mojom",
       "mojom/renderer.mojom",
       "mojom/run_location.mojom",
       "mojom/url_pattern_set.mojom",
diff --git a/extensions/common/component_extension_url_pattern_unittest.cc b/extensions/common/component_extension_url_pattern_unittest.cc
index b2e5b90..6fcab7e 100644
--- a/extensions/common/component_extension_url_pattern_unittest.cc
+++ b/extensions/common/component_extension_url_pattern_unittest.cc
@@ -22,7 +22,7 @@
   // the "<all_urls>" meta-pattern.
   auto all_urls = ExtensionBuilder("all urls")
                       .AddPermission("<all_urls>")
-                      .SetLocation(Manifest::COMPONENT)
+                      .SetLocation(mojom::ManifestLocation::kComponent)
                       .Build();
   std::string error;
   EXPECT_FALSE(all_urls->permissions_data()->CanAccessPage(
@@ -39,7 +39,7 @@
   // "<all_urls>" meta-pattern because it's whitelisted.
   auto all_urls = ExtensionBuilder("all urls")
                       .AddPermission("<all_urls>")
-                      .SetLocation(Manifest::COMPONENT)
+                      .SetLocation(mojom::ManifestLocation::kComponent)
                       .SetID(extension_misc::kChromeVoxExtensionId)
                       .Build();
   std::string error;
@@ -53,7 +53,7 @@
   // scheme is OK.
   auto chrome_urls = ExtensionBuilder("chrome urls")
                          .AddPermission(content::GetWebUIURLString("*/*"))
-                         .SetLocation(Manifest::COMPONENT)
+                         .SetLocation(mojom::ManifestLocation::kComponent)
                          .Build();
   std::string error;
   EXPECT_TRUE(chrome_urls->permissions_data()->CanAccessPage(
diff --git a/extensions/common/extension_builder.cc b/extensions/common/extension_builder.cc
index 2df43b21..1975fde 100644
--- a/extensions/common/extension_builder.cc
+++ b/extensions/common/extension_builder.cc
@@ -131,7 +131,8 @@
 };
 
 ExtensionBuilder::ExtensionBuilder()
-    : location_(Manifest::UNPACKED), flags_(Extension::NO_FLAGS) {}
+    : location_(mojom::ManifestLocation::kUnpacked),
+      flags_(Extension::NO_FLAGS) {}
 
 ExtensionBuilder::ExtensionBuilder(const std::string& name, Type type)
     : ExtensionBuilder() {
@@ -154,7 +155,7 @@
 
   std::string error;
   scoped_refptr<const Extension> extension = Extension::Create(
-      path_, location_,
+      path_, static_cast<Manifest::Location>(location_),
       manifest_data_ ? *manifest_data_->GetValue() : *manifest_value_, flags_,
       id_, &error);
 
@@ -211,7 +212,8 @@
   return *this;
 }
 
-ExtensionBuilder& ExtensionBuilder::SetLocation(Manifest::Location location) {
+ExtensionBuilder& ExtensionBuilder::SetLocation(
+    mojom::ManifestLocation location) {
   location_ = location;
   return *this;
 }
diff --git a/extensions/common/extension_builder.h b/extensions/common/extension_builder.h
index ac75c57..36a58f5 100644
--- a/extensions/common/extension_builder.h
+++ b/extensions/common/extension_builder.h
@@ -14,6 +14,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/strings/string_piece.h"
 #include "extensions/common/manifest.h"
+#include "extensions/common/mojom/manifest.mojom-shared.h"
 #include "extensions/common/value_builder.h"
 
 namespace extensions {
@@ -151,7 +152,7 @@
   ExtensionBuilder& SetPath(const base::FilePath& path);
 
   // Defaults to Manifest::UNPACKED.
-  ExtensionBuilder& SetLocation(Manifest::Location location);
+  ExtensionBuilder& SetLocation(mojom::ManifestLocation location);
 
   // Merge another manifest into the current manifest, with new keys taking
   // precedence.
@@ -180,7 +181,7 @@
   std::unique_ptr<base::DictionaryValue> manifest_value_;
 
   base::FilePath path_;
-  Manifest::Location location_;
+  mojom::ManifestLocation location_;
   int flags_;
   std::string id_;
 
diff --git a/extensions/common/manifest.cc b/extensions/common/manifest.cc
index 65abb4a..450f970 100644
--- a/extensions/common/manifest.cc
+++ b/extensions/common/manifest.cc
@@ -19,6 +19,7 @@
 #include "extensions/common/install_warning.h"
 #include "extensions/common/manifest_constants.h"
 #include "extensions/common/manifest_handler_helpers.h"
+#include "extensions/common/mojom/manifest.mojom-shared.h"
 
 namespace extensions {
 
@@ -178,6 +179,27 @@
   }
 };
 
+// Verifies that extensions::Manifest::Location and
+// extensions::mojom::ManifestLocation are kept in sync.
+// This static asserts will be removed after replacing all Manifest::Location
+// enum with ManifestLocation Mojo enum.
+#define STATIC_ASSERT_ENUM(native, mojo)                             \
+  static_assert(static_cast<int>(Manifest::Location::native) ==      \
+                    static_cast<int>(mojom::ManifestLocation::mojo), \
+                "mismatching enums: Manifest::Location::" #native)
+
+STATIC_ASSERT_ENUM(INVALID_LOCATION, kInvalidLocation);
+STATIC_ASSERT_ENUM(INTERNAL, kInternal);
+STATIC_ASSERT_ENUM(EXTERNAL_PREF, kExternalPref);
+STATIC_ASSERT_ENUM(EXTERNAL_REGISTRY, kExternalRegistry);
+STATIC_ASSERT_ENUM(UNPACKED, kUnpacked);
+STATIC_ASSERT_ENUM(COMPONENT, kComponent);
+STATIC_ASSERT_ENUM(EXTERNAL_PREF_DOWNLOAD, kExternalPrefDownload);
+STATIC_ASSERT_ENUM(EXTERNAL_POLICY_DOWNLOAD, kExternalPolicyDownload);
+STATIC_ASSERT_ENUM(COMMAND_LINE, kCommandLine);
+STATIC_ASSERT_ENUM(EXTERNAL_POLICY, kExternalPolicy);
+STATIC_ASSERT_ENUM(EXTERNAL_COMPONENT, kExternalComponent);
+
 }  // namespace
 
 // static
diff --git a/extensions/common/mojom/manifest.mojom b/extensions/common/mojom/manifest.mojom
new file mode 100644
index 0000000..af7bba2
--- /dev/null
+++ b/extensions/common/mojom/manifest.mojom
@@ -0,0 +1,46 @@
+// Copyright 2021 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.
+
+module extensions.mojom;
+
+// Historically, where an extension was loaded from, and whether an
+// extension's files were inside or outside of the profile's directory. In
+// modern usage, a Location can be thought of as the installation source:
+// whether an extension was explicitly installed by the user (through the
+// UI), or implicitly installed by other means. For example, enterprise
+// policy, being part of Chrome per se (but implemented as an extension), or
+// installed as a side effect of installing third party software.
+//
+// NOTE: These values are stored as integers in the preferences and used
+// in histograms so don't remove or reorder existing items.  Just append
+// to the end.
+enum ManifestLocation {
+  kInvalidLocation = 0,
+  kInternal = 1,  // A crx file from the internal Extensions directory. This
+                  // includes extensions explicitly installed by the user. It
+                  // also includes installed-by-default extensions that are not
+                  // part of Chrome itself (and thus not a kComponent), but are
+                  // part of a larger system (such as Chrome OS).
+  kExternalPref = 2,     // A crx file from an external directory (via prefs).
+  kExternalRegistry = 3, // A crx file from an external directory (via eg the
+                         // registry on Windows).
+  kUnpacked = 4,         // From loading an unpacked extension from the
+                         // extensions settings page.
+  kComponent = 5,        // An integral component of Chrome itself, which
+                         // happens to be implemented as an extension. We don't
+                         // show these in the management UI.
+  kExternalPrefDownload = 6,    // A crx file from an external directory (via
+                                // prefs), installed from an update URL.
+  kExternalPolicyDownload = 7,  // A crx file from an external directory (via
+                                // admin policies), installed from an update
+                                // URL.
+  kCommandLine = 8,         // --load-extension.
+  kExternalPolicy = 9,      // A crx file from an external directory (via admin
+                            // policies), cached locally and installed from the
+                            // cache.
+  kExternalComponent = 10,  // Similar to kComponent in that it's considered an
+                            // internal implementation detail of chrome, but
+                            // installed from an update URL like the *kDownload
+                            // ones.
+};
diff --git a/extensions/renderer/native_extension_bindings_system_unittest.cc b/extensions/renderer/native_extension_bindings_system_unittest.cc
index 92fe4e0..3ee9794 100644
--- a/extensions/renderer/native_extension_bindings_system_unittest.cc
+++ b/extensions/renderer/native_extension_bindings_system_unittest.cc
@@ -674,7 +674,7 @@
     connectable_extension =
         ExtensionBuilder()
             .SetManifest(manifest.Build())
-            .SetLocation(Manifest::INTERNAL)
+            .SetLocation(mojom::ManifestLocation::kInternal)
             .SetID(crx_file::id_util::GenerateId("connectable"))
             .Build();
   }
diff --git a/extensions/shell/browser/desktop_controller.h b/extensions/shell/browser/desktop_controller.h
index 5382cdf..efd8317 100644
--- a/extensions/shell/browser/desktop_controller.h
+++ b/extensions/shell/browser/desktop_controller.h
@@ -5,8 +5,14 @@
 #ifndef EXTENSIONS_SHELL_BROWSER_DESKTOP_CONTROLLER_H_
 #define EXTENSIONS_SHELL_BROWSER_DESKTOP_CONTROLLER_H_
 
+#include <memory>
+
 #include "ui/gfx/native_widget_types.h"
 
+namespace base {
+class RunLoop;
+}
+
 namespace extensions {
 class AppWindow;
 
@@ -25,8 +31,11 @@
   // we need a singleton somewhere).
   static DesktopController* instance();
 
-  // Runs the desktop and quits when finished.
-  virtual void Run() = 0;
+  // Forwarded from BrowserMainParts.
+  virtual void PreMainMessageLoopRun() {}
+  virtual void WillRunMainMessageLoop(
+      std::unique_ptr<base::RunLoop>& run_loop) {}
+  virtual void PostMainMessageLoopRun() {}
 
   // Attaches the window to our window hierarchy.
   virtual void AddAppWindow(AppWindow* app_window,
diff --git a/extensions/shell/browser/shell_browser_main_parts.cc b/extensions/shell/browser/shell_browser_main_parts.cc
index f385009..45fbd78 100644
--- a/extensions/shell/browser/shell_browser_main_parts.cc
+++ b/extensions/shell/browser/shell_browser_main_parts.cc
@@ -173,7 +173,7 @@
   return 0;
 }
 
-void ShellBrowserMainParts::PreMainMessageLoopRun() {
+int ShellBrowserMainParts::PreMainMessageLoopRun() {
   extensions_client_ = std::make_unique<ShellExtensionsClient>();
   ExtensionsClient::Set(extensions_client_.get());
 
@@ -255,17 +255,23 @@
   } else {
     browser_main_delegate_->Start(browser_context_.get());
   }
+
+  desktop_controller_->PreMainMessageLoopRun();
+
+  return content::RESULT_CODE_NORMAL_EXIT;
 }
 
-bool ShellBrowserMainParts::MainMessageLoopRun(int* result_code) {
-  if (!run_message_loop_)
-    return true;
-  desktop_controller_->Run();
-  *result_code = content::RESULT_CODE_NORMAL_EXIT;
-  return true;
+void ShellBrowserMainParts::WillRunMainMessageLoop(
+    std::unique_ptr<base::RunLoop>& run_loop) {
+  if (run_message_loop_)
+    desktop_controller_->WillRunMainMessageLoop(run_loop);
+  else
+    run_loop.reset();
 }
 
 void ShellBrowserMainParts::PostMainMessageLoopRun() {
+  desktop_controller_->PostMainMessageLoopRun();
+
   // Close apps before shutting down browser context and extensions system.
   desktop_controller_->CloseAppWindows();
 
diff --git a/extensions/shell/browser/shell_browser_main_parts.h b/extensions/shell/browser/shell_browser_main_parts.h
index 28a14bc..9c6c9c1 100644
--- a/extensions/shell/browser/shell_browser_main_parts.h
+++ b/extensions/shell/browser/shell_browser_main_parts.h
@@ -53,8 +53,9 @@
   void PreMainMessageLoopStart() override;
   void PostMainMessageLoopStart() override;
   int PreCreateThreads() override;
-  void PreMainMessageLoopRun() override;
-  bool MainMessageLoopRun(int* result_code) override;
+  int PreMainMessageLoopRun() override;
+  void WillRunMainMessageLoop(
+      std::unique_ptr<base::RunLoop>& run_loop) override;
   void PostMainMessageLoopRun() override;
   void PostDestroyThreads() override;
 
diff --git a/extensions/shell/browser/shell_desktop_controller_aura.cc b/extensions/shell/browser/shell_desktop_controller_aura.cc
index f1c33c60..b55237e 100644
--- a/extensions/shell/browser/shell_desktop_controller_aura.cc
+++ b/extensions/shell/browser/shell_desktop_controller_aura.cc
@@ -8,7 +8,6 @@
 #include <string>
 
 #include "base/check_op.h"
-#include "base/run_loop.h"
 #include "build/chromeos_buildflags.h"
 #include "components/keep_alive_registry/keep_alive_registry.h"
 #include "extensions/browser/app_window/app_window.h"
@@ -162,14 +161,16 @@
   extensions::AppWindowClient::Set(NULL);
 }
 
-void ShellDesktopControllerAura::Run() {
+void ShellDesktopControllerAura::PreMainMessageLoopRun() {
   KeepAliveRegistry::GetInstance()->AddObserver(this);
+}
 
-  base::RunLoop run_loop;
-  run_loop_ = &run_loop;
-  run_loop.Run();
-  run_loop_ = nullptr;
+void ShellDesktopControllerAura::WillRunMainMessageLoop(
+    std::unique_ptr<base::RunLoop>& run_loop) {
+  quit_when_idle_closure_ = run_loop->QuitWhenIdleClosure();
+}
 
+void ShellDesktopControllerAura::PostMainMessageLoopRun() {
   KeepAliveRegistry::GetInstance()->SetIsShuttingDown(true);
   KeepAliveRegistry::GetInstance()->RemoveObserver(this);
 }
@@ -399,9 +400,9 @@
 void ShellDesktopControllerAura::MaybeQuit() {
   // Quit if there are no app windows open and no keep-alives waiting for apps
   // to relaunch.  |run_loop_| may be null in tests.
-  if (run_loop_ && root_window_controllers_.empty() &&
+  if (quit_when_idle_closure_ && root_window_controllers_.empty() &&
       !KeepAliveRegistry::GetInstance()->IsKeepingAlive()) {
-    run_loop_->QuitWhenIdle();
+    std::move(quit_when_idle_closure_).Run();
   }
 }
 
diff --git a/extensions/shell/browser/shell_desktop_controller_aura.h b/extensions/shell/browser/shell_desktop_controller_aura.h
index f9bd47b..ca703bc 100644
--- a/extensions/shell/browser/shell_desktop_controller_aura.h
+++ b/extensions/shell/browser/shell_desktop_controller_aura.h
@@ -8,6 +8,7 @@
 #include <map>
 #include <memory>
 
+#include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "build/build_config.h"
@@ -28,10 +29,6 @@
 class WindowTreeHost;
 }  // namespace aura
 
-namespace base {
-class RunLoop;
-}  // namespace base
-
 namespace content {
 class BrowserContext;
 }  // namespace content
@@ -78,7 +75,10 @@
   ~ShellDesktopControllerAura() override;
 
   // DesktopController:
-  void Run() override;
+  void PreMainMessageLoopRun() override;
+  void WillRunMainMessageLoop(
+      std::unique_ptr<base::RunLoop>& run_loop) override;
+  void PostMainMessageLoopRun() override;
   void AddAppWindow(AppWindow* app_window, gfx::NativeWindow window) override;
   void CloseAppWindows() override;
 
@@ -174,8 +174,8 @@
   // NativeAppWindow::Close() deletes the AppWindow.
   std::list<AppWindow*> app_windows_;
 
-  // A pointer to the main message loop if this is run by ShellBrowserMainParts.
-  base::RunLoop* run_loop_ = nullptr;
+  // Non-null between WillRunMainMessageLoop() and MaybeQuit().
+  base::OnceClosure quit_when_idle_closure_;
 
   DISALLOW_COPY_AND_ASSIGN(ShellDesktopControllerAura);
 };
diff --git a/extensions/shell/browser/shell_desktop_controller_aura_browsertest.cc b/extensions/shell/browser/shell_desktop_controller_aura_browsertest.cc
index 58174ce..4a05744f 100644
--- a/extensions/shell/browser/shell_desktop_controller_aura_browsertest.cc
+++ b/extensions/shell/browser/shell_desktop_controller_aura_browsertest.cc
@@ -4,8 +4,11 @@
 
 #include "extensions/shell/browser/shell_desktop_controller_aura.h"
 
+#include <memory>
+
 #include "base/bind.h"
 #include "base/macros.h"
+#include "base/run_loop.h"
 #include "base/task/post_task.h"
 #include "base/test/bind.h"
 #include "base/time/time.h"
@@ -26,6 +29,11 @@
   ShellDesktopControllerAuraBrowserTest() = default;
   ~ShellDesktopControllerAuraBrowserTest() override = default;
 
+  ShellDesktopControllerAuraBrowserTest(
+      const ShellDesktopControllerAuraBrowserTest&) = delete;
+  ShellDesktopControllerAuraBrowserTest& operator=(
+      const ShellDesktopControllerAuraBrowserTest&) = delete;
+
   // Loads and launches a platform app that opens an app window.
   void LoadAndLaunchApp() {
     ASSERT_FALSE(app_);
@@ -62,11 +70,20 @@
     ShellApiTest::TearDownOnMainThread();
   }
 
-  ShellDesktopControllerAura* desktop_controller_ = nullptr;
+  void RunDesktopController() {
+    desktop_controller_->PreMainMessageLoopRun();
+
+    auto run_loop = std::make_unique<base::RunLoop>();
+    desktop_controller_->WillRunMainMessageLoop(run_loop);
+    run_loop->Run();
+
+    desktop_controller_->PostMainMessageLoopRun();
+  }
+
   scoped_refptr<const Extension> app_;
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(ShellDesktopControllerAuraBrowserTest);
+  ShellDesktopControllerAura* desktop_controller_ = nullptr;
 };
 
 // Test that closing the app window stops the DesktopController.
@@ -88,7 +105,7 @@
       }));
 
   // Start DesktopController. It should run until the last app window closes.
-  desktop_controller_->Run();
+  RunDesktopController();
   EXPECT_TRUE(test_succeeded)
       << "DesktopController quit before test completed.";
 }
@@ -131,7 +148,7 @@
             base::TimeDelta::FromMilliseconds(500));
       }));
 
-  desktop_controller_->Run();
+  RunDesktopController();
   EXPECT_TRUE(test_succeeded)
       << "DesktopController quit before test completed.";
 }
@@ -171,7 +188,7 @@
             base::TimeDelta::FromMilliseconds(500));
       }));
 
-  desktop_controller_->Run();
+  RunDesktopController();
   EXPECT_TRUE(test_succeeded)
       << "DesktopController quit before test completed.";
 }
diff --git a/extensions/shell/browser/shell_desktop_controller_mac.h b/extensions/shell/browser/shell_desktop_controller_mac.h
index bd08b3ee..8d7a3ad 100644
--- a/extensions/shell/browser/shell_desktop_controller_mac.h
+++ b/extensions/shell/browser/shell_desktop_controller_mac.h
@@ -23,7 +23,6 @@
   ~ShellDesktopControllerMac() override;
 
   // DesktopController:
-  void Run() override;
   void AddAppWindow(AppWindow* app_window, gfx::NativeWindow window) override;
   void CloseAppWindows() override;
 
diff --git a/extensions/shell/browser/shell_desktop_controller_mac.mm b/extensions/shell/browser/shell_desktop_controller_mac.mm
index 80e4d3a..d15f009 100644
--- a/extensions/shell/browser/shell_desktop_controller_mac.mm
+++ b/extensions/shell/browser/shell_desktop_controller_mac.mm
@@ -23,11 +23,6 @@
   CloseAppWindows();
 }
 
-void ShellDesktopControllerMac::Run() {
-  base::RunLoop run_loop;
-  run_loop.Run();
-}
-
 void ShellDesktopControllerMac::AddAppWindow(AppWindow* app_window,
                                              gfx::NativeWindow window) {
   app_window_ = app_window;
diff --git a/fuchsia/engine/browser/web_engine_browser_main_parts.cc b/fuchsia/engine/browser/web_engine_browser_main_parts.cc
index 7e526f4..62c0410 100644
--- a/fuchsia/engine/browser/web_engine_browser_main_parts.cc
+++ b/fuchsia/engine/browser/web_engine_browser_main_parts.cc
@@ -20,6 +20,7 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/main_function_params.h"
+#include "content/public/common/result_codes.h"
 #include "fuchsia/base/legacymetrics_client.h"
 #include "fuchsia/engine/browser/context_impl.h"
 #include "fuchsia/engine/browser/media_resource_provider_service.h"
@@ -70,7 +71,7 @@
   base::ImportantFileWriterCleaner::GetInstance().Initialize();
 }
 
-void WebEngineBrowserMainParts::PreMainMessageLoopRun() {
+int WebEngineBrowserMainParts::PreMainMessageLoopRun() {
   DCHECK(!screen_);
 
   // Watch for changes to the user's locale setting.
@@ -147,15 +148,16 @@
 
   // Make sure temporary files associated with this process are cleaned up.
   base::ImportantFileWriterCleaner::GetInstance().Start();
+
+  return content::RESULT_CODE_NORMAL_EXIT;
 }
 
-void WebEngineBrowserMainParts::PreDefaultMainMessageLoopRun(
-    base::OnceClosure quit_closure) {
-  quit_closure_ = std::move(quit_closure);
-}
-
-bool WebEngineBrowserMainParts::MainMessageLoopRun(int* result_code) {
-  return !run_message_loop_;
+void WebEngineBrowserMainParts::WillRunMainMessageLoop(
+    std::unique_ptr<base::RunLoop>& run_loop) {
+  if (run_message_loop_)
+    quit_closure_ = run_loop->QuitClosure();
+  else
+    run_loop.reset();
 }
 
 void WebEngineBrowserMainParts::PostMainMessageLoopRun() {
diff --git a/fuchsia/engine/browser/web_engine_browser_main_parts.h b/fuchsia/engine/browser/web_engine_browser_main_parts.h
index be584748..3753f64 100644
--- a/fuchsia/engine/browser/web_engine_browser_main_parts.h
+++ b/fuchsia/engine/browser/web_engine_browser_main_parts.h
@@ -53,9 +53,9 @@
 
   // content::BrowserMainParts overrides.
   void PostEarlyInitialization() override;
-  void PreMainMessageLoopRun() override;
-  void PreDefaultMainMessageLoopRun(base::OnceClosure quit_closure) override;
-  bool MainMessageLoopRun(int* result_code) override;
+  int PreMainMessageLoopRun() override;
+  void WillRunMainMessageLoop(
+      std::unique_ptr<base::RunLoop>& run_loop) override;
   void PostMainMessageLoopRun() override;
 
   ContextImpl* context_for_test() const { return context_service_.get(); }
diff --git a/google_apis/gaia/gaia_constants.cc b/google_apis/gaia/gaia_constants.cc
index 25aceb5c..b54f42a 100644
--- a/google_apis/gaia/gaia_constants.cc
+++ b/google_apis/gaia/gaia_constants.cc
@@ -130,8 +130,10 @@
 const char kNearbyShareOAuth2Scope[] =
     "https://www.googleapis.com/auth/nearbysharing-pa";
 
-// OAuth2 scope for access to GCM account tracker.
+// OAuth2 scopes for access to GCM account tracker.
 const char kGCMGroupServerOAuth2Scope[] = "https://www.googleapis.com/auth/gcm";
+const char kGCMCheckinServerOAuth2Scope[] =
+    "https://www.googleapis.com/auth/android_checkin";
 
 // OAuth2 scope for access to readonly Chrome web store.
 const char kChromeWebstoreOAuth2Scope[] =
diff --git a/google_apis/gaia/gaia_constants.h b/google_apis/gaia/gaia_constants.h
index 66521fb..633d735b0 100644
--- a/google_apis/gaia/gaia_constants.h
+++ b/google_apis/gaia/gaia_constants.h
@@ -54,6 +54,7 @@
 extern const char kAssistantOAuth2Scope[];
 extern const char kNearbyShareOAuth2Scope[];
 extern const char kGCMGroupServerOAuth2Scope[];
+extern const char kGCMCheckinServerOAuth2Scope[];
 extern const char kChromeWebstoreOAuth2Scope[];
 
 // Used with uber auth tokens when needed.
diff --git a/google_apis/gaia/oauth2_access_token_fetcher_impl.cc b/google_apis/gaia/oauth2_access_token_fetcher_impl.cc
index d407f73..9226d55c 100644
--- a/google_apis/gaia/oauth2_access_token_fetcher_impl.cc
+++ b/google_apis/gaia/oauth2_access_token_fetcher_impl.cc
@@ -138,6 +138,7 @@
 OAuth2AccessTokenFetcherImpl::~OAuth2AccessTokenFetcherImpl() = default;
 
 void OAuth2AccessTokenFetcherImpl::CancelRequest() {
+  state_ = GET_ACCESS_TOKEN_CANCELED;
   url_loader_.reset();
 }
 
@@ -274,7 +275,7 @@
 
 void OAuth2AccessTokenFetcherImpl::OnURLLoadComplete(
     std::unique_ptr<std::string> response_body) {
-  CHECK(state_ == GET_ACCESS_TOKEN_STARTED);
+  CHECK_EQ(state_, GET_ACCESS_TOKEN_STARTED);
   EndGetAccessToken(std::move(response_body));
 }
 
diff --git a/google_apis/gaia/oauth2_access_token_fetcher_impl.h b/google_apis/gaia/oauth2_access_token_fetcher_impl.h
index 07b5e17..55448bb 100644
--- a/google_apis/gaia/oauth2_access_token_fetcher_impl.h
+++ b/google_apis/gaia/oauth2_access_token_fetcher_impl.h
@@ -74,6 +74,7 @@
     INITIAL,
     GET_ACCESS_TOKEN_STARTED,
     GET_ACCESS_TOKEN_DONE,
+    GET_ACCESS_TOKEN_CANCELED,
     ERROR_STATE,
   };
 
diff --git a/google_apis/gaia/oauth2_access_token_fetcher_impl_unittest.cc b/google_apis/gaia/oauth2_access_token_fetcher_impl_unittest.cc
index 2380e5d..ba33d32 100644
--- a/google_apis/gaia/oauth2_access_token_fetcher_impl_unittest.cc
+++ b/google_apis/gaia/oauth2_access_token_fetcher_impl_unittest.cc
@@ -159,6 +159,15 @@
   base::RunLoop().RunUntilIdle();
 }
 
+TEST_F(OAuth2AccessTokenFetcherImplTest, CancelOngoingRequest) {
+  SetupGetAccessToken(net::OK, net::HTTP_OK, kValidTokenResponse);
+  // `OnGetTokenSuccess()` should not be called.
+  EXPECT_CALL(consumer_, OnGetTokenSuccess(_)).Times(0);
+  fetcher_->Start("client_id", "client_secret", ScopeList());
+  fetcher_->CancelRequest();
+  base::RunLoop().RunUntilIdle();
+}
+
 TEST_F(OAuth2AccessTokenFetcherImplTest, MakeGetAccessTokenBodyNoScope) {
   std::string body =
       "client_id=cid1&"
diff --git a/google_apis/gcm/engine/heartbeat_manager.cc b/google_apis/gcm/engine/heartbeat_manager.cc
index 14aa987e..da36c09 100644
--- a/google_apis/gcm/engine/heartbeat_manager.cc
+++ b/google_apis/gcm/engine/heartbeat_manager.cc
@@ -62,7 +62,7 @@
 
 HeartbeatManager::~HeartbeatManager() {
   // Stop listening for system suspend and resume events.
-  base::PowerMonitor::RemoveObserver(this);
+  base::PowerMonitor::RemovePowerSuspendObserver(this);
 }
 
 void HeartbeatManager::Start(
@@ -74,7 +74,7 @@
   trigger_reconnect_callback_ = trigger_reconnect_callback;
 
   // Listen for system suspend and resume events.
-  base::PowerMonitor::AddObserver(this);
+  base::PowerMonitor::AddPowerSuspendObserver(this);
 
   // Calculated the heartbeat interval just before we start the timer.
   UpdateHeartbeatInterval();
@@ -90,7 +90,7 @@
   heartbeat_timer_->Stop();
   waiting_for_ack_ = false;
 
-  base::PowerMonitor::RemoveObserver(this);
+  base::PowerMonitor::RemovePowerSuspendObserver(this);
 }
 
 void HeartbeatManager::OnHeartbeatAcked() {
diff --git a/google_apis/gcm/engine/heartbeat_manager.h b/google_apis/gcm/engine/heartbeat_manager.h
index 34b849d..6034497 100644
--- a/google_apis/gcm/engine/heartbeat_manager.h
+++ b/google_apis/gcm/engine/heartbeat_manager.h
@@ -26,7 +26,7 @@
 
 // A heartbeat management class, capable of sending and handling heartbeat
 // receipt/failures and triggering reconnection as necessary.
-class GCM_EXPORT HeartbeatManager : public base::PowerObserver {
+class GCM_EXPORT HeartbeatManager : public base::PowerSuspendObserver {
  public:
   using ReconnectCallback =
       base::RepeatingCallback<void(ConnectionFactory::ConnectionResetReason)>;
@@ -69,7 +69,7 @@
   // Updates the timer used for scheduling heartbeats.
   void UpdateHeartbeatTimer(std::unique_ptr<base::RetainingOneShotTimer> timer);
 
-  // base::PowerObserver override.
+  // base::PowerSuspendObserver override.
   void OnSuspend() override;
   void OnResume() override;
 
diff --git a/gpu/command_buffer/service/image_reader_gl_owner.cc b/gpu/command_buffer/service/image_reader_gl_owner.cc
index 03eec0d..158c033 100644
--- a/gpu/command_buffer/service/image_reader_gl_owner.cc
+++ b/gpu/command_buffer/service/image_reader_gl_owner.cc
@@ -346,6 +346,11 @@
   if (!buffer)
     return nullptr;
 
+  // TODO(1179206): We suspect that buffer is already freed here and it causes
+  // crash later. Trying to crash earlier.
+  base::AndroidHardwareBufferCompat::GetInstance().Acquire(buffer);
+  base::AndroidHardwareBufferCompat::GetInstance().Release(buffer);
+
   return std::make_unique<ScopedHardwareBufferImpl>(
       weak_factory_.GetWeakPtr(), current_image_ref_->image(),
       base::android::ScopedHardwareBufferHandle::Create(buffer),
diff --git a/gpu/ipc/service/gpu_watchdog_thread.cc b/gpu/ipc/service/gpu_watchdog_thread.cc
index 5c059d06..ff971e478 100644
--- a/gpu/ipc/service/gpu_watchdog_thread.cc
+++ b/gpu/ipc/service/gpu_watchdog_thread.cc
@@ -94,7 +94,7 @@
   Stop();  // stop the watchdog thread
 
   base::CurrentThread::Get()->RemoveTaskObserver(this);
-  base::PowerMonitor::RemoveObserver(this);
+  base::PowerMonitor::RemovePowerSuspendObserver(this);
   GpuWatchdogHistogram(GpuWatchdogThreadEvent::kGpuWatchdogEnd);
 #if defined(OS_WIN)
   if (watched_thread_handle_)
@@ -285,7 +285,7 @@
   DCHECK(watchdog_thread_task_runner_->BelongsToCurrentThread());
   DCHECK(base::PowerMonitor::IsInitialized());
 
-  base::PowerMonitor::AddObserver(this);
+  base::PowerMonitor::AddPowerSuspendObserver(this);
   is_power_observer_added_ = true;
 }
 
diff --git a/gpu/ipc/service/gpu_watchdog_thread.h b/gpu/ipc/service/gpu_watchdog_thread.h
index f0dbe28..ad714a7 100644
--- a/gpu/ipc/service/gpu_watchdog_thread.h
+++ b/gpu/ipc/service/gpu_watchdog_thread.h
@@ -76,10 +76,11 @@
 
 // A thread that intermitently sends tasks to a group of watched message loops
 // and deliberately crashes if one of them does not respond after a timeout.
-class GPU_IPC_SERVICE_EXPORT GpuWatchdogThread : public base::Thread,
-                                                 public base::PowerObserver,
-                                                 public base::TaskObserver,
-                                                 public gl::ProgressReporter {
+class GPU_IPC_SERVICE_EXPORT GpuWatchdogThread
+    : public base::Thread,
+      public base::PowerSuspendObserver,
+      public base::TaskObserver,
+      public gl::ProgressReporter {
  public:
   static std::unique_ptr<GpuWatchdogThread> Create(bool start_backgrounded);
 
@@ -135,7 +136,7 @@
                        bool was_blocked_or_low_priority) override;
   void DidProcessTask(const base::PendingTask& pending_task) override;
 
-  // Implements base::PowerObserver.
+  // Implements base::PowerSuspendObserver.
   void OnSuspend() override;
   void OnResume() override;
 
diff --git a/headless/lib/browser/headless_browser_main_parts.cc b/headless/lib/browser/headless_browser_main_parts.cc
index 06c4754c..b0e4bb8 100644
--- a/headless/lib/browser/headless_browser_main_parts.cc
+++ b/headless/lib/browser/headless_browser_main_parts.cc
@@ -4,6 +4,7 @@
 
 #include "headless/lib/browser/headless_browser_main_parts.h"
 
+#include "content/public/common/result_codes.h"
 #include "headless/app/headless_shell_switches.h"
 #include "headless/lib/browser/headless_browser_context_impl.h"
 #include "headless/lib/browser/headless_browser_impl.h"
@@ -34,7 +35,7 @@
 
 HeadlessBrowserMainParts::~HeadlessBrowserMainParts() = default;
 
-void HeadlessBrowserMainParts::PreMainMessageLoopRun() {
+int HeadlessBrowserMainParts::PreMainMessageLoopRun() {
 #if defined(HEADLESS_USE_PREFS)
   CreatePrefService();
 #endif
@@ -50,15 +51,16 @@
     delete parameters_.ui_task;
     run_message_loop_ = false;
   }
+
+  return content::RESULT_CODE_NORMAL_EXIT;
 }
 
-void HeadlessBrowserMainParts::PreDefaultMainMessageLoopRun(
-    base::OnceClosure quit_closure) {
-  quit_main_message_loop_ = std::move(quit_closure);
-}
-
-bool HeadlessBrowserMainParts::MainMessageLoopRun(int* result_code) {
-  return !run_message_loop_;
+void HeadlessBrowserMainParts::WillRunMainMessageLoop(
+    std::unique_ptr<base::RunLoop>& run_loop) {
+  if (run_message_loop_)
+    quit_main_message_loop_ = run_loop->QuitClosure();
+  else
+    run_loop.reset();
 }
 
 void HeadlessBrowserMainParts::PostMainMessageLoopRun() {
diff --git a/headless/lib/browser/headless_browser_main_parts.h b/headless/lib/browser/headless_browser_main_parts.h
index e1a531c9..2ecf49b 100644
--- a/headless/lib/browser/headless_browser_main_parts.h
+++ b/headless/lib/browser/headless_browser_main_parts.h
@@ -30,9 +30,9 @@
   ~HeadlessBrowserMainParts() override;
 
   // content::BrowserMainParts implementation:
-  void PreMainMessageLoopRun() override;
-  void PreDefaultMainMessageLoopRun(base::OnceClosure quit_closure) override;
-  bool MainMessageLoopRun(int* result_code) override;
+  int PreMainMessageLoopRun() override;
+  void WillRunMainMessageLoop(
+      std::unique_ptr<base::RunLoop>& run_loop) override;
   void PostMainMessageLoopRun() override;
 #if defined(OS_MAC)
   void PreMainMessageLoopStart() override;
diff --git a/ios/build/tools/setup-gn.py b/ios/build/tools/setup-gn.py
index ddf657c..b674426 100755
--- a/ios/build/tools/setup-gn.py
+++ b/ios/build/tools/setup-gn.py
@@ -359,6 +359,9 @@
   parser.add_argument(
       '--build-dir', default='out',
       help='path where the build should be created (default: %(default)s)')
+  parser.add_argument(
+      '--no-xcode-project', action='store_true', default=False,
+      help='do not generate the build directory with XCode project')
   args = parser.parse_args(args)
 
   # Load configuration (first global and then any user overrides).
@@ -396,9 +399,10 @@
   if not os.path.isdir(out_dir):
     os.makedirs(out_dir)
 
-  GenerateXcodeProject(gn_path, args.root, out_dir, settings)
+  if not args.no_xcode_project:
+    GenerateXcodeProject(gn_path, args.root, out_dir, settings)
+    CreateLLDBInitFile(args.root, out_dir, settings)
   GenerateGnBuildRules(gn_path, args.root, out_dir, settings)
-  CreateLLDBInitFile(args.root, out_dir, settings)
 
 
 if __name__ == '__main__':
diff --git a/ios/chrome/app/resources/BUILD.gn b/ios/chrome/app/resources/BUILD.gn
index ee75e039..0870cab 100644
--- a/ios/chrome/app/resources/BUILD.gn
+++ b/ios/chrome/app/resources/BUILD.gn
@@ -59,7 +59,7 @@
   sources = [
     "$root_gen_dir/components/components_resources.pak",
     "$root_gen_dir/components/dev_ui_components_resources.pak",
-    "$root_gen_dir/components/sync_driver_resources.pak",
+    "$root_gen_dir/components/sync_driver_sync_internals_resources.pak",
     "$root_gen_dir/ios/chrome/ios_resources.pak",
     "$root_gen_dir/ios/web/ios_web_resources.pak",
     "$root_gen_dir/mojo/public/js/mojo_bindings_resources.pak",
@@ -70,7 +70,7 @@
   deps = [
     ":ios_resources",
     "//components/resources",
-    "//components/sync/driver:resources",
+    "//components/sync/driver/resources",
     "//ios/web:resources",
     "//mojo/public/js:resources",
     "//net:net_resources",
diff --git a/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.h b/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.h
index 8ebd3d8..a03050c9 100644
--- a/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.h
+++ b/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.h
@@ -62,6 +62,7 @@
   std::string GetApplicationLocale() override;
   bool GetBrand(std::string* brand_code) override;
   metrics::SystemProfileProto::Channel GetChannel() override;
+  bool IsExtendedStableChannel() override;
   std::string GetVersionString() override;
   void CollectFinalMetricsForLog(base::OnceClosure done_callback) override;
   std::unique_ptr<metrics::MetricsLogUploader> CreateUploader(
diff --git a/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm b/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm
index a4f9803..35a07a8 100644
--- a/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm
+++ b/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm
@@ -205,6 +205,10 @@
   return metrics::AsProtobufChannel(::GetChannel());
 }
 
+bool IOSChromeMetricsServiceClient::IsExtendedStableChannel() {
+  return false;  // Not supported on iOS.
+}
+
 std::string IOSChromeMetricsServiceClient::GetVersionString() {
   return metrics::GetVersionString();
 }
diff --git a/ios/components/webui/sync_internals/BUILD.gn b/ios/components/webui/sync_internals/BUILD.gn
index 40a88be..1219d0e1 100644
--- a/ios/components/webui/sync_internals/BUILD.gn
+++ b/ios/components/webui/sync_internals/BUILD.gn
@@ -15,12 +15,13 @@
     "//components/browser_sync",
     "//components/resources",
     "//components/sync",
-    "//components/sync/driver:resources",
+    "//components/sync/driver/resources",
     "//components/version_info:version_info",
     "//ios/components/webui:provider",
     "//ios/components/webui:url_constants",
     "//ios/web/public",
     "//ios/web/public/thread",
     "//ios/web/public/webui",
+    "//ui/base:base",
   ]
 }
diff --git a/ios/components/webui/sync_internals/DEPS b/ios/components/webui/sync_internals/DEPS
index 064a9dc..199a9d97 100644
--- a/ios/components/webui/sync_internals/DEPS
+++ b/ios/components/webui/sync_internals/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
   "+components/grit",
   "+components/sync",
+  "+ui/base",
 ]
diff --git a/ios/components/webui/sync_internals/sync_internals_ui.mm b/ios/components/webui/sync_internals/sync_internals_ui.mm
index 182ddc3..daa359d8 100644
--- a/ios/components/webui/sync_internals/sync_internals_ui.mm
+++ b/ios/components/webui/sync_internals/sync_internals_ui.mm
@@ -6,7 +6,8 @@
 
 #include <memory>
 
-#include "components/grit/sync_driver_resources.h"
+#include "components/grit/sync_driver_sync_internals_resources.h"
+#include "components/grit/sync_driver_sync_internals_resources_map.h"
 #include "components/sync/driver/sync_internals_util.h"
 #include "ios/components/webui/sync_internals/sync_internals_message_handler.h"
 #include "ios/components/webui/web_ui_url_constants.h"
@@ -14,6 +15,7 @@
 #include "ios/web/public/web_state.h"
 #include "ios/web/public/webui/web_ui_ios.h"
 #include "ios/web/public/webui/web_ui_ios_data_source.h"
+#include "ui/base/webui/resource_path.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -26,28 +28,10 @@
       web::WebUIIOSDataSource::Create(kChromeUISyncInternalsHost);
 
   source->UseStringsJs();
-  source->AddResourcePath(syncer::sync_ui_util::kSyncIndexJS,
-                          IDR_SYNC_DRIVER_SYNC_INTERNALS_INDEX_JS);
-  source->AddResourcePath(syncer::sync_ui_util::kChromeSyncJS,
-                          IDR_SYNC_DRIVER_SYNC_INTERNALS_CHROME_SYNC_JS);
-  source->AddResourcePath(syncer::sync_ui_util::kSyncLogJS,
-                          IDR_SYNC_DRIVER_SYNC_INTERNALS_SYNC_LOG_JS);
-  source->AddResourcePath(syncer::sync_ui_util::kSyncNodeBrowserJS,
-                          IDR_SYNC_DRIVER_SYNC_INTERNALS_SYNC_NODE_BROWSER_JS);
-  source->AddResourcePath(syncer::sync_ui_util::kSyncSearchJS,
-                          IDR_SYNC_DRIVER_SYNC_INTERNALS_SYNC_SEARCH_JS);
-  source->AddResourcePath(syncer::sync_ui_util::kAboutJS,
-                          IDR_SYNC_DRIVER_SYNC_INTERNALS_ABOUT_JS);
-  source->AddResourcePath(syncer::sync_ui_util::kDataJS,
-                          IDR_SYNC_DRIVER_SYNC_INTERNALS_DATA_JS);
-  source->AddResourcePath(syncer::sync_ui_util::kEventsJS,
-                          IDR_SYNC_DRIVER_SYNC_INTERNALS_EVENTS_JS);
-  source->AddResourcePath(syncer::sync_ui_util::kSearchJS,
-                          IDR_SYNC_DRIVER_SYNC_INTERNALS_SEARCH_JS);
-  source->AddResourcePath(syncer::sync_ui_util::kUserEventsJS,
-                          IDR_SYNC_DRIVER_SYNC_INTERNALS_USER_EVENTS_JS);
-  source->AddResourcePath(syncer::sync_ui_util::kTrafficLogJS,
-                          IDR_SYNC_DRIVER_SYNC_INTERNALS_TRAFFIC_LOG_JS);
+  for (size_t i = 0; i < kSyncDriverSyncInternalsResourcesSize; i++) {
+    const webui::ResourcePath path = kSyncDriverSyncInternalsResources[i];
+    source->AddResourcePath(path.path, path.id);
+  }
   source->SetDefaultResource(IDR_SYNC_DRIVER_SYNC_INTERNALS_INDEX_HTML);
   return source;
 }
diff --git a/ios/web_view/BUILD.gn b/ios/web_view/BUILD.gn
index 11a813ad..2e3298e0 100644
--- a/ios/web_view/BUILD.gn
+++ b/ios/web_view/BUILD.gn
@@ -521,13 +521,13 @@
   visibility = [ ":web_view_resources" ]
   deps = [
     "//components/resources:components_resources",
-    "//components/sync/driver:resources",
+    "//components/sync/driver/resources",
     "//ios/web:resources",
     "//ui/resources",
   ]
   sources = [
     "$root_gen_dir/components/components_resources.pak",
-    "$root_gen_dir/components/sync_driver_resources.pak",
+    "$root_gen_dir/components/sync_driver_sync_internals_resources.pak",
     "$root_gen_dir/ios/web/ios_web_resources.pak",
     "$root_gen_dir/ui/resources/webui_generated_resources.pak",
     "$root_gen_dir/ui/resources/webui_resources.pak",
diff --git a/media/audio/mac/audio_manager_mac.cc b/media/audio/mac/audio_manager_mac.cc
index a994f74..526250e 100644
--- a/media/audio/mac/audio_manager_mac.cc
+++ b/media/audio/mac/audio_manager_mac.cc
@@ -438,7 +438,7 @@
   return true;
 }
 
-class AudioManagerMac::AudioPowerObserver : public base::PowerObserver {
+class AudioManagerMac::AudioPowerObserver : public base::PowerSuspendObserver {
  public:
   AudioPowerObserver()
       : is_suspending_(false),
@@ -449,14 +449,14 @@
     // base::PowerMonitorDeviceSource for more details.
     if (!is_monitoring_)
       return;
-    base::PowerMonitor::AddObserver(this);
+    base::PowerMonitor::AddPowerSuspendObserver(this);
   }
 
   ~AudioPowerObserver() override {
     DCHECK(thread_checker_.CalledOnValidThread());
     if (!is_monitoring_)
       return;
-    base::PowerMonitor::RemoveObserver(this);
+    base::PowerMonitor::RemovePowerSuspendObserver(this);
   }
 
   bool IsSuspending() const {
diff --git a/media/audio/power_observer_helper.cc b/media/audio/power_observer_helper.cc
index d8e6d819..187ca85 100644
--- a/media/audio/power_observer_helper.cc
+++ b/media/audio/power_observer_helper.cc
@@ -28,12 +28,12 @@
   // TODO(grunell): We could be suspending when adding this as observer, and
   // we won't be notified about that. See if we can add
   // PowerMonitorSource::IsSuspending() so that this can be checked here.
-  base::PowerMonitor::AddObserver(this);
+  base::PowerMonitor::AddPowerSuspendObserver(this);
 }
 
 PowerObserverHelper::~PowerObserverHelper() {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  base::PowerMonitor::RemoveObserver(this);
+  base::PowerMonitor::RemovePowerSuspendObserver(this);
 }
 
 bool PowerObserverHelper::IsSuspending() const {
diff --git a/media/audio/power_observer_helper.h b/media/audio/power_observer_helper.h
index 52dae42..8722e12c 100644
--- a/media/audio/power_observer_helper.h
+++ b/media/audio/power_observer_helper.h
@@ -15,11 +15,12 @@
 
 namespace media {
 
-// Helper class that implements PowerObserver and handles threading. A task
-// runner is given, on which suspend and resume notification callbacks are run.
-// It also provides a function to check if we are suspending on the task runner.
+// Helper class that implements PowerSuspendObserver and handles threading. A
+// task runner is given, on which suspend and resume notification callbacks are
+// run. It also provides a function to check if we are suspending on the task
+// runner.
 // Note that on Linux suspend/resume information is not supported.
-class MEDIA_EXPORT PowerObserverHelper : public base::PowerObserver {
+class MEDIA_EXPORT PowerObserverHelper : public base::PowerSuspendObserver {
  public:
   PowerObserverHelper(scoped_refptr<base::SequencedTaskRunner> task_runner,
                       base::RepeatingClosure suspend_callback,
@@ -57,7 +58,7 @@
   base::RepeatingClosure suspend_callback_;
   base::RepeatingClosure resume_callback_;
 
-  // base::PowerObserver implementation.
+  // base::PowerSuspendObserver implementation.
   void OnSuspend() override;
   void OnResume() override;
 
diff --git a/media/cast/sender/h264_vt_encoder.cc b/media/cast/sender/h264_vt_encoder.cc
index 9a716f6..9977f00 100644
--- a/media/cast/sender/h264_vt_encoder.cc
+++ b/media/cast/sender/h264_vt_encoder.cc
@@ -182,7 +182,7 @@
             weak_factory_.GetWeakPtr(), cast_environment_));
 
     // Register for power state changes.
-    base::PowerMonitor::AddObserver(this);
+    base::PowerMonitor::AddPowerSuspendObserver(this);
     VLOG(1) << "Registered for power state changes.";
   }
 }
@@ -192,7 +192,7 @@
 
   // Unregister the power observer. It is valid to remove an observer that was
   // not added.
-  base::PowerMonitor::RemoveObserver(this);
+  base::PowerMonitor::RemovePowerSuspendObserver(this);
 }
 
 void H264VideoToolboxEncoder::ResetCompressionSession() {
diff --git a/media/cast/sender/h264_vt_encoder.h b/media/cast/sender/h264_vt_encoder.h
index de12347..252b04a1 100644
--- a/media/cast/sender/h264_vt_encoder.h
+++ b/media/cast/sender/h264_vt_encoder.h
@@ -24,7 +24,7 @@
 // sizes directly. Implements the base::PowerObserver interface to reset the
 // compression session when the host process is suspended.
 class H264VideoToolboxEncoder : public VideoEncoder,
-                                public base::PowerObserver {
+                                public base::PowerSuspendObserver {
  public:
   // Returns true if the current platform and system configuration supports
   // using H264VideoToolboxEncoder with the given |video_config|.
@@ -45,7 +45,7 @@
   std::unique_ptr<VideoFrameFactory> CreateVideoFrameFactory() final;
   void EmitFrames() final;
 
-  // base::PowerObserver
+  // base::PowerSuspendObserver
   void OnSuspend() final;
   void OnResume() final;
 
diff --git a/media/renderers/audio_renderer_impl.cc b/media/renderers/audio_renderer_impl.cc
index 44f2e48..93d7dc4 100644
--- a/media/renderers/audio_renderer_impl.cc
+++ b/media/renderers/audio_renderer_impl.cc
@@ -80,13 +80,14 @@
   // won't remove the observer until we're destructed on |task_runner_| so we
   // must post it here if we're on the wrong thread.
   if (task_runner_->BelongsToCurrentThread()) {
-    base::PowerMonitor::AddObserver(this);
+    base::PowerMonitor::AddPowerSuspendObserver(this);
   } else {
     // Safe to post this without a WeakPtr because this class must be destructed
     // on the same thread and construction has not completed yet.
     task_runner_->PostTask(
         FROM_HERE,
-        base::BindOnce(IgnoreResult(&base::PowerMonitor::AddObserver), this));
+        base::BindOnce(
+            IgnoreResult(&base::PowerMonitor::AddPowerSuspendObserver), this));
   }
 
   // Do not add anything below this line since the above actions are only safe
@@ -96,7 +97,7 @@
 AudioRendererImpl::~AudioRendererImpl() {
   DVLOG(1) << __func__;
   DCHECK(task_runner_->BelongsToCurrentThread());
-  base::PowerMonitor::RemoveObserver(this);
+  base::PowerMonitor::RemovePowerSuspendObserver(this);
 
   // If Render() is in progress, this call will wait for Render() to finish.
   // After this call, the |sink_| will not call back into |this| anymore.
diff --git a/media/renderers/audio_renderer_impl.h b/media/renderers/audio_renderer_impl.h
index 1d3202c..90d5a18 100644
--- a/media/renderers/audio_renderer_impl.h
+++ b/media/renderers/audio_renderer_impl.h
@@ -55,7 +55,7 @@
 class MEDIA_EXPORT AudioRendererImpl
     : public AudioRenderer,
       public TimeSource,
-      public base::PowerObserver,
+      public base::PowerSuspendObserver,
       public AudioRendererSink::RenderCallback {
  public:
   using PlayDelayCBForTesting = base::RepeatingCallback<void(base::TimeDelta)>;
@@ -103,7 +103,7 @@
   void SetPreservesPitch(bool preserves_pitch) override;
   void SetAutoplayInitiated(bool autoplay_initiated) override;
 
-  // base::PowerObserver implementation.
+  // base::PowerSuspendObserver implementation.
   void OnSuspend() override;
   void OnResume() override;
 
diff --git a/mojo/public/tools/mojom/mojom_parser.py b/mojo/public/tools/mojom/mojom_parser.py
index 6c278a0..68a2abc7 100755
--- a/mojo/public/tools/mojom/mojom_parser.py
+++ b/mojo/public/tools/mojom/mojom_parser.py
@@ -27,9 +27,16 @@
 from mojom.parse import conditional_features
 
 
-# Disable this for easier debugging.
-# In Python 2, subprocesses just hang when exceptions are thrown :(.
-ENABLE_MULTIPROCESSING = sys.version_info[0] > 2
+# TODO(crbug.com/1187708): The multiprocessing code below seems
+# like it doesn't work on (at least) Mac Python3, and so it's
+# disabled for now until we can dig into it. Once that's working,
+# we can restore the logic to just be disabled under Python2.
+#
+# # Disable this for easier debugging.
+# # In Python 2, subprocesses just hang when exceptions are thrown :(.
+# ENABLE_MULTIPROCESSING = sys.version_info[0] > 2
+#
+ENABLE_MULTIPROCESSING = False
 
 
 def _ResolveRelativeImportPath(path, roots):
diff --git a/net/base/features.cc b/net/base/features.cc
index e8942723..0fdfedf6 100644
--- a/net/base/features.cc
+++ b/net/base/features.cc
@@ -138,6 +138,21 @@
 #if BUILDFLAG(BUILTIN_CERT_VERIFIER_FEATURE_SUPPORTED)
 const base::Feature kCertVerifierBuiltinFeature{
     "CertVerifierBuiltin", base::FEATURE_DISABLED_BY_DEFAULT};
+#if defined(OS_MAC)
+const base::FeatureParam<int> kCertVerifierBuiltinImpl{
+    &kCertVerifierBuiltinFeature, "impl", 0};
+#endif /* defined(OS_MAC) */
+#endif
+
+#if BUILDFLAG(TRIAL_COMPARISON_CERT_VERIFIER_SUPPORTED)
+// Enables the dual certificate verification trial feature.
+// https://crbug.com/649026
+const base::Feature kCertDualVerificationTrialFeature{
+    "CertDualVerificationTrial", base::FEATURE_DISABLED_BY_DEFAULT};
+#if defined(OS_MAC)
+const base::FeatureParam<int> kCertDualVerificationTrialImpl{
+    &kCertDualVerificationTrialFeature, "impl", 0};
+#endif /* defined(OS_MAC) */
 #endif
 
 const base::Feature kTurnOffStreamingMediaCachingOnBattery{
diff --git a/net/base/features.h b/net/base/features.h
index 449bfbc..7023f41 100644
--- a/net/base/features.h
+++ b/net/base/features.h
@@ -11,6 +11,7 @@
 #include "base/metrics/field_trial_params.h"
 #include "base/strings/string_piece.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
 #include "net/base/net_export.h"
 #include "net/net_buildflags.h"
 
@@ -215,7 +216,17 @@
 #if BUILDFLAG(BUILTIN_CERT_VERIFIER_FEATURE_SUPPORTED)
 // When enabled, use the builtin cert verifier instead of the platform verifier.
 NET_EXPORT extern const base::Feature kCertVerifierBuiltinFeature;
-#endif
+#if defined(OS_MAC)
+NET_EXPORT extern const base::FeatureParam<int> kCertVerifierBuiltinImpl;
+#endif /* defined(OS_MAC) */
+#endif /* BUILDFLAG(BUILTIN_CERT_VERIFIER_FEATURE_SUPPORTED) */
+
+#if BUILDFLAG(TRIAL_COMPARISON_CERT_VERIFIER_SUPPORTED)
+NET_EXPORT extern const base::Feature kCertDualVerificationTrialFeature;
+#if defined(OS_MAC)
+NET_EXPORT extern const base::FeatureParam<int> kCertDualVerificationTrialImpl;
+#endif /* defined(OS_MAC) */
+#endif /* BUILDFLAG(BUILTIN_CERT_VERIFIER_FEATURE_SUPPORTED) */
 
 // Turns off streaming media caching to disk when on battery power.
 NET_EXPORT extern const base::Feature kTurnOffStreamingMediaCachingOnBattery;
diff --git a/net/cert/internal/system_trust_store.cc b/net/cert/internal/system_trust_store.cc
index 646ea2f..21b3123 100644
--- a/net/cert/internal/system_trust_store.cc
+++ b/net/cert/internal/system_trust_store.cc
@@ -38,6 +38,7 @@
 #include "net/cert/known_roots_nss.h"
 #include "net/cert/scoped_nss_types.h"
 #elif defined(OS_MAC)
+#include "net/base/features.h"
 #include "net/cert/internal/trust_store_mac.h"
 #include "net/cert/x509_util_mac.h"
 #elif defined(OS_FUCHSIA)
@@ -183,9 +184,35 @@
   }
 
  private:
+  static constexpr TrustStoreMac::TrustImplType kDefaultTrustImpl =
+      TrustStoreMac::TrustImplType::kDomainCache;
+
+  static TrustStoreMac::TrustImplType ParamToTrustImplType(int param) {
+    switch (param) {
+      case 1:
+        return TrustStoreMac::TrustImplType::kDomainCache;
+      case 2:
+        return TrustStoreMac::TrustImplType::kSimple;
+      case 3:
+        return TrustStoreMac::TrustImplType::kMruCache;
+      default:
+        return kDefaultTrustImpl;
+    }
+  }
+
+  static TrustStoreMac::TrustImplType GetTrustStoreImplParam() {
+    if (base::FeatureList::IsEnabled(features::kCertVerifierBuiltinFeature))
+      return ParamToTrustImplType(features::kCertVerifierBuiltinImpl.Get());
+    if (base::FeatureList::IsEnabled(
+            features::kCertDualVerificationTrialFeature))
+      return ParamToTrustImplType(
+          features::kCertDualVerificationTrialImpl.Get());
+    return kDefaultTrustImpl;
+  }
+
   static TrustStoreMac* GetGlobalTrustStoreMac() {
     static base::NoDestructor<TrustStoreMac> static_trust_store_mac(
-        kSecPolicyAppleSSL);
+        kSecPolicyAppleSSL, GetTrustStoreImplParam());
     return static_trust_store_mac.get();
   }
 };
diff --git a/net/cert/internal/trust_store_mac.cc b/net/cert/internal/trust_store_mac.cc
index 33407e2..dffc3474 100644
--- a/net/cert/internal/trust_store_mac.cc
+++ b/net/cert/internal/trust_store_mac.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/callback_list.h"
 #include "base/containers/flat_map.h"
+#include "base/containers/mru_cache.h"
 #include "base/logging.h"
 #include "base/mac/foundation_util.h"
 #include "base/mac/mac_logging.h"
@@ -21,6 +22,7 @@
 #include "net/cert/internal/cert_errors.h"
 #include "net/cert/internal/parse_name.h"
 #include "net/cert/internal/parsed_certificate.h"
+#include "net/cert/known_roots_mac.h"
 #include "net/cert/test_keychain_search_list_mac.h"
 #include "net/cert/x509_util.h"
 #include "net/cert/x509_util_mac.h"
@@ -204,6 +206,32 @@
 
 // Returns the trust status for |cert_handle| for the policy |policy_oid| in
 // |trust_domain|.
+TrustStatus IsSecCertificateTrustedForPolicyInDomain(
+    SecCertificateRef cert_handle,
+    const bool is_self_issued,
+    const CFStringRef policy_oid,
+    SecTrustSettingsDomain trust_domain,
+    int* debug_info) {
+  base::ScopedCFTypeRef<CFArrayRef> trust_settings;
+  OSStatus err;
+  {
+    base::AutoLock lock(crypto::GetMacSecurityServicesLock());
+    err = SecTrustSettingsCopyTrustSettings(cert_handle, trust_domain,
+                                            trust_settings.InitializeInto());
+  }
+  if (err == errSecItemNotFound) {
+    // No trust settings for that domain.. try the next.
+    return TrustStatus::UNSPECIFIED;
+  }
+  if (err) {
+    OSSTATUS_LOG(ERROR, err) << "SecTrustSettingsCopyTrustSettings error";
+    return TrustStatus::UNSPECIFIED;
+  }
+  TrustStatus trust = IsTrustSettingsTrustedForPolicy(
+      trust_settings, is_self_issued, policy_oid, debug_info);
+  return trust;
+}
+
 TrustStatus IsCertificateTrustedForPolicyInDomain(
     const scoped_refptr<ParsedCertificate>& cert,
     const CFStringRef policy_oid,
@@ -228,32 +256,62 @@
   const bool is_self_issued =
       cert->normalized_subject() == cert->normalized_issuer();
 
-  base::ScopedCFTypeRef<CFArrayRef> trust_settings;
-  OSStatus err;
-  {
-    base::AutoLock lock(crypto::GetMacSecurityServicesLock());
-    err = SecTrustSettingsCopyTrustSettings(cert_handle, trust_domain,
-                                            trust_settings.InitializeInto());
-  }
-  if (err == errSecItemNotFound) {
-    // No trust settings for that domain.. try the next.
-    return TrustStatus::UNSPECIFIED;
-  }
-  if (err) {
-    OSSTATUS_LOG(ERROR, err) << "SecTrustSettingsCopyTrustSettings error";
-    return TrustStatus::UNSPECIFIED;
-  }
-  TrustStatus trust = IsTrustSettingsTrustedForPolicy(
-      trust_settings, is_self_issued, policy_oid, debug_info);
-  return trust;
+  return IsSecCertificateTrustedForPolicyInDomain(
+      cert_handle, is_self_issued, policy_oid, trust_domain, debug_info);
 }
 
-void UpdateUserData(int debug_info, base::SupportsUserData* user_data) {
+TrustStatus IsCertificateTrustedForPolicy(
+    const scoped_refptr<ParsedCertificate>& cert,
+    const CFStringRef policy_oid,
+    int* debug_info) {
+  base::ScopedCFTypeRef<SecCertificateRef> cert_handle =
+      x509_util::CreateSecCertificateFromBytes(cert->der_cert().UnsafeData(),
+                                               cert->der_cert().Length());
+  if (!cert_handle)
+    return TrustStatus::UNSPECIFIED;
+
+  const bool is_self_issued =
+      cert->normalized_subject() == cert->normalized_issuer();
+
+  // Evaluate trust domains in user, admin, system order. Admin settings can
+  // override system ones, and user settings can override both admin and system.
+  for (const auto& trust_domain :
+       {kSecTrustSettingsDomainUser, kSecTrustSettingsDomainAdmin,
+        kSecTrustSettingsDomainSystem}) {
+    base::ScopedCFTypeRef<CFArrayRef> trust_settings;
+    OSStatus err;
+    {
+      base::AutoLock lock(crypto::GetMacSecurityServicesLock());
+      err = SecTrustSettingsCopyTrustSettings(cert_handle, trust_domain,
+                                              trust_settings.InitializeInto());
+    }
+    if (err == errSecItemNotFound) {
+      // No trust settings for that domain.. try the next.
+      continue;
+    }
+    if (err) {
+      OSSTATUS_LOG(ERROR, err) << "SecTrustSettingsCopyTrustSettings error";
+      continue;
+    }
+    TrustStatus trust = IsTrustSettingsTrustedForPolicy(
+        trust_settings, is_self_issued, policy_oid, debug_info);
+    if (trust != TrustStatus::UNSPECIFIED)
+      return trust;
+  }
+
+  // No trust settings, or none of the settings were for the correct policy, or
+  // had the correct trust result.
+  return TrustStatus::UNSPECIFIED;
+}
+
+void UpdateUserData(int debug_info,
+                    base::SupportsUserData* user_data,
+                    TrustStoreMac::TrustImplType impl_type) {
   if (!user_data)
     return;
   TrustStoreMac::ResultDebugData* result_debug_data =
       TrustStoreMac::ResultDebugData::GetOrCreate(user_data);
-  result_debug_data->UpdateTrustDebugInfo(debug_info);
+  result_debug_data->UpdateTrustDebugInfo(debug_info, impl_type);
 }
 
 // Caches calculated trust status for certificates present in a single trust
@@ -312,7 +370,8 @@
     if (cache_iter->second.trust_status != TrustStatus::UNKNOWN) {
       // Cert has trust settings and trust has already been calculated, return
       // the cached value.
-      UpdateUserData(cache_iter->second.debug_info, debug_data);
+      UpdateUserData(cache_iter->second.debug_info, debug_data,
+                     TrustStoreMac::TrustImplType::kDomainCache);
       return cache_iter->second.trust_status;
     }
 
@@ -321,7 +380,8 @@
     TrustStatus cert_trust = IsCertificateTrustedForPolicyInDomain(
         cert, policy_oid_, domain_, &cache_iter->second.debug_info);
     cache_iter->second.trust_status = cert_trust;
-    UpdateUserData(cache_iter->second.debug_info, debug_data);
+    UpdateUserData(cache_iter->second.debug_info, debug_data,
+                   TrustStoreMac::TrustImplType::kDomainCache);
     return cert_trust;
   }
 
@@ -458,8 +518,10 @@
 }
 
 void TrustStoreMac::ResultDebugData::UpdateTrustDebugInfo(
-    int trust_debug_info) {
+    int trust_debug_info,
+    TrustImplType impl_type) {
   combined_trust_debug_info_ |= trust_debug_info;
+  trust_impl_ = impl_type;
 }
 
 std::unique_ptr<base::SupportsUserData::Data>
@@ -467,25 +529,40 @@
   return std::make_unique<ResultDebugData>(*this);
 }
 
-// TrustCache caches the calculated trust status of certificates with trust
-// settings in each of the three trust domains, and ensures the cache is reset
-// if trust settings are modified.
-class TrustStoreMac::TrustCache {
+// Interface for different implementations of getting trust settings from the
+// Mac APIs. This abstraction can be removed once a single implementation has
+// been chosen and launched.
+class TrustStoreMac::TrustImpl {
  public:
-  explicit TrustCache(CFStringRef policy_oid)
+  virtual ~TrustImpl() = default;
+
+  virtual bool IsKnownRoot(const ParsedCertificate* cert) = 0;
+  virtual TrustStatus IsCertTrusted(
+      const scoped_refptr<ParsedCertificate>& cert,
+      base::SupportsUserData* debug_data) = 0;
+  virtual void InitializeTrustCache() = 0;
+};
+
+// TrustImplDomainCache uses SecTrustSettingsCopyCertificates to get the list
+// of certs in each trust domain and then caches the calculated trust status of
+// those certs on access, and ensures the cache is reset if trust settings are
+// modified.
+class TrustStoreMac::TrustImplDomainCache : public TrustStoreMac::TrustImpl {
+ public:
+  explicit TrustImplDomainCache(CFStringRef policy_oid)
       : system_domain_cache_(kSecTrustSettingsDomainSystem, policy_oid),
         admin_domain_cache_(kSecTrustSettingsDomainAdmin, policy_oid),
         user_domain_cache_(kSecTrustSettingsDomainUser, policy_oid) {
     keychain_observer_ = std::make_unique<KeychainTrustObserver>();
   }
 
-  ~TrustCache() {
+  ~TrustImplDomainCache() override {
     GetNetworkNotificationThreadMac()->DeleteSoon(
         FROM_HERE, std::move(keychain_observer_));
   }
 
   // Returns true if |cert| is present in kSecTrustSettingsDomainSystem.
-  bool IsKnownRoot(const ParsedCertificate* cert) {
+  bool IsKnownRoot(const ParsedCertificate* cert) override {
     SHA256HashValue cert_hash = CalculateFingerprint256(cert->der_cert());
 
     base::AutoLock lock(cache_lock_);
@@ -495,7 +572,7 @@
 
   // Returns the trust status for |cert|.
   TrustStatus IsCertTrusted(const scoped_refptr<ParsedCertificate>& cert,
-                            base::SupportsUserData* debug_data) {
+                            base::SupportsUserData* debug_data) override {
     SHA256HashValue cert_hash = CalculateFingerprint256(cert->der_cert());
 
     base::AutoLock lock(cache_lock_);
@@ -517,7 +594,7 @@
   }
 
   // Initializes the cache, if it isn't already initialized.
-  void InitializeTrustCache() {
+  void InitializeTrustCache() override {
     base::AutoLock lock(cache_lock_);
     MaybeInitializeCache();
   }
@@ -553,11 +630,150 @@
   TrustDomainCache admin_domain_cache_;
   TrustDomainCache user_domain_cache_;
 
-  DISALLOW_COPY_AND_ASSIGN(TrustCache);
+  DISALLOW_COPY_AND_ASSIGN(TrustImplDomainCache);
 };
 
-TrustStoreMac::TrustStoreMac(CFStringRef policy_oid)
-    : trust_cache_(std::make_unique<TrustCache>(policy_oid)) {}
+// TrustImplNoCache is the simplest approach which calls
+// SecTrustSettingsCopyTrustSettings on every cert checked, with no caching.
+class TrustStoreMac::TrustImplNoCache : public TrustStoreMac::TrustImpl {
+ public:
+  explicit TrustImplNoCache(CFStringRef policy_oid) : policy_oid_(policy_oid) {}
+
+  ~TrustImplNoCache() override = default;
+
+  // Returns true if |cert| is present in kSecTrustSettingsDomainSystem.
+  bool IsKnownRoot(const ParsedCertificate* cert) override {
+    HashValue cert_hash(CalculateFingerprint256(cert->der_cert()));
+    return net::IsKnownRoot(cert_hash);
+  }
+
+  // Returns the trust status for |cert|.
+  TrustStatus IsCertTrusted(const scoped_refptr<ParsedCertificate>& cert,
+                            base::SupportsUserData* debug_data) override {
+    int debug_info = 0;
+    TrustStatus result =
+        IsCertificateTrustedForPolicy(cert, policy_oid_, &debug_info);
+    UpdateUserData(debug_info, debug_data,
+                   TrustStoreMac::TrustImplType::kSimple);
+    return result;
+  }
+
+  void InitializeTrustCache() override {
+    // No-op for this impl.
+  }
+
+ private:
+  const CFStringRef policy_oid_;
+
+  DISALLOW_COPY_AND_ASSIGN(TrustImplNoCache);
+};
+
+// TrustImplMRUCache is calls SecTrustSettingsCopyTrustSettings on every cert
+// checked, but caches the results in an MRU cache. The cache is cleared on
+// keychain updates.
+class TrustStoreMac::TrustImplMRUCache : public TrustStoreMac::TrustImpl {
+ public:
+  TrustImplMRUCache(CFStringRef policy_oid, size_t cache_size)
+      : policy_oid_(policy_oid), trust_status_cache_(cache_size) {
+    keychain_observer_ = std::make_unique<KeychainTrustObserver>();
+  }
+
+  ~TrustImplMRUCache() override {
+    GetNetworkNotificationThreadMac()->DeleteSoon(
+        FROM_HERE, std::move(keychain_observer_));
+  }
+
+  // Returns true if |cert| is present in kSecTrustSettingsDomainSystem.
+  bool IsKnownRoot(const ParsedCertificate* cert) override {
+    HashValue cert_hash(CalculateFingerprint256(cert->der_cert()));
+    return net::IsKnownRoot(cert_hash);
+  }
+
+  // Returns the trust status for |cert|.
+  TrustStatus IsCertTrusted(const scoped_refptr<ParsedCertificate>& cert,
+                            base::SupportsUserData* debug_data) override {
+    SHA256HashValue cert_hash = CalculateFingerprint256(cert->der_cert());
+
+    int starting_cache_iteration = -1;
+    {
+      base::AutoLock lock(cache_lock_);
+      MaybeResetCache();
+      starting_cache_iteration = iteration_;
+      auto cache_iter = trust_status_cache_.Get(cert_hash);
+      if (cache_iter != trust_status_cache_.end()) {
+        UpdateUserData(cache_iter->second.debug_info, debug_data,
+                       TrustStoreMac::TrustImplType::kMruCache);
+        return cache_iter->second.trust_status;
+      }
+    }
+
+    TrustStatusDetails trust_details;
+    trust_details.trust_status = IsCertificateTrustedForPolicy(
+        cert, policy_oid_, &trust_details.debug_info);
+
+    {
+      base::AutoLock lock(cache_lock_);
+      MaybeResetCache();
+      // Only store in the cache if the keychain has not changed since trust
+      // evaluation started. If the keychain changed during evaluation, then
+      // it isn't clear whether the calculated result applies to the new or old
+      // trust settings, so don't put it in the cache.
+      if (iteration_ == starting_cache_iteration)
+        trust_status_cache_.Put(cert_hash, trust_details);
+    }
+    UpdateUserData(trust_details.debug_info, debug_data,
+                   TrustStoreMac::TrustImplType::kMruCache);
+    return trust_details.trust_status;
+  }
+
+  void InitializeTrustCache() override {
+    // No-op for this impl.
+  }
+
+ private:
+  struct TrustStatusDetails {
+    TrustStatus trust_status = TrustStatus::UNKNOWN;
+    int debug_info = 0;
+  };
+
+  void MaybeResetCache() {
+    cache_lock_.AssertAcquired();
+    int64_t keychain_iteration = keychain_observer_->Iteration();
+    if (iteration_ == keychain_iteration)
+      return;
+    iteration_ = keychain_iteration;
+    trust_status_cache_.Clear();
+  }
+
+  const CFStringRef policy_oid_;
+  std::unique_ptr<KeychainTrustObserver> keychain_observer_;
+
+  base::Lock cache_lock_;
+  // |cache_lock_| must be held while accessing any following members.
+  base::MRUCache<SHA256HashValue, TrustStatusDetails> trust_status_cache_;
+  int64_t iteration_ = -1;
+
+  DISALLOW_COPY_AND_ASSIGN(TrustImplMRUCache);
+};
+
+TrustStoreMac::TrustStoreMac(CFStringRef policy_oid, TrustImplType impl) {
+  constexpr size_t cache_size = 512;  // TODO(mattm): make this a param.
+  switch (impl) {
+    case TrustImplType::kUnknown:
+      DCHECK(false);
+      break;
+    case TrustImplType::kDomainCache:
+      trust_cache_ = std::make_unique<TrustImplDomainCache>(policy_oid);
+      break;
+    case TrustImplType::kSimple:
+      trust_cache_ = std::make_unique<TrustImplNoCache>(policy_oid);
+      break;
+    case TrustImplType::kMruCache:
+      trust_cache_ =
+          std::make_unique<TrustImplMRUCache>(policy_oid, cache_size);
+      break;
+  }
+}
 
 TrustStoreMac::~TrustStoreMac() = default;
 
@@ -626,7 +842,7 @@
       *trust = CertificateTrust::ForUnspecified();
       return;
     case TrustStatus::UNKNOWN:
-      // UNKNOWN is an implementation detail of TrustCache and should never be
+      // UNKNOWN is an implementation detail of TrustImpl and should never be
       // returned.
       NOTREACHED();
       break;
diff --git a/net/cert/internal/trust_store_mac.h b/net/cert/internal/trust_store_mac.h
index c3f227d..92a2386 100644
--- a/net/cert/internal/trust_store_mac.h
+++ b/net/cert/internal/trust_store_mac.h
@@ -70,12 +70,19 @@
     TRUST_SETTINGS_DICT_CONTAINS_ALLOWED_ERROR = 1 << 10,
   };
 
+  enum class TrustImplType {
+    kUnknown = 0,
+    kDomainCache = 1,
+    kSimple = 2,
+    kMruCache = 3,
+  };
+
   class ResultDebugData : public base::SupportsUserData::Data {
    public:
     static const ResultDebugData* Get(const base::SupportsUserData* debug_data);
     static ResultDebugData* GetOrCreate(base::SupportsUserData* debug_data);
 
-    void UpdateTrustDebugInfo(int trust_debug_info);
+    void UpdateTrustDebugInfo(int trust_debug_info, TrustImplType impl_type);
 
     // base::SupportsUserData::Data implementation:
     std::unique_ptr<Data> Clone() override;
@@ -85,14 +92,21 @@
     // union of all the TrustDebugInfo flags.
     int combined_trust_debug_info() const { return combined_trust_debug_info_; }
 
+    // Returns an enum representing which trust implementation was used.
+    TrustImplType trust_impl() const { return trust_impl_; }
+
    private:
     int combined_trust_debug_info_ = 0;
+
+    TrustImplType trust_impl_ = TrustImplType::kUnknown;
   };
 
   // Creates a TrustStoreMac which will find anchors that are trusted for
   // |policy_oid|. For list of possible policy values, see:
   // https://developer.apple.com/reference/security/1667150-certificate_key_and_trust_servic/1670151-standard_policies_for_specific_c?language=objc
-  explicit TrustStoreMac(CFStringRef policy_oid);
+  // |impl| selects which internal implementation is used for checking trust
+  // settings.
+  TrustStoreMac(CFStringRef policy_oid, TrustImplType impl);
   ~TrustStoreMac() override;
 
   // Initializes the trust cache, if it isn't already initialized.
@@ -110,11 +124,14 @@
                 base::SupportsUserData* debug_data) const override;
 
  private:
+  class TrustImpl;
+  class TrustImplDomainCache;
+  class TrustImplNoCache;
+  class TrustImplMRUCache;
+
   FRIEND_TEST_ALL_PREFIXES(TrustStoreMacTest, MultiRootNotTrusted);
   FRIEND_TEST_ALL_PREFIXES(TrustStoreMacTest, SystemCerts);
 
-  class TrustCache;
-
   // Finds certificates in the OS keychains whose Subject matches |name_data|.
   // The result is an array of SecCertificateRef.
   static base::ScopedCFTypeRef<CFArrayRef>
@@ -127,7 +144,7 @@
   static base::ScopedCFTypeRef<CFDataRef> GetMacNormalizedIssuer(
       const ParsedCertificate* cert);
 
-  std::unique_ptr<TrustCache> trust_cache_;
+  std::unique_ptr<TrustImpl> trust_cache_;
 
   DISALLOW_COPY_AND_ASSIGN(TrustStoreMac);
 };
diff --git a/net/cert/internal/trust_store_mac_unittest.cc b/net/cert/internal/trust_store_mac_unittest.cc
index 7c5ff552..a62b85a 100644
--- a/net/cert/internal/trust_store_mac_unittest.cc
+++ b/net/cert/internal/trust_store_mac_unittest.cc
@@ -119,7 +119,8 @@
   ASSERT_TRUE(keychain);
   test_keychain_search_list->AddKeychain(keychain);
 
-  TrustStoreMac trust_store(kSecPolicyAppleSSL);
+  TrustStoreMac trust_store(kSecPolicyAppleSSL,
+                            TrustStoreMac::TrustImplType::kDomainCache);
 
   scoped_refptr<ParsedCertificate> a_by_b, b_by_c, b_by_f, c_by_d, c_by_e,
       f_by_e, d_by_d, e_by_e;
@@ -211,9 +212,12 @@
   }
 }
 
+class TrustStoreMacImplTest
+    : public testing::TestWithParam<TrustStoreMac::TrustImplType> {};
+
 // Test against all the certificates in the default keychains. Confirms that
 // the computed trust value matches that of SecTrustEvaluate.
-TEST(TrustStoreMacTest, SystemCerts) {
+TEST_P(TrustStoreMacImplTest, SystemCerts) {
   // Get the list of all certificates in the user & system keychains.
   // This may include both trusted and untrusted certificates.
   //
@@ -233,7 +237,7 @@
        "/System/Library/Keychains/SystemRootCertificates.keychain"},
       &find_certificate_system_roots_output));
 
-  TrustStoreMac trust_store(kSecPolicyAppleX509Basic);
+  TrustStoreMac trust_store(kSecPolicyAppleX509Basic, GetParam());
 
   base::ScopedCFTypeRef<SecPolicyRef> sec_policy(SecPolicyCreateBasicX509());
   ASSERT_TRUE(sec_policy);
@@ -324,9 +328,18 @@
         // what bits should be set in the trust debug info, but it should at
         // least have something set.
         EXPECT_NE(0, trust_debug_data->combined_trust_debug_info());
+        // The impl that was used should be specified in the debug data.
+        EXPECT_EQ(GetParam(), trust_debug_data->trust_impl());
       }
     }
   }
 }
 
+INSTANTIATE_TEST_SUITE_P(
+    Impl,
+    TrustStoreMacImplTest,
+    testing::Values(TrustStoreMac::TrustImplType::kDomainCache,
+                    TrustStoreMac::TrustImplType::kSimple,
+                    TrustStoreMac::TrustImplType::kMruCache));
+
 }  // namespace net
diff --git a/net/cert/known_roots_mac.cc b/net/cert/known_roots_mac.cc
index dfcaecd7..02dbb59 100644
--- a/net/cert/known_roots_mac.cc
+++ b/net/cert/known_roots_mac.cc
@@ -38,6 +38,15 @@
     return IsSHA256HashInSortedArray(hash, known_roots_);
   }
 
+  bool IsKnownRoot(const HashValue& cert_sha256) {
+    // If there are no known roots, then an API failure occurred. For safety,
+    // assume that all certificates are issued by known roots.
+    if (known_roots_.empty())
+      return true;
+
+    return IsSHA256HashInSortedArray(cert_sha256, known_roots_);
+  }
+
  private:
   friend struct base::LazyInstanceTraitsBase<OSXKnownRootHelper>;
 
@@ -77,6 +86,10 @@
   return g_known_roots.Get().IsKnownRoot(cert);
 }
 
+bool IsKnownRoot(const HashValue& cert_sha256) {
+  return g_known_roots.Get().IsKnownRoot(cert_sha256);
+}
+
 void InitializeKnownRoots() {
   base::AutoLock lock(crypto::GetMacSecurityServicesLock());
   g_known_roots.Get();
diff --git a/net/cert/known_roots_mac.h b/net/cert/known_roots_mac.h
index 5093d18..fd82894 100644
--- a/net/cert/known_roots_mac.h
+++ b/net/cert/known_roots_mac.h
@@ -7,6 +7,8 @@
 
 #include <Security/Security.h>
 
+#include "net/base/hash_value.h"
+
 namespace net {
 
 // IsKnownRoot returns true if the given certificate is one that we believe
@@ -17,6 +19,7 @@
 // acquire that lock prior to calling this, or eagerly initialize beforehand
 // using InitializeKnownRoots().
 bool IsKnownRoot(SecCertificateRef cert);
+bool IsKnownRoot(const HashValue& cert_sha256);
 
 // Calling this is optional as initialization will otherwise be done lazily when
 // calling IsKnownRoot(). When calling this, the current thread must NOT already
diff --git a/net/http/http_network_layer.cc b/net/http/http_network_layer.cc
index 6c0030d..084ff724 100644
--- a/net/http/http_network_layer.cc
+++ b/net/http/http_network_layer.cc
@@ -24,14 +24,14 @@
       suspended_(false) {
   DCHECK(session_);
 #if defined(OS_WIN)
-  base::PowerMonitor::AddObserver(this);
+  base::PowerMonitor::AddPowerSuspendObserver(this);
 #endif
 }
 
 HttpNetworkLayer::~HttpNetworkLayer() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 #if defined(OS_WIN)
-  base::PowerMonitor::RemoveObserver(this);
+  base::PowerMonitor::RemovePowerSuspendObserver(this);
 #endif
 }
 
diff --git a/net/http/http_network_layer.h b/net/http/http_network_layer.h
index 1b949badc..51223d9 100644
--- a/net/http/http_network_layer.h
+++ b/net/http/http_network_layer.h
@@ -21,7 +21,7 @@
 class HttpNetworkSession;
 
 class NET_EXPORT HttpNetworkLayer : public HttpTransactionFactory,
-                                    public base::PowerObserver {
+                                    public base::PowerSuspendObserver {
  public:
   // Construct a HttpNetworkLayer with an existing HttpNetworkSession which
   // contains a valid ProxyResolutionService. The HttpNetworkLayer must be
@@ -35,7 +35,7 @@
   HttpCache* GetCache() override;
   HttpNetworkSession* GetSession() override;
 
-  // base::PowerObserver methods:
+  // base::PowerSuspendObserver methods:
   void OnSuspend() override;
   void OnResume() override;
 
diff --git a/net/quic/quic_chromium_client_session.cc b/net/quic/quic_chromium_client_session.cc
index c0bc76f0..601a871 100644
--- a/net/quic/quic_chromium_client_session.cc
+++ b/net/quic/quic_chromium_client_session.cc
@@ -55,6 +55,7 @@
 #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "third_party/boringssl/src/include/openssl/ssl.h"
+#include "url/origin.h"
 
 namespace net {
 
@@ -78,6 +79,40 @@
 // network.
 const int kDefaultRTTMilliSecs = 300;
 
+// These values are persisted to logs. Entries should not be renumbered,
+// and numeric values should never be reused.
+enum class AcceptChEntries {
+  kNoEntries = 0,
+  kOnlyValidEntries = 1,
+  kOnlyInvalidEntries = 2,
+  kBothValidAndInvalidEntries = 3,
+  kMaxValue = kBothValidAndInvalidEntries,
+};
+
+void LogAcceptChFrameReceivedHistogram(bool has_valid_entry,
+                                       bool has_invalid_entry) {
+  AcceptChEntries value;
+  if (has_valid_entry) {
+    if (has_invalid_entry) {
+      value = AcceptChEntries::kBothValidAndInvalidEntries;
+    } else {
+      value = AcceptChEntries::kOnlyValidEntries;
+    }
+  } else {
+    if (has_invalid_entry) {
+      value = AcceptChEntries::kOnlyInvalidEntries;
+    } else {
+      value = AcceptChEntries::kNoEntries;
+    }
+  }
+  base::UmaHistogramEnumeration("Net.QuicSession.AcceptChFrameReceivedViaAlps",
+                                value);
+}
+
+void LogAcceptChForOriginHistogram(bool value) {
+  base::UmaHistogramBoolean("Net.QuicSession.AcceptChForOrigin", value);
+}
+
 void RecordConnectionCloseErrorCodeImpl(const std::string& histogram,
                                         uint64_t error,
                                         bool is_google_host,
@@ -1195,6 +1230,30 @@
   });
 }
 
+void QuicChromiumClientSession::OnAcceptChFrameReceivedViaAlps(
+    const quic::AcceptChFrame& frame) {
+  bool has_valid_entry = false;
+  bool has_invalid_entry = false;
+  for (const auto& entry : frame.entries) {
+    // |entry.origin| must be a valid origin.
+    GURL url(entry.origin);
+    if (!url.is_valid()) {
+      has_invalid_entry = true;
+      continue;
+    }
+    const url::Origin origin = url::Origin::Create(url);
+    std::string serialized = origin.Serialize();
+    if (serialized.empty() || entry.origin != serialized) {
+      has_invalid_entry = true;
+      continue;
+    }
+    has_valid_entry = true;
+    accept_ch_entries_received_via_alps_.insert(
+        std::make_pair(std::move(origin), entry.value));
+  }
+  LogAcceptChFrameReceivedHistogram(has_valid_entry, has_invalid_entry);
+}
+
 void QuicChromiumClientSession::AddHandle(Handle* handle) {
   if (going_away_) {
     handle->OnSessionClosed(connection()->version(), ERR_UNEXPECTED, error(),
@@ -1455,8 +1514,14 @@
 
 base::StringPiece QuicChromiumClientSession::GetAcceptChViaAlpsForOrigin(
     const url::Origin& origin) const {
-  // TODO(https://crbug.com/1184252): Implement.
-  return {};
+  auto it = accept_ch_entries_received_via_alps_.find(origin);
+  if (it == accept_ch_entries_received_via_alps_.end()) {
+    LogAcceptChForOriginHistogram(false);
+    return {};
+  } else {
+    LogAcceptChForOriginHistogram(true);
+    return it->second;
+  }
 }
 
 int QuicChromiumClientSession::CryptoConnect(CompletionOnceCallback callback) {
diff --git a/net/quic/quic_chromium_client_session.h b/net/quic/quic_chromium_client_session.h
index c7b3fab0..afe3dbd6 100644
--- a/net/quic/quic_chromium_client_session.h
+++ b/net/quic/quic_chromium_client_session.h
@@ -18,6 +18,7 @@
 #include <string>
 #include <vector>
 
+#include "base/containers/flat_map.h"
 #include "base/containers/mru_cache.h"
 #include "base/macros.h"
 #include "base/observer_list_types.h"
@@ -656,6 +657,8 @@
       quic::QuicStreamId id,
       const spdy::SpdyStreamPrecedence& new_precedence) override;
   void OnHttp3GoAway(uint64_t id) override;
+  void OnAcceptChFrameReceivedViaAlps(
+      const quic::AcceptChFrame& frame) override;
 
   // quic::QuicSession methods:
   QuicChromiumClientStream* CreateOutgoingBidirectionalStream() override;
@@ -1076,6 +1079,9 @@
 
   QuicChromiumPathValidationWriterDelegate path_validation_writer_delegate_;
 
+  // Map of origin to Accept-CH header field values received via ALPS.
+  base::flat_map<url::Origin, std::string> accept_ch_entries_received_via_alps_;
+
   base::WeakPtrFactory<QuicChromiumClientSession> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(QuicChromiumClientSession);
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index 86da050f..b2341a4 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -15,6 +15,7 @@
 #include "base/stl_util.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/default_tick_clock.h"
 #include "base/time/time.h"
@@ -2692,5 +2693,36 @@
   EXPECT_EQ(0, stream_->GetTotalReceivedBytes());
 }
 
+TEST_P(QuicHttpStreamTest, GetAcceptChViaAlps) {
+  AddWrite(ConstructInitialSettingsPacket());
+  Initialize();
+
+  if (!VersionUsesHttp3(version_.transport_version)) {
+    // ALPS is only implemented for HTTP/3.
+    return;
+  }
+
+  base::HistogramTester histogram_tester;
+
+  session_->OnAcceptChFrameReceivedViaAlps(
+      {{{"https://www.example.org", "Sec-UA-CH-Platform"}}});
+
+  request_.method = "GET";
+  request_.url = GURL("https://www.example.org/foo");
+
+  EXPECT_EQ(OK,
+            stream_->InitializeStream(&request_, true, DEFAULT_PRIORITY,
+                                      net_log_.bound(), callback_.callback()));
+  EXPECT_EQ("Sec-UA-CH-Platform", stream_->GetAcceptChViaAlps());
+  EXPECT_TRUE(AtEof());
+
+  histogram_tester.ExpectBucketCount(
+      "Net.QuicSession.AcceptChFrameReceivedViaAlps", 1, 1);
+  histogram_tester.ExpectTotalCount(
+      "Net.QuicSession.AcceptChFrameReceivedViaAlps", 1);
+  histogram_tester.ExpectBucketCount("Net.QuicSession.AcceptChForOrigin", 1, 1);
+  histogram_tester.ExpectTotalCount("Net.QuicSession.AcceptChForOrigin", 1);
+}
+
 }  // namespace test
 }  // namespace net
diff --git a/net/socket/tcp_client_socket.cc b/net/socket/tcp_client_socket.cc
index 9e62f5e..a9acb466 100644
--- a/net/socket/tcp_client_socket.cc
+++ b/net/socket/tcp_client_socket.cc
@@ -57,7 +57,7 @@
 TCPClientSocket::~TCPClientSocket() {
   Disconnect();
 #if defined(TCP_CLIENT_SOCKET_OBSERVES_SUSPEND)
-  base::PowerMonitor::RemoveObserver(this);
+  base::PowerMonitor::RemovePowerSuspendObserver(this);
 #endif  // defined(TCP_CLIENT_SOCKET_OBSERVES_SUSPEND)
 }
 
@@ -159,7 +159,7 @@
   if (socket_->IsValid())
     socket_->SetDefaultOptionsForClient();
 #if defined(TCP_CLIENT_SOCKET_OBSERVES_SUSPEND)
-  base::PowerMonitor::AddObserver(this);
+  base::PowerMonitor::AddPowerSuspendObserver(this);
 #endif  // defined(TCP_CLIENT_SOCKET_OBSERVES_SUSPEND)
 }
 
diff --git a/net/socket/tcp_client_socket.h b/net/socket/tcp_client_socket.h
index d5d62bd..3d4c4ed 100644
--- a/net/socket/tcp_client_socket.h
+++ b/net/socket/tcp_client_socket.h
@@ -49,7 +49,7 @@
 
 // A client socket that uses TCP as the transport layer.
 class NET_EXPORT TCPClientSocket : public TransportClientSocket,
-                                   public base::PowerObserver {
+                                   public base::PowerSuspendObserver {
  public:
   // The IP address(es) and port number to connect to.  The TCP socket will try
   // each IP address in the list until it succeeds in establishing a
@@ -121,7 +121,7 @@
   // release ownership of the descriptor.
   SocketDescriptor SocketDescriptorForTesting() const;
 
-  // base::PowerObserver methods:
+  // base::PowerSuspendObserver methods:
   void OnSuspend() override;
 
  private:
diff --git a/pdf/out_of_process_instance.cc b/pdf/out_of_process_instance.cc
index d7c5b8a..2502522 100644
--- a/pdf/out_of_process_instance.cc
+++ b/pdf/out_of_process_instance.cc
@@ -81,8 +81,6 @@
 // Name of identifier field passed from JS to the plugin and back, to associate
 // Page->Plugin messages to Plugin->Page responses.
 constexpr char kJSMessageId[] = "messageId";
-// Document print preview loaded (Plugin -> Page)
-constexpr char kJSPreviewLoadedType[] = "printPreviewLoaded";
 // Print (Page -> Plugin)
 constexpr char kJSPrintType[] = "print";
 // Save attachment (Page -> Plugin)
@@ -1502,12 +1500,6 @@
   }
 }
 
-void OutOfProcessInstance::SendPrintPreviewLoadedNotification() {
-  pp::VarDictionary loaded_message;
-  loaded_message.Set(pp::Var(kType), pp::Var(kJSPreviewLoadedType));
-  PostMessage(loaded_message);
-}
-
 void OutOfProcessInstance::SendThumbnail(const std::string& message_id,
                                          Thumbnail thumbnail) {
   pp::VarDictionary reply;
diff --git a/pdf/out_of_process_instance.h b/pdf/out_of_process_instance.h
index 027e0d0c..acfd2565 100644
--- a/pdf/out_of_process_instance.h
+++ b/pdf/out_of_process_instance.h
@@ -200,9 +200,6 @@
   // Called after a preview page has loaded or failed to load.
   void LoadNextPreviewPage();
 
-  // Send a notification that the print preview has loaded.
-  void SendPrintPreviewLoadedNotification();
-
   // Sends the thumbnail image data.
   void SendThumbnail(const std::string& message_id, Thumbnail thumbnail);
 
diff --git a/pdf/pdf_view_plugin_base.cc b/pdf/pdf_view_plugin_base.cc
index e0537f8b..8d4adcc6 100644
--- a/pdf/pdf_view_plugin_base.cc
+++ b/pdf/pdf_view_plugin_base.cc
@@ -464,6 +464,12 @@
   SendMessage(std::move(message));
 }
 
+void PdfViewPluginBase::SendPrintPreviewLoadedNotification() {
+  base::Value message(base::Value::Type::DICTIONARY);
+  message.SetStringKey("type", "printPreviewLoaded");
+  SendMessage(std::move(message));
+}
+
 void PdfViewPluginBase::OnPaint(const std::vector<gfx::Rect>& paint_rects,
                                 std::vector<PaintReadyRect>& ready,
                                 std::vector<gfx::Rect>& pending) {
diff --git a/pdf/pdf_view_plugin_base.h b/pdf/pdf_view_plugin_base.h
index 044f5dfc..29f01d53 100644
--- a/pdf/pdf_view_plugin_base.h
+++ b/pdf/pdf_view_plugin_base.h
@@ -169,6 +169,9 @@
   // -1 for loading error.
   void SendLoadingProgress(double percentage);
 
+  // Send a notification that the print preview has loaded.
+  void SendPrintPreviewLoadedNotification();
+
   // Initialize image buffer(s) according to the new context size.
   virtual void InitImageData(const gfx::Size& size) = 0;
 
diff --git a/remoting/host/linux/x_server_clipboard_unittest.cc b/remoting/host/linux/x_server_clipboard_unittest.cc
index b451e7f..3ad92c6 100644
--- a/remoting/host/linux/x_server_clipboard_unittest.cc
+++ b/remoting/host/linux/x_server_clipboard_unittest.cc
@@ -19,10 +19,14 @@
 class ClipboardTestClient : public x11::EventObserver {
  public:
   ClipboardTestClient() = default;
-  ~ClipboardTestClient() override = default;
+  ~ClipboardTestClient() override {
+    DCHECK(connection_);
+    connection_->RemoveEventObserver(this);
+  }
 
   void Init(x11::Connection* connection) {
     connection_ = connection;
+    connection_->AddEventObserver(this);
     clipboard_.Init(connection, base::BindRepeating(
                                     &ClipboardTestClient::OnClipboardChanged,
                                     base::Unretained(this)));
diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
index ab0566b0..ba3a126 100644
--- a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
@@ -193,8 +193,13 @@
   }
 #endif
 
-  if (sysno == __NR_futex)
+  if (sysno == __NR_futex
+#if defined(__NR_futex_time64)
+      || sysno == __NR_futex_time64
+#endif
+  ) {
     return RestrictFutex();
+  }
 
   if (sysno == __NR_set_robust_list)
     return Error(EPERM);
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc b/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc
index a76fd307..0330aeab 100644
--- a/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc
@@ -423,6 +423,9 @@
     case __NR_get_robust_list:
     case __NR_set_robust_list:
     case __NR_futex:
+#if defined(__NR_futex_time64)
+    case __NR_futex_time64:
+#endif
     default:
       return false;
   }
diff --git a/services/device/power_monitor/power_monitor_message_broadcaster.cc b/services/device/power_monitor/power_monitor_message_broadcaster.cc
index c3f0e690..96364f7 100644
--- a/services/device/power_monitor/power_monitor_message_broadcaster.cc
+++ b/services/device/power_monitor/power_monitor_message_broadcaster.cc
@@ -10,11 +10,13 @@
 namespace device {
 
 PowerMonitorMessageBroadcaster::PowerMonitorMessageBroadcaster() {
-  base::PowerMonitor::AddObserver(this);
+  base::PowerMonitor::AddPowerSuspendObserver(this);
+  base::PowerMonitor::AddPowerStateObserver(this);
 }
 
 PowerMonitorMessageBroadcaster::~PowerMonitorMessageBroadcaster() {
-  base::PowerMonitor::RemoveObserver(this);
+  base::PowerMonitor::RemovePowerSuspendObserver(this);
+  base::PowerMonitor::RemovePowerStateObserver(this);
 }
 
 // static
diff --git a/services/device/power_monitor/power_monitor_message_broadcaster.h b/services/device/power_monitor/power_monitor_message_broadcaster.h
index 7dc8b43..2fb99222 100644
--- a/services/device/power_monitor/power_monitor_message_broadcaster.h
+++ b/services/device/power_monitor/power_monitor_message_broadcaster.h
@@ -17,7 +17,8 @@
 
 // A class used to monitor the power state change and communicate it to child
 // processes via IPC.
-class PowerMonitorMessageBroadcaster : public base::PowerObserver,
+class PowerMonitorMessageBroadcaster : public base::PowerStateObserver,
+                                       public base::PowerSuspendObserver,
                                        public device::mojom::PowerMonitor {
  public:
   PowerMonitorMessageBroadcaster();
@@ -29,8 +30,10 @@
   void AddClient(mojo::PendingRemote<device::mojom::PowerMonitorClient>
                      power_monitor_client) override;
 
-  // base::PowerObserver:
+  // base::PowerStateObserver:
   void OnPowerStateChange(bool on_battery_power) override;
+
+  // base::PowerSuspendObserver:
   void OnSuspend() override;
   void OnResume() override;
 
diff --git a/services/device/public/cpp/power_monitor/power_monitor_broadcast_source_unittest.cc b/services/device/public/cpp/power_monitor/power_monitor_broadcast_source_unittest.cc
index 86a14040..d52e06f 100644
--- a/services/device/public/cpp/power_monitor/power_monitor_broadcast_source_unittest.cc
+++ b/services/device/public/cpp/power_monitor/power_monitor_broadcast_source_unittest.cc
@@ -45,7 +45,8 @@
 
 TEST_F(PowerMonitorBroadcastSourceTest, PowerMessageReceiveBroadcast) {
   base::PowerMonitorTestObserver observer;
-  base::PowerMonitor::AddObserver(&observer);
+  base::PowerMonitor::AddPowerSuspendObserver(&observer);
+  base::PowerMonitor::AddPowerStateObserver(&observer);
 
   // Sending resume when not suspended should have no effect.
   client()->Resume();
@@ -93,7 +94,9 @@
   client()->PowerStateChange(false);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(observer.power_state_changes(), 2);
-  base::PowerMonitor::RemoveObserver(&observer);
+
+  base::PowerMonitor::RemovePowerSuspendObserver(&observer);
+  base::PowerMonitor::RemovePowerStateObserver(&observer);
 }
 
 }  // namespace device
diff --git a/services/media_session/audio_focus_manager.cc b/services/media_session/audio_focus_manager.cc
index 4aa0146d..7fe7f43 100644
--- a/services/media_session/audio_focus_manager.cc
+++ b/services/media_session/audio_focus_manager.cc
@@ -35,16 +35,18 @@
 }  // namespace
 
 // MediaPowerDelegate will pause all playback if the device is suspended.
-class MediaPowerDelegate : public base::PowerObserver {
+class MediaPowerDelegate : public base::PowerSuspendObserver {
  public:
   explicit MediaPowerDelegate(base::WeakPtr<AudioFocusManager> owner)
       : owner_(owner) {
-    base::PowerMonitor::AddObserver(this);
+    base::PowerMonitor::AddPowerSuspendObserver(this);
   }
 
-  ~MediaPowerDelegate() override { base::PowerMonitor::RemoveObserver(this); }
+  ~MediaPowerDelegate() override {
+    base::PowerMonitor::RemovePowerSuspendObserver(this);
+  }
 
-  // base::PowerObserver:
+  // base::PowerSuspendObserver:
   void OnSuspend() override {
     DCHECK(owner_);
     owner_->SuspendAllSessions();
diff --git a/services/network/cors/preflight_controller.cc b/services/network/cors/preflight_controller.cc
index 74be751f..03cc1f04 100644
--- a/services/network/cors/preflight_controller.cc
+++ b/services/network/cors/preflight_controller.cc
@@ -95,7 +95,6 @@
   preflight_request->load_flags = RetrieveCacheFlags(request.load_flags);
   preflight_request->resource_type = request.resource_type;
   preflight_request->fetch_window_id = request.fetch_window_id;
-  preflight_request->render_frame_id = request.render_frame_id;
 
   preflight_request->headers.SetHeader(net::HttpRequestHeaders::kAccept,
                                        kDefaultAcceptHeaderValue);
diff --git a/services/network/cors/preflight_controller_unittest.cc b/services/network/cors/preflight_controller_unittest.cc
index 2e11fea..8296448 100644
--- a/services/network/cors/preflight_controller_unittest.cc
+++ b/services/network/cors/preflight_controller_unittest.cc
@@ -209,21 +209,6 @@
   EXPECT_EQ(request.fetch_window_id, preflight->fetch_window_id);
 }
 
-TEST(PreflightControllerCreatePreflightRequestTest, RenderFrameId) {
-  ResourceRequest request;
-  request.mode = mojom::RequestMode::kCors;
-  request.credentials_mode = mojom::CredentialsMode::kOmit;
-  request.request_initiator = url::Origin();
-  request.headers.SetHeader(net::HttpRequestHeaders::kContentType,
-                            "application/octet-stream");
-  request.render_frame_id = 99;
-
-  std::unique_ptr<ResourceRequest> preflight =
-      PreflightController::CreatePreflightRequestForTesting(request);
-
-  EXPECT_EQ(request.render_frame_id, preflight->render_frame_id);
-}
-
 TEST(PreflightControllerOptionsTest, CheckOptions) {
   base::test::TaskEnvironment task_environment_(
       base::test::TaskEnvironment::MainThreadType::IO);
diff --git a/services/network/cors/preflight_result.cc b/services/network/cors/preflight_result.cc
index 198621d..5c0395855 100644
--- a/services/network/cors/preflight_result.cc
+++ b/services/network/cors/preflight_result.cc
@@ -41,21 +41,32 @@
   return base::TimeTicks::Now();
 }
 
-bool ParseAccessControlMaxAge(const base::Optional<std::string>& max_age,
-                              base::TimeDelta* expiry_delta) {
-  DCHECK(expiry_delta);
+base::TimeDelta ParseAccessControlMaxAge(
+    const base::Optional<std::string>& max_age) {
+  if (!max_age) {
+    return kDefaultTimeout;
+  }
 
-  if (!max_age)
-    return false;
+  int64_t seconds;
+  if (!base::StringToInt64(*max_age, &seconds)) {
+    return kDefaultTimeout;
+  }
 
-  uint64_t delta;
-  if (!base::StringToUint64(*max_age, &delta))
-    return false;
+  // Negative value doesn't make sense - use 0 instead, to represent that the
+  // entry cannot be cached.
+  if (seconds < 0) {
+    return base::TimeDelta();
+  }
+  // To avoid integer overflow, we compare seconds instead of comparing
+  // TimeDeltas.
+  static_assert(
+      kMaxTimeout == base::TimeDelta::FromSeconds(kMaxTimeout.InSeconds()),
+      "`kMaxTimeout` must be a multiple of one second.");
+  if (seconds >= kMaxTimeout.InSeconds()) {
+    return kMaxTimeout;
+  }
 
-  *expiry_delta = base::TimeDelta::FromSeconds(delta);
-  if (*expiry_delta > kMaxTimeout)
-    *expiry_delta = kMaxTimeout;
-  return true;
+  return base::TimeDelta::FromSeconds(seconds);
 }
 
 // Parses |string| as a Access-Control-Allow-* header value, storing the result
@@ -192,16 +203,7 @@
   if (!ParseAccessControlAllowList(allow_headers_header, &headers_, true))
     return mojom::CorsError::kInvalidAllowHeadersPreflightResponse;
 
-  base::TimeDelta expiry_delta;
-  if (max_age_header) {
-    // Set expiry_delta to 0 on invalid Access-Control-Max-Age headers so to
-    // invalidate the entry immediately. CORS-preflight response should be still
-    // usable for the request that initiates the CORS-preflight.
-    if (!ParseAccessControlMaxAge(max_age_header, &expiry_delta))
-      expiry_delta = base::TimeDelta();
-  } else {
-    expiry_delta = kDefaultTimeout;
-  }
+  const base::TimeDelta expiry_delta = ParseAccessControlMaxAge(max_age_header);
   absolute_expiry_time_ = Now() + expiry_delta;
 
   return base::nullopt;
diff --git a/services/network/cors/preflight_result_unittest.cc b/services/network/cors/preflight_result_unittest.cc
index 8b8a3d28..8eaef93 100644
--- a/services/network/cors/preflight_result_unittest.cc
+++ b/services/network/cors/preflight_result_unittest.cc
@@ -177,9 +177,6 @@
   EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSeconds(573),
             result1->absolute_expiry_time());
 
-  // Negative values are invalid. The preflight result itself can be usable, but
-  // should not cache such results. PreflightResult expresses it as a result
-  // with 'Access-Control-Max-Age: 0'.
   std::unique_ptr<PreflightResult> result2 =
       PreflightResult::Create(mojom::CredentialsMode::kOmit, base::nullopt,
                               base::nullopt, std::string("-765"), nullptr);
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index 0855a57a..bea8617 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -166,7 +166,6 @@
 using ::testing::Optional;
 
 constexpr char kMockHost[] = "mock.host";
-constexpr int kRouteId = 12;
 
 #if BUILDFLAG(ENABLE_REPORTING)
 const base::FilePath::CharType kFilename[] =
@@ -5782,7 +5781,6 @@
 
   ResourceRequest request;
   request.url = GURL("http://does.not.resolve/echo");
-  request.render_frame_id = kRouteId;
   std::unique_ptr<TestURLLoaderClient> client =
       FetchRequest(request, network_context.get());
   std::string response;
diff --git a/services/network/public/cpp/cert_verifier/trial_comparison_cert_verifier_mojo.cc b/services/network/public/cpp/cert_verifier/trial_comparison_cert_verifier_mojo.cc
index 50c45e5..25e5ca2 100644
--- a/services/network/public/cpp/cert_verifier/trial_comparison_cert_verifier_mojo.cc
+++ b/services/network/public/cpp/cert_verifier/trial_comparison_cert_verifier_mojo.cc
@@ -18,6 +18,27 @@
 #include "net/cert/internal/trust_store_mac.h"
 #endif
 
+namespace {
+
+#if defined(OS_MAC)
+network::mojom::CertVerifierDebugInfo::MacTrustImplType TrustImplTypeToMojom(
+    net::TrustStoreMac::TrustImplType input) {
+  switch (input) {
+    case net::TrustStoreMac::TrustImplType::kUnknown:
+      return network::mojom::CertVerifierDebugInfo::MacTrustImplType::kUnknown;
+    case net::TrustStoreMac::TrustImplType::kDomainCache:
+      return network::mojom::CertVerifierDebugInfo::MacTrustImplType::
+          kDomainCache;
+    case net::TrustStoreMac::TrustImplType::kSimple:
+      return network::mojom::CertVerifierDebugInfo::MacTrustImplType::kSimple;
+    case net::TrustStoreMac::TrustImplType::kMruCache:
+      return network::mojom::CertVerifierDebugInfo::MacTrustImplType::kMruCache;
+  }
+}
+#endif
+
+}  // namespace
+
 namespace network {
 
 TrialComparisonCertVerifierMojo::TrialComparisonCertVerifierMojo(
@@ -99,6 +120,8 @@
   if (mac_trust_debug_info) {
     debug_info->mac_combined_trust_debug_info =
         mac_trust_debug_info->combined_trust_debug_info();
+    debug_info->mac_trust_impl =
+        TrustImplTypeToMojom(mac_trust_debug_info->trust_impl());
   }
 #endif
   auto* cert_verify_proc_builtin_debug_data =
diff --git a/services/network/public/cpp/cert_verifier/trial_comparison_cert_verifier_mojo_unittest.cc b/services/network/public/cpp/cert_verifier/trial_comparison_cert_verifier_mojo_unittest.cc
index 73a5200e..c5df5d3 100644
--- a/services/network/public/cpp/cert_verifier/trial_comparison_cert_verifier_mojo_unittest.cc
+++ b/services/network/public/cpp/cert_verifier/trial_comparison_cert_verifier_mojo_unittest.cc
@@ -128,7 +128,8 @@
   auto* mac_trust_debug_info =
       net::TrustStoreMac::ResultDebugData::GetOrCreate(&trial_result);
   ASSERT_TRUE(mac_trust_debug_info);
-  mac_trust_debug_info->UpdateTrustDebugInfo(kExpectedTrustDebugInfo);
+  mac_trust_debug_info->UpdateTrustDebugInfo(
+      kExpectedTrustDebugInfo, net::TrustStoreMac::TrustImplType::kSimple);
 #endif
 
   base::Time time = base::Time::Now();
@@ -188,6 +189,8 @@
 
   EXPECT_EQ(kExpectedTrustDebugInfo,
             report.debug_info->mac_combined_trust_debug_info);
+  EXPECT_EQ(network::mojom::CertVerifierDebugInfo::MacTrustImplType::kSimple,
+            report.debug_info->mac_trust_impl);
 #endif
 
   EXPECT_EQ(time, report.debug_info->trial_verification_time);
diff --git a/services/network/public/cpp/resource_request.cc b/services/network/public/cpp/resource_request.cc
index 45c1f5d..6e4351b 100644
--- a/services/network/public/cpp/resource_request.cc
+++ b/services/network/public/cpp/resource_request.cc
@@ -191,7 +191,6 @@
          enable_load_timing == request.enable_load_timing &&
          enable_upload_progress == request.enable_upload_progress &&
          do_not_prompt_for_login == request.do_not_prompt_for_login &&
-         render_frame_id == request.render_frame_id &&
          is_main_frame == request.is_main_frame &&
          transition_type == request.transition_type &&
          report_raw_headers == request.report_raw_headers &&
diff --git a/services/network/public/cpp/resource_request.h b/services/network/public/cpp/resource_request.h
index f9e197e4..dfd15a9ee 100644
--- a/services/network/public/cpp/resource_request.h
+++ b/services/network/public/cpp/resource_request.h
@@ -140,7 +140,6 @@
   bool enable_load_timing = false;
   bool enable_upload_progress = false;
   bool do_not_prompt_for_login = false;
-  int render_frame_id = MSG_ROUTING_NONE;
   bool is_main_frame = false;
   int transition_type = 0;
   bool report_raw_headers = false;
diff --git a/services/network/public/cpp/url_request_mojom_traits.cc b/services/network/public/cpp/url_request_mojom_traits.cc
index 7871a9f..4e7fb8c 100644
--- a/services/network/public/cpp/url_request_mojom_traits.cc
+++ b/services/network/public/cpp/url_request_mojom_traits.cc
@@ -255,7 +255,6 @@
   out->enable_load_timing = data.enable_load_timing();
   out->enable_upload_progress = data.enable_upload_progress();
   out->do_not_prompt_for_login = data.do_not_prompt_for_login();
-  out->render_frame_id = data.render_frame_id();
   out->is_main_frame = data.is_main_frame();
   out->transition_type = data.transition_type();
   out->report_raw_headers = data.report_raw_headers();
diff --git a/services/network/public/cpp/url_request_mojom_traits.h b/services/network/public/cpp/url_request_mojom_traits.h
index 8042bd4..9407ca07 100644
--- a/services/network/public/cpp/url_request_mojom_traits.h
+++ b/services/network/public/cpp/url_request_mojom_traits.h
@@ -245,9 +245,6 @@
   static bool do_not_prompt_for_login(const network::ResourceRequest& request) {
     return request.do_not_prompt_for_login;
   }
-  static int32_t render_frame_id(const network::ResourceRequest& request) {
-    return request.render_frame_id;
-  }
   static bool is_main_frame(const network::ResourceRequest& request) {
     return request.is_main_frame;
   }
diff --git a/services/network/public/cpp/url_request_mojom_traits_unittest.cc b/services/network/public/cpp/url_request_mojom_traits_unittest.cc
index cbf992e..03eea0c 100644
--- a/services/network/public/cpp/url_request_mojom_traits_unittest.cc
+++ b/services/network/public/cpp/url_request_mojom_traits_unittest.cc
@@ -76,7 +76,6 @@
   original.enable_load_timing = true;
   original.enable_upload_progress = false;
   original.do_not_prompt_for_login = true;
-  original.render_frame_id = 5;
   original.is_main_frame = true;
   original.transition_type = 0;
   original.report_raw_headers = true;
diff --git a/services/network/public/mojom/trial_comparison_cert_verifier.mojom b/services/network/public/mojom/trial_comparison_cert_verifier.mojom
index 309de8f..fd35d24 100644
--- a/services/network/public/mojom/trial_comparison_cert_verifier.mojom
+++ b/services/network/public/mojom/trial_comparison_cert_verifier.mojom
@@ -49,6 +49,18 @@
   [EnableIf=is_mac]
   int32 mac_combined_trust_debug_info;
 
+  // A TrustStoreMac::TrustImplType value representing which implementation was
+  // used for the verification
+  [EnableIf=is_mac]
+  enum MacTrustImplType {
+    kUnknown = 0,
+    kDomainCache = 1,
+    kSimple = 2,
+    kMruCache = 3,
+  };
+  [EnableIf=is_mac]
+  MacTrustImplType mac_trust_impl;
+
   [EnableIf=is_mac]
   MacPlatformVerifierDebugInfo? mac_platform_debug_info;
 
diff --git a/services/network/public/mojom/url_request.mojom b/services/network/public/mojom/url_request.mojom
index 8700c1a..2d5766c 100644
--- a/services/network/public/mojom/url_request.mojom
+++ b/services/network/public/mojom/url_request.mojom
@@ -303,18 +303,6 @@
   // credentials or default credentials may still be used for authentication.
   bool do_not_prompt_for_login;
 
-  // The id of the RenderFrame. This may be:
-  // - The render frame id for a) subresource requests from a document, b) the
-  //   main resource request for a dedicated/shared worker if that worker was
-  //   created by a frame.
-  // - MSG_ROUTING_NONE for nested dedicated workers.
-  // - MSG_ROUTING_NONE for subresource requests from a dedicated/shared worker.
-  // - service_worker_route_id from EmbeddedWorkerStartParams for service worker
-  //   main script requests and subresource requests.
-  // - The frame tree node ID for navigation requests only. Please do not use
-  //   frame tree node ID for other requests.
-  int32 render_frame_id;
-
   // True if |frame_id| is the main frame of a RenderView.
   bool is_main_frame;
 
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index 136c4ec..6bcaca9 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -482,7 +482,6 @@
       is_load_timing_enabled_(request.enable_load_timing),
       factory_params_(factory_params),
       coep_reporter_(coep_reporter),
-      render_frame_id_(request.render_frame_id),
       request_id_(request_id),
       keepalive_request_size_(keepalive_request_size),
       keepalive_(request.keepalive),
@@ -1224,15 +1223,6 @@
 void URLLoader::OnCertificateRequested(net::URLRequest* unused,
                                        net::SSLCertRequestInfo* cert_info) {
   DCHECK(!client_cert_responder_receiver_.is_bound());
-
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kIgnoreUrlFetcherCertRequests) &&
-      factory_params_->process_id == 0 &&
-      render_frame_id_ == MSG_ROUTING_NONE) {
-    ContinueWithoutCertificate();
-    return;
-  }
-
   auto* url_loader_network_observer = GetURLLoaderNetworkServiceObserver();
   if (!url_loader_network_observer) {
     CancelRequest();
@@ -1703,10 +1693,6 @@
   return url_request_->GetLoadState().state;
 }
 
-int32_t URLLoader::GetRenderFrameId() const {
-  return render_frame_id_;
-}
-
 int32_t URLLoader::GetProcessId() const {
   return factory_params_->process_id;
 }
diff --git a/services/network/url_loader.h b/services/network/url_loader.h
index f8c61123..e8f8e720 100644
--- a/services/network/url_loader.h
+++ b/services/network/url_loader.h
@@ -198,7 +198,6 @@
 
   net::LoadState GetLoadStateForTesting() const;
 
-  int32_t GetRenderFrameId() const;
   int32_t GetProcessId() const;
   uint32_t GetResourceType() const;
 
@@ -414,7 +413,6 @@
   // This also belongs to URLLoaderFactory and outlives this loader.
   mojom::CrossOriginEmbedderPolicyReporter* const coep_reporter_;
 
-  int render_frame_id_;
   uint32_t request_id_;
   const int keepalive_request_size_;
   const bool keepalive_;
diff --git a/services/video_capture/BUILD.gn b/services/video_capture/BUILD.gn
index ef795f2f..ba597d2 100644
--- a/services/video_capture/BUILD.gn
+++ b/services/video_capture/BUILD.gn
@@ -58,26 +58,9 @@
     "//media/capture:capture_switches",
   ]
 
-  if (is_chromeos) {
-    deps += [ "//chromeos/crosapi/mojom" ]
-  }
-
   if (is_chromeos_ash) {
     public_deps += [ "//media/capture/video/chromeos/mojom:cros_camera" ]
   }
-
-  if (is_chromeos_lacros) {
-    sources += [
-      "lacros/device_factory_adapter_lacros.cc",
-      "lacros/device_factory_adapter_lacros.h",
-      "lacros/device_proxy_lacros.cc",
-      "lacros/device_proxy_lacros.h",
-      "lacros/video_frame_handler_proxy_lacros.cc",
-      "lacros/video_frame_handler_proxy_lacros.h",
-    ]
-
-    deps += [ "//chromeos/lacros" ]
-  }
 }
 
 source_set("tests") {
diff --git a/services/video_capture/DEPS b/services/video_capture/DEPS
index 250a48f..16163ad 100644
--- a/services/video_capture/DEPS
+++ b/services/video_capture/DEPS
@@ -1,10 +1,8 @@
 include_rules = [
-  "+chromeos/crosapi",
-  "+chromeos/lacros",
   "+gpu/command_buffer/client",
   "+media/base",
   "+media/mojo",
   "+media/capture",
-  "+ui/gfx",
+  "+ui/gfx/geometry",
   "+services/viz/public/cpp/gpu",
 ]
diff --git a/services/video_capture/lacros/OWNERS b/services/video_capture/lacros/OWNERS
deleted file mode 100644
index 6f44092..0000000
--- a/services/video_capture/lacros/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-wtlee@chromium.org
-shik@chromium.org
diff --git a/services/video_capture/lacros/device_factory_adapter_lacros.cc b/services/video_capture/lacros/device_factory_adapter_lacros.cc
deleted file mode 100644
index cbd3ab5..0000000
--- a/services/video_capture/lacros/device_factory_adapter_lacros.cc
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright 2021 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 "services/video_capture/lacros/device_factory_adapter_lacros.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/check.h"
-#include "base/notreached.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "services/video_capture/lacros/device_proxy_lacros.h"
-#include "services/video_capture/public/uma/video_capture_service_event.h"
-
-namespace video_capture {
-
-DeviceFactoryAdapterLacros::DeviceFactoryAdapterLacros(
-    mojo::PendingRemote<crosapi::mojom::VideoCaptureDeviceFactory>
-        device_factory_ash)
-    : device_factory_ash_(std::move(device_factory_ash)) {}
-
-DeviceFactoryAdapterLacros::~DeviceFactoryAdapterLacros() = default;
-
-void DeviceFactoryAdapterLacros::GetDeviceInfos(
-    GetDeviceInfosCallback callback) {
-  DCHECK(device_factory_ash_.is_bound());
-  device_factory_ash_->GetDeviceInfos(std::move(callback));
-}
-
-void DeviceFactoryAdapterLacros::CreateDevice(
-    const std::string& device_id,
-    mojo::PendingReceiver<mojom::Device> device_receiver,
-    CreateDeviceCallback callback) {
-  DCHECK(device_factory_ash_.is_bound());
-  mojo::PendingRemote<crosapi::mojom::VideoCaptureDevice> proxy_remote;
-  auto proxy_receiver = proxy_remote.InitWithNewPipeAndPassReceiver();
-  // Since |device_proxy| is owned by this instance and the cleanup callback is
-  // only called within the lifetime of |device_proxy|, it should be safe to use
-  // base::Unretained(this) here.
-  auto device_proxy = std::make_unique<DeviceProxyLacros>(
-      std::move(device_receiver), std::move(proxy_remote),
-      base::BindOnce(
-          &DeviceFactoryAdapterLacros::OnClientConnectionErrorOrClose,
-          base::Unretained(this), device_id));
-
-  auto wrapped_callback = base::BindOnce(
-      [](CreateDeviceCallback callback,
-         crosapi::mojom::DeviceAccessResultCode code) {
-        video_capture::mojom::DeviceAccessResultCode video_capture_result_code;
-        switch (code) {
-          case crosapi::mojom::DeviceAccessResultCode::NOT_INITIALIZED:
-            video_capture_result_code =
-                video_capture::mojom::DeviceAccessResultCode::NOT_INITIALIZED;
-            break;
-          case crosapi::mojom::DeviceAccessResultCode::SUCCESS:
-            video_capture_result_code =
-                video_capture::mojom::DeviceAccessResultCode::SUCCESS;
-            break;
-          case crosapi::mojom::DeviceAccessResultCode::ERROR_DEVICE_NOT_FOUND:
-            video_capture_result_code = video_capture::mojom::
-                DeviceAccessResultCode::ERROR_DEVICE_NOT_FOUND;
-            break;
-          default:
-            NOTREACHED() << "Unexpected device access result code";
-        }
-        std::move(callback).Run(video_capture_result_code);
-      },
-      std::move(callback));
-
-  devices_.emplace(device_id, std::move(device_proxy));
-  device_factory_ash_->CreateDevice(device_id, std::move(proxy_receiver),
-                                    std::move(wrapped_callback));
-}
-
-void DeviceFactoryAdapterLacros::AddSharedMemoryVirtualDevice(
-    const media::VideoCaptureDeviceInfo& device_info,
-    mojo::PendingRemote<mojom::Producer> producer,
-    bool send_buffer_handles_to_producer_as_raw_file_descriptors,
-    mojo::PendingReceiver<mojom::SharedMemoryVirtualDevice>
-        virtual_device_receiver) {
-  NOTREACHED();
-}
-
-void DeviceFactoryAdapterLacros::AddTextureVirtualDevice(
-    const media::VideoCaptureDeviceInfo& device_info,
-    mojo::PendingReceiver<mojom::TextureVirtualDevice>
-        virtual_device_receiver) {
-  NOTREACHED();
-}
-
-void DeviceFactoryAdapterLacros::AddGpuMemoryBufferVirtualDevice(
-    const media::VideoCaptureDeviceInfo& device_info,
-    mojo::PendingReceiver<mojom::GpuMemoryBufferVirtualDevice>
-        virtual_device_receiver) {
-  NOTREACHED();
-}
-
-void DeviceFactoryAdapterLacros::RegisterVirtualDevicesChangedObserver(
-    mojo::PendingRemote<mojom::DevicesChangedObserver> observer,
-    bool raise_event_if_virtual_devices_already_present) {
-  NOTREACHED();
-}
-
-void DeviceFactoryAdapterLacros::OnClientConnectionErrorOrClose(
-    std::string device_id) {
-  video_capture::uma::LogVideoCaptureServiceEvent(
-      video_capture::uma::SERVICE_LOST_CONNECTION_TO_BROWSER);
-
-  devices_.erase(device_id);
-}
-
-}  // namespace video_capture
diff --git a/services/video_capture/lacros/device_factory_adapter_lacros.h b/services/video_capture/lacros/device_factory_adapter_lacros.h
deleted file mode 100644
index 08789c4..0000000
--- a/services/video_capture/lacros/device_factory_adapter_lacros.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2021 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 SERVICES_VIDEO_CAPTURE_LACROS_DEVICE_FACTORY_ADAPTER_LACROS_H_
-#define SERVICES_VIDEO_CAPTURE_LACROS_DEVICE_FACTORY_ADAPTER_LACROS_H_
-
-#include <memory>
-#include <string>
-
-#include "base/containers/flat_map.h"
-#include "chromeos/crosapi/mojom/video_capture.mojom.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "services/video_capture/device_factory.h"
-#include "services/video_capture/public/mojom/device_factory.mojom.h"
-
-namespace video_capture {
-
-class DeviceProxyLacros;
-
-// A proxy which forwards the requests to the actual
-// video_capture::DeviceFactory in Ash-Chrome.
-class DeviceFactoryAdapterLacros : public DeviceFactory {
- public:
-  explicit DeviceFactoryAdapterLacros(
-      mojo::PendingRemote<crosapi::mojom::VideoCaptureDeviceFactory>
-          device_factory_ash);
-  DeviceFactoryAdapterLacros(const DeviceFactoryAdapterLacros&) = delete;
-  DeviceFactoryAdapterLacros& operator=(const DeviceFactoryAdapterLacros&) =
-      delete;
-  ~DeviceFactoryAdapterLacros() override;
-
- private:
-  // DeviceFactory implementation.
-  void GetDeviceInfos(GetDeviceInfosCallback callback) override;
-  void CreateDevice(const std::string& device_id,
-                    mojo::PendingReceiver<mojom::Device> device_receiver,
-                    CreateDeviceCallback callback) override;
-  void AddSharedMemoryVirtualDevice(
-      const media::VideoCaptureDeviceInfo& device_info,
-      mojo::PendingRemote<mojom::Producer> producer,
-      bool send_buffer_handles_to_producer_as_raw_file_descriptors,
-      mojo::PendingReceiver<mojom::SharedMemoryVirtualDevice>
-          virtual_device_receiver) override;
-  void AddTextureVirtualDevice(
-      const media::VideoCaptureDeviceInfo& device_info,
-      mojo::PendingReceiver<mojom::TextureVirtualDevice>
-          virtual_device_receiver) override;
-  void AddGpuMemoryBufferVirtualDevice(
-      const media::VideoCaptureDeviceInfo& device_info,
-      mojo::PendingReceiver<mojom::GpuMemoryBufferVirtualDevice>
-          virtual_device_receiver) override;
-  void RegisterVirtualDevicesChangedObserver(
-      mojo::PendingRemote<mojom::DevicesChangedObserver> observer,
-      bool raise_event_if_virtual_devices_already_present) override;
-
-  void OnClientConnectionErrorOrClose(std::string device_id);
-
-  mojo::Remote<crosapi::mojom::VideoCaptureDeviceFactory> device_factory_ash_;
-
-  // The key is the device id used in blink::MediaStreamDevice.
-  base::flat_map<std::string, std::unique_ptr<DeviceProxyLacros>> devices_;
-};
-
-}  // namespace video_capture
-
-#endif  // SERVICES_VIDEO_CAPTURE_LACROS_DEVICE_FACTORY_ADAPTER_LACROS_H_
diff --git a/services/video_capture/lacros/device_proxy_lacros.cc b/services/video_capture/lacros/device_proxy_lacros.cc
deleted file mode 100644
index 59740da0..0000000
--- a/services/video_capture/lacros/device_proxy_lacros.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2021 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 "services/video_capture/lacros/device_proxy_lacros.h"
-
-#include <memory>
-#include <utility>
-
-#include "services/video_capture/lacros/video_frame_handler_proxy_lacros.h"
-
-namespace video_capture {
-
-DeviceProxyLacros::DeviceProxyLacros(
-    mojo::PendingReceiver<mojom::Device> device_receiver,
-    mojo::PendingRemote<crosapi::mojom::VideoCaptureDevice> proxy_remote,
-    base::OnceClosure cleanup_callback)
-    : device_(std::move(proxy_remote)) {
-  receiver_.Bind(std::move(device_receiver));
-  receiver_.set_disconnect_handler(std::move(cleanup_callback));
-}
-
-DeviceProxyLacros::~DeviceProxyLacros() = default;
-
-void DeviceProxyLacros::Start(
-    const media::VideoCaptureParams& requested_settings,
-    mojo::PendingRemote<mojom::VideoFrameHandler> handler) {
-  mojo::PendingRemote<crosapi::mojom::VideoFrameHandler> proxy_handler_remote;
-  handler_ = std::make_unique<VideoFrameHandlerProxyLacros>(
-      proxy_handler_remote.InitWithNewPipeAndPassReceiver(),
-      std::move(handler));
-  device_->Start(std::move(requested_settings),
-                 std::move(proxy_handler_remote));
-}
-
-void DeviceProxyLacros::MaybeSuspend() {
-  device_->MaybeSuspend();
-}
-
-void DeviceProxyLacros::Resume() {
-  device_->Resume();
-}
-
-void DeviceProxyLacros::GetPhotoState(GetPhotoStateCallback callback) {
-  device_->GetPhotoState(std::move(callback));
-}
-
-void DeviceProxyLacros::SetPhotoOptions(media::mojom::PhotoSettingsPtr settings,
-                                        SetPhotoOptionsCallback callback) {
-  device_->SetPhotoOptions(std::move(settings), std::move(callback));
-}
-
-void DeviceProxyLacros::TakePhoto(TakePhotoCallback callback) {
-  device_->TakePhoto(std::move(callback));
-}
-
-void DeviceProxyLacros::ProcessFeedback(
-    const media::VideoFrameFeedback& feedback) {
-  device_->ProcessFeedback(std::move(feedback));
-}
-
-}  // namespace video_capture
diff --git a/services/video_capture/lacros/device_proxy_lacros.h b/services/video_capture/lacros/device_proxy_lacros.h
deleted file mode 100644
index b7ce0e5..0000000
--- a/services/video_capture/lacros/device_proxy_lacros.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2021 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 SERVICES_VIDEO_CAPTURE_LACROS_DEVICE_PROXY_LACROS_H_
-#define SERVICES_VIDEO_CAPTURE_LACROS_DEVICE_PROXY_LACROS_H_
-
-#include <memory>
-
-#include "chromeos/crosapi/mojom/video_capture.mojom.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "services/video_capture/public/mojom/device.mojom.h"
-
-namespace video_capture {
-
-class VideoFrameHandlerProxyLacros;
-
-// A proxy which is used for communication between the client on Lacros-Chrome
-// and the actual video_capture::Device in Ash-Chrome.
-class DeviceProxyLacros : public mojom::Device {
- public:
-  DeviceProxyLacros(
-      mojo::PendingReceiver<mojom::Device> device_receiver,
-      mojo::PendingRemote<crosapi::mojom::VideoCaptureDevice> proxy_remote,
-      base::OnceClosure cleanup_callback);
-  DeviceProxyLacros(const DeviceProxyLacros&) = delete;
-  DeviceProxyLacros& operator=(const DeviceProxyLacros&) = delete;
-  ~DeviceProxyLacros() override;
-
- private:
-  // mojom::Device implementation.
-  void Start(const media::VideoCaptureParams& requested_settings,
-             mojo::PendingRemote<mojom::VideoFrameHandler> handler) override;
-  void MaybeSuspend() override;
-  void Resume() override;
-  void GetPhotoState(GetPhotoStateCallback callback) override;
-  void SetPhotoOptions(media::mojom::PhotoSettingsPtr settings,
-                       SetPhotoOptionsCallback callback) override;
-  void TakePhoto(TakePhotoCallback callback) override;
-  void ProcessFeedback(const media::VideoFrameFeedback& feedback) override;
-
-  std::unique_ptr<VideoFrameHandlerProxyLacros> handler_;
-
-  mojo::Receiver<mojom::Device> receiver_{this};
-
-  mojo::Remote<crosapi::mojom::VideoCaptureDevice> device_;
-};
-
-}  // namespace video_capture
-
-#endif  // SERVICES_VIDEO_CAPTURE_LACROS_DEVICE_PROXY_LACROS_H_
diff --git a/services/video_capture/lacros/video_frame_handler_proxy_lacros.cc b/services/video_capture/lacros/video_frame_handler_proxy_lacros.cc
deleted file mode 100644
index 10b2a91e..0000000
--- a/services/video_capture/lacros/video_frame_handler_proxy_lacros.cc
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright 2021 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 "services/video_capture/lacros/video_frame_handler_proxy_lacros.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/notreached.h"
-#include "mojo/public/cpp/bindings/self_owned_receiver.h"
-#include "ui/gfx/gpu_memory_buffer.h"
-#include "ui/gfx/mojom/buffer_types.mojom.h"
-#include "ui/gfx/mojom/native_handle_types.mojom.h"
-
-namespace video_capture {
-
-namespace {
-
-mojom::ReadyFrameInBufferPtr ToVideoCaptureBuffer(
-    crosapi::mojom::ReadyFrameInBufferPtr buffer) {
-  auto video_capture_buffer = mojom::ReadyFrameInBuffer::New();
-  video_capture_buffer->buffer_id = buffer->buffer_id;
-  video_capture_buffer->frame_feedback_id = buffer->frame_feedback_id;
-
-  mojo::PendingRemote<mojom::ScopedAccessPermission> access_permission;
-  mojo::MakeSelfOwnedReceiver(
-      std::make_unique<VideoFrameHandlerProxyLacros::AccessPermissionProxy>(
-          std::move(buffer->access_permission)),
-      access_permission.InitWithNewPipeAndPassReceiver());
-  video_capture_buffer->access_permission = std::move(access_permission);
-
-  const auto& buffer_info = buffer->frame_info;
-  auto video_capture_buffer_info = media::mojom::VideoFrameInfo::New();
-  video_capture_buffer_info->timestamp = buffer_info->timestamp;
-  video_capture_buffer_info->pixel_format = buffer_info->pixel_format;
-  video_capture_buffer_info->coded_size = buffer_info->coded_size;
-  video_capture_buffer_info->visible_rect = buffer_info->visible_rect;
-
-  media::VideoFrameMetadata media_frame_metadata;
-  switch (buffer_info->rotation) {
-    case crosapi::mojom::VideoRotation::kVideoRotation0:
-      media_frame_metadata.transformation =
-          media::VideoTransformation(media::VideoRotation::VIDEO_ROTATION_0);
-      break;
-    case crosapi::mojom::VideoRotation::kVideoRotation90:
-      media_frame_metadata.transformation =
-          media::VideoTransformation(media::VideoRotation::VIDEO_ROTATION_90);
-      break;
-    case crosapi::mojom::VideoRotation::kVideoRotation180:
-      media_frame_metadata.transformation =
-          media::VideoTransformation(media::VideoRotation::VIDEO_ROTATION_180);
-      break;
-    case crosapi::mojom::VideoRotation::kVideoRotation270:
-      media_frame_metadata.transformation =
-          media::VideoTransformation(media::VideoRotation::VIDEO_ROTATION_270);
-      break;
-    default:
-      NOTREACHED() << "Unexpected rotation in video frame metadata";
-  }
-  media_frame_metadata.reference_time = buffer_info->reference_time;
-
-  video_capture_buffer_info->metadata = std::move(media_frame_metadata);
-  video_capture_buffer->frame_info = std::move(video_capture_buffer_info);
-
-  return video_capture_buffer;
-}
-
-gfx::GpuMemoryBufferHandle ToGfxGpuMemoryBufferHandle(
-    crosapi::mojom::GpuMemoryBufferHandlePtr buffer_handle) {
-  gfx::GpuMemoryBufferHandle gfx_buffer_handle;
-  gfx_buffer_handle.id = gfx::GpuMemoryBufferId(buffer_handle->id);
-  gfx_buffer_handle.offset = buffer_handle->offset;
-  gfx_buffer_handle.stride = buffer_handle->stride;
-
-  if (buffer_handle->platform_handle) {
-    auto& platform_handle = buffer_handle->platform_handle;
-    if (platform_handle->is_shared_memory_handle()) {
-      gfx_buffer_handle.region =
-          std::move(platform_handle->get_shared_memory_handle());
-    } else if (platform_handle->is_native_pixmap_handle()) {
-      auto& native_pixmap_handle = platform_handle->get_native_pixmap_handle();
-      gfx::NativePixmapHandle gfx_native_pixmap_handle;
-      gfx_native_pixmap_handle.planes = std::move(native_pixmap_handle->planes);
-      gfx_native_pixmap_handle.modifier = native_pixmap_handle->modifier;
-      gfx_buffer_handle.native_pixmap_handle =
-          std::move(gfx_native_pixmap_handle);
-    }
-  }
-  return gfx_buffer_handle;
-}
-
-}  // namespace
-
-VideoFrameHandlerProxyLacros::VideoFrameHandlerProxyLacros(
-    mojo::PendingReceiver<crosapi::mojom::VideoFrameHandler> proxy_receiver,
-    mojo::PendingRemote<mojom::VideoFrameHandler> handler_remote)
-    : handler_(std::move(handler_remote)) {
-  receiver_.Bind(std::move(proxy_receiver));
-}
-
-VideoFrameHandlerProxyLacros::~VideoFrameHandlerProxyLacros() = default;
-
-VideoFrameHandlerProxyLacros::AccessPermissionProxy::AccessPermissionProxy(
-    mojo::PendingRemote<crosapi::mojom::ScopedAccessPermission> remote)
-    : remote_(std::move(remote)) {}
-
-VideoFrameHandlerProxyLacros::AccessPermissionProxy::~AccessPermissionProxy() =
-    default;
-
-void VideoFrameHandlerProxyLacros::OnNewBuffer(
-    int buffer_id,
-    crosapi::mojom::VideoBufferHandlePtr buffer_handle) {
-  media::mojom::VideoBufferHandlePtr media_handle =
-      media::mojom::VideoBufferHandle::New();
-
-  if (buffer_handle->is_shared_buffer_handle()) {
-    media_handle->set_shared_buffer_handle(
-        buffer_handle->get_shared_buffer_handle()->Clone(
-            mojo::SharedBufferHandle::AccessMode::READ_WRITE));
-  } else if (buffer_handle->is_gpu_memory_buffer_handle()) {
-    media_handle->set_gpu_memory_buffer_handle(ToGfxGpuMemoryBufferHandle(
-        std::move(buffer_handle->get_gpu_memory_buffer_handle())));
-  } else {
-    NOTREACHED() << "Unexpected new buffer type";
-  }
-  handler_->OnNewBuffer(buffer_id, std::move(media_handle));
-}
-
-void VideoFrameHandlerProxyLacros::OnFrameReadyInBuffer(
-    crosapi::mojom::ReadyFrameInBufferPtr buffer,
-    std::vector<crosapi::mojom::ReadyFrameInBufferPtr> scaled_buffers) {
-  mojom::ReadyFrameInBufferPtr video_capture_buffer =
-      ToVideoCaptureBuffer(std::move(buffer));
-  std::vector<mojom::ReadyFrameInBufferPtr> video_capture_scaled_buffers;
-  for (auto& b : scaled_buffers)
-    video_capture_scaled_buffers.push_back(ToVideoCaptureBuffer(std::move(b)));
-
-  handler_->OnFrameReadyInBuffer(std::move(video_capture_buffer),
-                                 std::move(video_capture_scaled_buffers));
-}
-
-void VideoFrameHandlerProxyLacros::OnBufferRetired(int buffer_id) {
-  handler_->OnBufferRetired(buffer_id);
-}
-
-void VideoFrameHandlerProxyLacros::OnError(media::VideoCaptureError error) {
-  handler_->OnError(error);
-}
-
-void VideoFrameHandlerProxyLacros::OnFrameDropped(
-    media::VideoCaptureFrameDropReason reason) {
-  handler_->OnFrameDropped(reason);
-}
-
-void VideoFrameHandlerProxyLacros::OnLog(const std::string& message) {
-  handler_->OnLog(message);
-}
-
-void VideoFrameHandlerProxyLacros::OnStarted() {
-  handler_->OnStarted();
-}
-
-void VideoFrameHandlerProxyLacros::OnStartedUsingGpuDecode() {
-  handler_->OnStartedUsingGpuDecode();
-}
-
-void VideoFrameHandlerProxyLacros::OnStopped() {
-  handler_->OnStopped();
-}
-
-}  // namespace video_capture
diff --git a/services/video_capture/lacros/video_frame_handler_proxy_lacros.h b/services/video_capture/lacros/video_frame_handler_proxy_lacros.h
deleted file mode 100644
index 3cc1e2e..0000000
--- a/services/video_capture/lacros/video_frame_handler_proxy_lacros.h
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2021 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 SERVICES_VIDEO_CAPTURE_LACROS_VIDEO_FRAME_HANDLER_PROXY_LACROS_H_
-#define SERVICES_VIDEO_CAPTURE_LACROS_VIDEO_FRAME_HANDLER_PROXY_LACROS_H_
-
-#include <string>
-
-#include "chromeos/crosapi/mojom/video_capture.mojom.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "services/video_capture/public/mojom/video_frame_handler.mojom.h"
-
-namespace video_capture {
-
-// A proxy which is used for communication between the actual handler in
-// Lacros-Chrome and the video_capture::Device in Ash-Chrome. Since we
-// have simplified some structures in crosapi video capture interface to reduce
-// dependencies to other components, this class should also be responsible for
-// translating those structures between the interfaces.
-class VideoFrameHandlerProxyLacros : public crosapi::mojom::VideoFrameHandler {
- public:
-  VideoFrameHandlerProxyLacros(
-      mojo::PendingReceiver<crosapi::mojom::VideoFrameHandler> proxy_receiver,
-      mojo::PendingRemote<mojom::VideoFrameHandler> handler_remote);
-  VideoFrameHandlerProxyLacros(const VideoFrameHandlerProxyLacros&) = delete;
-  VideoFrameHandlerProxyLacros& operator=(const VideoFrameHandlerProxyLacros&) =
-      delete;
-  ~VideoFrameHandlerProxyLacros() override;
-
-  class AccessPermissionProxy : public mojom::ScopedAccessPermission {
-   public:
-    AccessPermissionProxy(
-        mojo::PendingRemote<crosapi::mojom::ScopedAccessPermission> remote);
-    AccessPermissionProxy(const AccessPermissionProxy&) = delete;
-    AccessPermissionProxy& operator=(const AccessPermissionProxy&) = delete;
-    ~AccessPermissionProxy() override;
-
-   private:
-    mojo::Remote<crosapi::mojom::ScopedAccessPermission> remote_;
-  };
-
- private:
-  // crosapi::mojom::VideoFrameHandler implementation.
-  void OnNewBuffer(int buffer_id,
-                   crosapi::mojom::VideoBufferHandlePtr buffer_handle) override;
-  void OnFrameReadyInBuffer(crosapi::mojom::ReadyFrameInBufferPtr buffer,
-                            std::vector<crosapi::mojom::ReadyFrameInBufferPtr>
-                                scaled_buffers) override;
-  void OnBufferRetired(int buffer_id) override;
-  void OnError(media::VideoCaptureError error) override;
-  void OnFrameDropped(media::VideoCaptureFrameDropReason reason) override;
-  void OnLog(const std::string& message) override;
-  void OnStarted() override;
-  void OnStartedUsingGpuDecode() override;
-  void OnStopped() override;
-
-  mojo::Receiver<crosapi::mojom::VideoFrameHandler> receiver_{this};
-
-  mojo::Remote<mojom::VideoFrameHandler> handler_;
-};
-
-}  // namespace video_capture
-
-#endif  // SERVICES_VIDEO_CAPTURE_LACROS_VIDEO_FRAME_HANDLER_PROXY_LACROS_H_
diff --git a/services/video_capture/video_capture_service_impl.cc b/services/video_capture/video_capture_service_impl.cc
index f7350a9..1b82ce7 100644
--- a/services/video_capture/video_capture_service_impl.cc
+++ b/services/video_capture/video_capture_service_impl.cc
@@ -36,12 +36,6 @@
 #include "media/capture/video/chromeos/camera_app_device_bridge_impl.h"
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-#include "chromeos/crosapi/mojom/video_capture.mojom.h"
-#include "chromeos/lacros/lacros_chrome_service_impl.h"
-#include "services/video_capture/lacros/device_factory_adapter_lacros.h"
-#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
-
 namespace video_capture {
 
 // Intended usage of this class is to instantiate on any sequence, and then
@@ -190,26 +184,6 @@
               &GpuDependenciesContext::CreateJpegDecodeAccelerator,
               gpu_dependencies_context_->GetWeakPtr()),
           gpu_dependencies_context_->GetTaskRunner()));
-#elif BUILDFLAG(IS_CHROMEOS_LACROS)
-  auto* lacros_chrome_service = chromeos::LacrosChromeServiceImpl::Get();
-  DCHECK(lacros_chrome_service) << "Failed to get Lacros Chrome Service";
-
-  if (!lacros_chrome_service->IsVideoCaptureDeviceFactoryAvailable()) {
-    LOG(WARNING)
-        << "Connected to an older version of ash. Use device factory in "
-           "Lacros-Chrome which is backed by Linux VCD instead of CrOS VCD.";
-    device_factory_ = std::make_unique<VirtualDeviceEnabledDeviceFactory>(
-        std::make_unique<DeviceFactoryMediaToMojoAdapter>(
-            std::move(video_capture_system)));
-  } else {
-    mojo::PendingRemote<crosapi::mojom::VideoCaptureDeviceFactory>
-        device_factory_ash;
-    lacros_chrome_service->BindVideoCaptureDeviceFactory(
-        device_factory_ash.InitWithNewPipeAndPassReceiver());
-    device_factory_ = std::make_unique<VirtualDeviceEnabledDeviceFactory>(
-        std::make_unique<DeviceFactoryAdapterLacros>(
-            std::move(device_factory_ash)));
-  }
 #else
   device_factory_ = std::make_unique<VirtualDeviceEnabledDeviceFactory>(
       std::make_unique<DeviceFactoryMediaToMojoAdapter>(
diff --git a/testing/buildbot/trybot_analyze_config.json b/testing/buildbot/trybot_analyze_config.json
index a6fa4488..1af8054 100644
--- a/testing/buildbot/trybot_analyze_config.json
+++ b/testing/buildbot/trybot_analyze_config.json
@@ -14,8 +14,8 @@
       "build/get_landmines.py",
       "build/gn_helpers.py",
       "build/mac_toolchain.py",
+      "build/toolchain/apple/.*py",
       "build/toolchain/get_concurrent_links.py",
-      "build/toolchain/mac/.*py",
       "build/util/lib/common/unittest_util.py",
       "build/vs_toolchain.py",
       "DEPS",
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 7689251..e943e56 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -3222,34 +3222,6 @@
             ]
         }
     ],
-    "FreezeBackgroundTabOnNetworkIdle": [
-        {
-            "platforms": [
-                "android",
-                "android_weblayer"
-            ],
-            "experiments": [
-                {
-                    "name": "enable_1min",
-                    "params": {
-                        "DelayForBackgroundAndNetworkIdleTabFreezingMills": "60000"
-                    },
-                    "enable_features": [
-                        "freeze-background-tab-on-network-idle"
-                    ]
-                },
-                {
-                    "name": "enable_3min",
-                    "params": {
-                        "DelayForBackgroundAndNetworkIdleTabFreezingMills": "180000"
-                    },
-                    "enable_features": [
-                        "freeze-background-tab-on-network-idle"
-                    ]
-                }
-            ]
-        }
-    ],
     "FuzzyAppSearch": [
         {
             "platforms": [
@@ -3693,18 +3665,6 @@
             ]
         }
     ],
-    "InstantApps": [
-        {
-            "platforms": [
-                "android"
-            ],
-            "experiments": [
-                {
-                    "name": "InstantAppsEnabled"
-                }
-            ]
-        }
-    ],
     "IntentBlockExternalFormRedirectsNoGesture": [
         {
             "platforms": [
@@ -4483,7 +4443,7 @@
                     "name": "EnabledDefault",
                     "params": {
                         "colorful_mic": "false",
-                        "min_agsa_version": "12.7.2.23"
+                        "min_agsa_version": "12.8.4"
                     },
                     "enable_features": [
                         "OmniboxAssistantVoiceSearch"
@@ -4493,7 +4453,7 @@
                     "name": "EnabledColorfulMic",
                     "params": {
                         "colorful_mic": "true",
-                        "min_agsa_version": "12.7.2.23"
+                        "min_agsa_version": "12.8.4"
                     },
                     "enable_features": [
                         "OmniboxAssistantVoiceSearch"
@@ -4954,56 +4914,6 @@
             ]
         }
     ],
-    "PartitionAllocGigaCage": [
-        {
-            "platforms": [
-                "android",
-                "android_webview",
-                "chromeos",
-                "chromeos_lacros",
-                "ios",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled_Mobile",
-                    "enable_features": [
-                        "PartitionAllocGigaCage"
-                    ]
-                },
-                {
-                    "name": "Enabled_V3",
-                    "enable_features": [
-                        "PartitionAllocGigaCage"
-                    ]
-                }
-            ]
-        }
-    ],
-    "PartitionAllocGigaCage32bit": [
-        {
-            "platforms": [
-                "android",
-                "android_webview",
-                "chromeos",
-                "chromeos_lacros",
-                "ios",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "PartitionAllocGigaCage32bit"
-                    ]
-                }
-            ]
-        }
-    ],
     "PartitionAllocThreadCachePeriodicPurge": [
         {
             "platforms": [
@@ -6708,25 +6618,6 @@
             ]
         }
     ],
-    "TranslateCompactUI": [
-        {
-            "platforms": [
-                "android",
-                "android_weblayer"
-            ],
-            "experiments": [
-                {
-                    "name": "DarkerColor",
-                    "params": {
-                        "translate_tab_default_text_color": "1"
-                    },
-                    "enable_features": [
-                        "TranslateCompactUI"
-                    ]
-                }
-            ]
-        }
-    ],
     "TranslateRankerModel": [
         {
             "platforms": [
@@ -7670,27 +7561,6 @@
             ]
         }
     ],
-    "WebSocketReassembleShortMessages": [
-        {
-            "platforms": [
-                "android",
-                "android_webview",
-                "chromeos",
-                "chromeos_lacros",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "DisabledBeta",
-                    "disable_features": [
-                        "WebSocketReassembleShortMessages"
-                    ]
-                }
-            ]
-        }
-    ],
     "WebUITabStrip": [
         {
             "platforms": [
diff --git a/third_party/android_provider/README.chromium b/third_party/android_provider/README.chromium
index 17b5d8a..0027850 100644
--- a/third_party/android_provider/README.chromium
+++ b/third_party/android_provider/README.chromium
@@ -16,3 +16,4 @@
 - Added logs
 - Introduced some helper method.
 - Add @TargetApi(Build.VERSION_CODES.Q).
+- Catch an exception thrown by ContentResolver.delete()
diff --git a/third_party/android_provider/java/src/org/chromium/third_party/android/provider/MediaStoreUtils.java b/third_party/android_provider/java/src/org/chromium/third_party/android/provider/MediaStoreUtils.java
index 28b26c40..e102f0b 100644
--- a/third_party/android_provider/java/src/org/chromium/third_party/android/provider/MediaStoreUtils.java
+++ b/third_party/android_provider/java/src/org/chromium/third_party/android/provider/MediaStoreUtils.java
@@ -210,7 +210,11 @@
          * destroy the pending item record and any data related to it.
          */
         public void abandon() {
-            mContext.getContentResolver().delete(mUri, null, null);
+            try {
+                mContext.getContentResolver().delete(mUri, null, null);
+            } catch (Exception e) {
+                Log.e(TAG, "Unable to delete pending session.", e);
+            }
         }
 
         @Override
diff --git a/third_party/blink/common/loader/throttling_url_loader.cc b/third_party/blink/common/loader/throttling_url_loader.cc
index 6f7cb48..bc114fc 100644
--- a/third_party/blink/common/loader/throttling_url_loader.cc
+++ b/third_party/blink/common/loader/throttling_url_loader.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/public/common/loader/throttling_url_loader.h"
 
 #include "base/bind.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -68,6 +69,22 @@
 }
 #endif
 
+void RecordHistogram(const std::string& stage,
+                     base::Time start,
+                     const std::string& metric_type) {
+  base::TimeDelta delta = base::Time::Now() - start;
+  base::UmaHistogramTimes(
+      base::StrCat({"Net.URLLoaderThrottle", metric_type, ".", stage}), delta);
+}
+
+void RecordDeferTimeHistogram(const std::string& stage, base::Time start) {
+  RecordHistogram(stage, start, "DeferTime");
+}
+
+void RecordExecutionTimeHistogram(const std::string& stage, base::Time start) {
+  RecordHistogram(stage, start, "ExecutionTime");
+}
+
 }  // namespace
 
 const char ThrottlingURLLoader::kFollowRedirectReason[] = "FollowRedirect";
@@ -438,7 +455,10 @@
       }
 #endif
 
+      base::Time start = base::Time::Now();
       throttle->WillStartRequest(url_request, &throttle_deferred);
+      RecordExecutionTimeHistogram(GetStageNameForHistogram(DEFERRED_START),
+                                   start);
 
 #if DCHECK_IS_ON()
       if (cors_exempt_header_list) {
@@ -575,16 +595,21 @@
     return false;
   *should_defer |= throttle_deferred;
   if (throttle_deferred)
-    deferring_throttles_.insert(throttle);
+    deferring_throttles_.insert({throttle, base::Time::Now()});
   return true;
 }
 
 void ThrottlingURLLoader::StopDeferringForThrottle(
     URLLoaderThrottle* throttle) {
-  if (deferring_throttles_.find(throttle) == deferring_throttles_.end())
+  auto iter = deferring_throttles_.find(throttle);
+  if (iter == deferring_throttles_.end())
     return;
 
-  deferring_throttles_.erase(throttle);
+  if (deferred_stage_ != DEFERRED_NONE) {
+    RecordDeferTimeHistogram(GetStageNameForHistogram(deferred_stage_),
+                             iter->second);
+  }
+  deferring_throttles_.erase(iter);
   if (deferring_throttles_.empty() && !loader_completed_)
     Resume();
 }
@@ -641,8 +666,11 @@
     for (auto& entry : throttles_) {
       auto* throttle = entry.throttle.get();
       bool throttle_deferred = false;
+      base::Time start = base::Time::Now();
       throttle->BeforeWillProcessResponse(response_url_, *response_head,
                                           &throttle_deferred);
+      RecordExecutionTimeHistogram(
+          GetStageNameForHistogram(DEFERRED_BEFORE_RESPONSE), start);
       if (!HandleThrottleResult(throttle, throttle_deferred, &deferred))
         return;
     }
@@ -665,8 +693,11 @@
     for (auto& entry : throttles_) {
       auto* throttle = entry.throttle.get();
       bool throttle_deferred = false;
+      base::Time start = base::Time::Now();
       throttle->WillProcessResponse(response_url_, response_head.get(),
                                     &throttle_deferred);
+      RecordExecutionTimeHistogram(GetStageNameForHistogram(DEFERRED_RESPONSE),
+                                   start);
       if (!HandleThrottleResult(throttle, throttle_deferred, &deferred))
         return;
     }
@@ -699,6 +730,7 @@
       net::HttpRequestHeaders modified_headers;
       net::HttpRequestHeaders modified_cors_exempt_headers;
       net::RedirectInfo redirect_info_copy = redirect_info;
+      base::Time start = base::Time::Now();
       throttle->WillRedirectRequest(
           &redirect_info_copy, *response_head, &throttle_deferred,
           &removed_headers, &modified_headers, &modified_cors_exempt_headers);
@@ -706,6 +738,8 @@
       if (!weak_ptr)
         return;
 
+      RecordExecutionTimeHistogram(GetStageNameForHistogram(DEFERRED_REDIRECT),
+                                   start);
 #if DCHECK_IS_ON()
       if (start_info_->cors_exempt_header_list) {
         CheckThrottleWillNotCauseCorsPreflight(
@@ -807,7 +841,10 @@
     for (auto& entry : throttles_) {
       auto* throttle = entry.throttle.get();
       bool throttle_deferred = false;
+      base::Time start = base::Time::Now();
       throttle->WillOnCompleteWithError(status, &throttle_deferred);
+      RecordExecutionTimeHistogram(GetStageNameForHistogram(DEFERRED_COMPLETE),
+                                   start);
       if (!HandleThrottleResult(throttle, throttle_deferred, &deferred))
         return;
     }
@@ -995,6 +1032,24 @@
   loader_completed_ = true;
 }
 
+const char* ThrottlingURLLoader::GetStageNameForHistogram(DeferredStage stage) {
+  switch (stage) {
+    case DEFERRED_START:
+      return "WillStartRequest";
+    case DEFERRED_REDIRECT:
+      return "WillRedirectRequest";
+    case DEFERRED_BEFORE_RESPONSE:
+      return "BeforeWillProcessResponse";
+    case DEFERRED_RESPONSE:
+      return "WillProcessResponse";
+    case DEFERRED_COMPLETE:
+      return "WillOnCompleteWithError";
+    default:
+      NOTREACHED();
+  }
+  return "";
+}
+
 ThrottlingURLLoader::ThrottleEntry::ThrottleEntry(
     ThrottlingURLLoader* loader,
     std::unique_ptr<URLLoaderThrottle> the_throttle)
diff --git a/third_party/blink/common/media/watch_time_reporter.cc b/third_party/blink/common/media/watch_time_reporter.cc
index 3cf5182..b693479d 100644
--- a/third_party/blink/common/media/watch_time_reporter.cc
+++ b/third_party/blink/common/media/watch_time_reporter.cc
@@ -94,7 +94,7 @@
   if (is_muted_)
     DCHECK_EQ(volume_, 1.0);
 
-  base::PowerMonitor::AddObserver(this);
+  base::PowerMonitor::AddPowerStateObserver(this);
 
   provider->AcquireWatchTimeRecorder(properties_->Clone(),
                                      recorder_.BindNewPipeAndPassReceiver());
@@ -144,7 +144,7 @@
   // This is our last chance, so finalize now if there's anything remaining.
   in_shutdown_ = true;
   MaybeFinalizeWatchTime(FinalizeTime::IMMEDIATELY);
-  base::PowerMonitor::RemoveObserver(this);
+  base::PowerMonitor::RemovePowerStateObserver(this);
 }
 
 void WatchTimeReporter::OnPlaying() {
diff --git a/third_party/blink/public/common/loader/throttling_url_loader.h b/third_party/blink/public/common/loader/throttling_url_loader.h
index 8a6bbb5..ff9608d29 100644
--- a/third_party/blink/public/common/loader/throttling_url_loader.h
+++ b/third_party/blink/public/common/loader/throttling_url_loader.h
@@ -195,6 +195,8 @@
     DEFERRED_RESPONSE,
     DEFERRED_COMPLETE
   };
+  const char* GetStageNameForHistogram(DeferredStage stage);
+
   DeferredStage deferred_stage_ = DEFERRED_NONE;
   bool loader_completed_ = false;
   bool did_receive_response_ = false;
@@ -215,7 +217,7 @@
   };
 
   std::vector<ThrottleEntry> throttles_;
-  std::set<URLLoaderThrottle*> deferring_throttles_;
+  std::map<URLLoaderThrottle*, /*start=*/base::Time> deferring_throttles_;
   // nullptr is used when this loader is directly requested to pause reading
   // body from net by calling PauseReadingBodyFromNet().
   std::set<URLLoaderThrottle*> pausing_reading_body_from_net_throttles_;
diff --git a/third_party/blink/public/common/media/watch_time_reporter.h b/third_party/blink/public/common/media/watch_time_reporter.h
index 6ae896c9..f4d10f6b 100644
--- a/third_party/blink/public/common/media/watch_time_reporter.h
+++ b/third_party/blink/public/common/media/watch_time_reporter.h
@@ -60,7 +60,7 @@
 //
 // Each seek event will result in a new watch time metric being started and the
 // old metric finalized as accurately as possible.
-class BLINK_COMMON_EXPORT WatchTimeReporter : base::PowerObserver {
+class BLINK_COMMON_EXPORT WatchTimeReporter : base::PowerStateObserver {
  public:
   using GetMediaTimeCB = base::RepeatingCallback<base::TimeDelta(void)>;
   using GetPipelineStatsCB =
@@ -172,12 +172,13 @@
                     scoped_refptr<base::SequencedTaskRunner> task_runner,
                     const base::TickClock* tick_clock);
 
-  // base::PowerObserver implementation.
+  // base::PowerStateObserver implementation.
   //
   // We only observe power source changes. We don't need to observe suspend and
   // resume events because we report watch time in terms of elapsed media time
   // and not in terms of elapsed real time.
   void OnPowerStateChange(bool on_battery_power) override;
+
   void OnNativeControlsChanged(bool has_native_controls);
   void OnDisplayTypeChanged(DisplayType display_type);
 
diff --git a/third_party/blink/public/platform/web_resource_request_sender.h b/third_party/blink/public/platform/web_resource_request_sender.h
index 5a5d5ec9..3e15e1a 100644
--- a/third_party/blink/public/platform/web_resource_request_sender.h
+++ b/third_party/blink/public/platform/web_resource_request_sender.h
@@ -180,7 +180,6 @@
   struct PendingRequestInfo {
     PendingRequestInfo(scoped_refptr<WebRequestPeer> peer,
                        network::mojom::RequestDestination request_destination,
-                       int render_frame_id,
                        const GURL& request_url,
                        std::unique_ptr<ResourceLoadInfoNotifierWrapper>
                            resource_load_info_notifier_wrapper);
@@ -189,7 +188,6 @@
 
     scoped_refptr<WebRequestPeer> peer;
     network::mojom::RequestDestination request_destination;
-    int render_frame_id;
     WebURLLoader::DeferType is_deferred = WebURLLoader::DeferType::kNotDeferred;
     // Original requested url.
     GURL url;
diff --git a/third_party/blink/public/platform/web_url_request_extra_data.h b/third_party/blink/public/platform/web_url_request_extra_data.h
index 8ef9b9a..5a5e522 100644
--- a/third_party/blink/public/platform/web_url_request_extra_data.h
+++ b/third_party/blink/public/platform/web_url_request_extra_data.h
@@ -30,9 +30,6 @@
   WebURLRequestExtraData(const WebURLRequestExtraData&) = delete;
   WebURLRequestExtraData& operator=(const WebURLRequestExtraData&) = delete;
 
-  void set_render_frame_id(int render_frame_id) {
-    render_frame_id_ = render_frame_id;
-  }
   void set_is_main_frame(bool is_main_frame) { is_main_frame_ = is_main_frame; }
   ui::PageTransition transition_type() const { return transition_type_; }
   void set_transition_type(ui::PageTransition transition_type) {
@@ -97,7 +94,6 @@
   virtual ~WebURLRequestExtraData();
 
  private:
-  base::Optional<int> render_frame_id_;
   bool is_main_frame_ = false;
   ui::PageTransition transition_type_ = ui::PAGE_TRANSITION_LINK;
   bool is_for_no_state_prefetch_ = false;
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_set_return_value_for_core.h b/third_party/blink/renderer/bindings/core/v8/v8_set_return_value_for_core.h
index 3fe0df43..ea5139ba 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_set_return_value_for_core.h
+++ b/third_party/blink/renderer/bindings/core/v8/v8_set_return_value_for_core.h
@@ -70,6 +70,18 @@
       JSEventHandler::AsV8Value(isolate, event_target, event_listener));
 }
 
+// IDLDictionaryBase
+template <typename CallbackInfo>
+void V8SetReturnValue(const CallbackInfo& info,
+                      const IDLDictionaryBase* dictionary) {
+  // TODO(crbug.com/1185018): Change this if-branch to DCHECK(dictionary).
+  if (!dictionary)
+    return V8SetReturnValue(info, v8::Null(info.GetIsolate()));
+  V8SetReturnValue(info,
+                   dictionary->ToV8Impl(V8ReturnValue::CreationContext(info),
+                                        info.GetIsolate()));
+}
+
 }  // namespace bindings
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni
index 8e94c485..1194b55 100644
--- a/third_party/blink/renderer/bindings/generated_in_modules.gni
+++ b/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -25,6 +25,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_decode_success_callback.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk_output_callback.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk_output_callback.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk_output_callback.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk_output_callback.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_launch_consumer.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_launch_consumer.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_lock_granted_callback.cc",
@@ -63,8 +65,6 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_storage_quota_callback.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_storage_usage_callback.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_storage_usage_callback.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_encoder_output_callback.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_encoder_output_callback.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_frame_output_callback.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_frame_output_callback.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_frame_request_callback.cc",
@@ -279,6 +279,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk_init.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk_init.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk_init.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk_metadata.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk_metadata.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_event_source_init.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_event_source_init.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_extendable_cookie_change_event_init.cc",
diff --git a/third_party/blink/renderer/bindings/idl_in_modules.gni b/third_party/blink/renderer/bindings/idl_in_modules.gni
index 514eff7..8d9d4c1 100644
--- a/third_party/blink/renderer/bindings/idl_in_modules.gni
+++ b/third_party/blink/renderer/bindings/idl_in_modules.gni
@@ -784,7 +784,9 @@
           "//third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_init.idl",
           "//third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.idl",
           "//third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_init.idl",
+          "//third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_metadata.idl",
           "//third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_output_callback.idl",
+          "//third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_output_callback.idl",
           "//third_party/blink/renderer/modules/webcodecs/hardware_preference.idl",
           "//third_party/blink/renderer/modules/webcodecs/image_decoder.idl",
           "//third_party/blink/renderer/modules/webcodecs/image_decoder_init.idl",
@@ -802,7 +804,6 @@
           "//third_party/blink/renderer/modules/webcodecs/video_encoder_config.idl",
           "//third_party/blink/renderer/modules/webcodecs/video_encoder_encode_options.idl",
           "//third_party/blink/renderer/modules/webcodecs/video_encoder_init.idl",
-          "//third_party/blink/renderer/modules/webcodecs/video_encoder_output_callback.idl",
           "//third_party/blink/renderer/modules/webcodecs/video_frame.idl",
           "//third_party/blink/renderer/modules/webcodecs/video_frame_init.idl",
           "//third_party/blink/renderer/modules/webcodecs/video_frame_output_callback.idl",
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
index 135f830..d317c4a 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
@@ -1641,6 +1641,9 @@
                  "${return_value}, "
                  "bindings::V8ReturnValue::kIDLObject);")
 
+    if return_type.is_dictionary:
+        return T("bindings::V8SetReturnValue(${info}, ${return_value});")
+
     if return_type.is_sequence:
         return T("bindings::V8SetReturnValue(${info}, ${v8_return_value});")
 
diff --git a/third_party/blink/renderer/build/scripts/scripts.gni b/third_party/blink/renderer/build/scripts/scripts.gni
index bfd65de2..d00c031 100644
--- a/third_party/blink/renderer/build/scripts/scripts.gni
+++ b/third_party/blink/renderer/build/scripts/scripts.gni
@@ -73,6 +73,8 @@
 if (host_os == "win") {
   gperf_exe = rebase_path("//third_party/gperf/bin/gperf.exe", root_build_dir)
 } else if (host_os == "mac") {
+  # TODO(thakis): This should probably run in the host toolchain and check
+  # is_mac instead of checking host_os.
   gperf_exe = mac_bin_path + "gperf"
 } else {
   gperf_exe = "gperf"
diff --git a/third_party/blink/renderer/controller/performance_manager/v8_worker_memory_reporter.cc b/third_party/blink/renderer/controller/performance_manager/v8_worker_memory_reporter.cc
index 9b08d87..b9bf7059 100644
--- a/third_party/blink/renderer/controller/performance_manager/v8_worker_memory_reporter.cc
+++ b/third_party/blink/renderer/controller/performance_manager/v8_worker_memory_reporter.cc
@@ -104,7 +104,8 @@
       std::make_unique<V8WorkerMemoryReporter::WorkerMemoryUsage>();
   memory_usage->token = worker_global_scope->GetWorkerToken();
   memory_usage->bytes = bytes;
-  if (worker_global_scope->Url().GetString().length() < kMaxReportedUrlLength) {
+  if (worker_global_scope->IsUrlValid() &&
+      worker_global_scope->Url().GetString().length() < kMaxReportedUrlLength) {
     // Copy the URL to send it over to the main thread.
     memory_usage->url = worker_global_scope->Url().Copy();
   }
diff --git a/third_party/blink/renderer/core/clipboard/data_object.cc b/third_party/blink/renderer/core/clipboard/data_object.cc
index d10402a7..58d1c47d 100644
--- a/third_party/blink/renderer/core/clipboard/data_object.cc
+++ b/third_party/blink/renderer/core/clipboard/data_object.cc
@@ -57,9 +57,10 @@
   for (const String& type : system_clipboard->ReadAvailableTypes()) {
     if (paste_mode == PasteMode::kPlainTextOnly && type != kMimeTypeTextPlain)
       continue;
+    mojom::blink::ClipboardFilesPtr files;
     if (type == kMimeTypeTextURIList &&
         base::FeatureList::IsEnabled(features::kClipboardFilenames)) {
-      mojom::blink::ClipboardFilesPtr files = system_clipboard->ReadFiles();
+      files = system_clipboard->ReadFiles();
       // Ignore ReadFiles() result if clipboard sequence number has changed.
       if (system_clipboard->SequenceNumber() != sequence_number) {
         files->files.clear();
@@ -71,9 +72,9 @@
             base::MakeRefCounted<FileSystemAccessDropData>(
                 std::move(file->file_system_access_token)));
       }
-      if (files && !files->files.IsEmpty()) {
-        DraggedIsolatedFileSystem::PrepareForDataObject(data_object);
-      }
+    }
+    if (files && !files->files.IsEmpty()) {
+      DraggedIsolatedFileSystem::PrepareForDataObject(data_object);
     } else {
       data_object->item_list_.push_back(DataObjectItem::CreateFromClipboard(
           system_clipboard, type, sequence_number));
diff --git a/third_party/blink/renderer/core/css/css_value_keywords.json5 b/third_party/blink/renderer/core/css/css_value_keywords.json5
index e99da16e..dc2c319f 100644
--- a/third_party/blink/renderer/core/css/css_value_keywords.json5
+++ b/third_party/blink/renderer/core/css/css_value_keywords.json5
@@ -1445,7 +1445,7 @@
     "single-fold-vertical",
     "single-fold-horizontal",
 
-    // (screen-fold-posture) media feature
+    // (device-posture) media feature
     "no-fold",
     "laptop",
     // flat,
diff --git a/third_party/blink/renderer/core/css/media_feature_names.json5 b/third_party/blink/renderer/core/css/media_feature_names.json5
index babc3d59..002c071d 100644
--- a/third_party/blink/renderer/core/css/media_feature_names.json5
+++ b/third_party/blink/renderer/core/css/media_feature_names.json5
@@ -59,7 +59,7 @@
     "resolution",
     "-webkit-transform-3d",
     "scan",
-    "screen-fold-posture",
+    "device-posture",
     "screen-spanning",
   ],
 }
diff --git a/third_party/blink/renderer/core/css/media_query_evaluator.cc b/third_party/blink/renderer/core/css/media_query_evaluator.cc
index f02ca798..afe9ac8a 100644
--- a/third_party/blink/renderer/core/css/media_query_evaluator.cc
+++ b/third_party/blink/renderer/core/css/media_query_evaluator.cc
@@ -980,31 +980,31 @@
           value.id == CSSValueID::kSingleFoldHorizontal);
 }
 
-static bool ScreenFoldPostureMediaFeatureEval(const MediaQueryExpValue& value,
-                                              MediaFeaturePrefix,
-                                              const MediaValues& media_values) {
+static bool DevicePostureMediaFeatureEval(const MediaQueryExpValue& value,
+                                          MediaFeaturePrefix,
+                                          const MediaValues& media_values) {
   // isValid() is false if there is no parameter. Without parameter we should
-  // return true to indicate that screenFoldPosture is enabled in the
+  // return true to indicate that device posture is enabled in the
   // browser.
   if (!value.IsValid())
     return true;
 
   DCHECK(value.is_id);
 
-  ScreenFoldPosture screen_fold_posture = media_values.GetScreenFoldPosture();
+  DevicePosture device_posture = media_values.GetDevicePosture();
   switch (value.id) {
     case CSSValueID::kNoFold:
-      return screen_fold_posture == ScreenFoldPosture::kNoFold;
+      return device_posture == DevicePosture::kNoFold;
     case CSSValueID::kLaptop:
-      return screen_fold_posture == ScreenFoldPosture::kLaptop;
+      return device_posture == DevicePosture::kLaptop;
     case CSSValueID::kFlat:
-      return screen_fold_posture == ScreenFoldPosture::kFlat;
+      return device_posture == DevicePosture::kFlat;
     case CSSValueID::kTent:
-      return screen_fold_posture == ScreenFoldPosture::kTent;
+      return device_posture == DevicePosture::kTent;
     case CSSValueID::kTablet:
-      return screen_fold_posture == ScreenFoldPosture::kTablet;
+      return device_posture == DevicePosture::kTablet;
     case CSSValueID::kBook:
-      return screen_fold_posture == ScreenFoldPosture::kBook;
+      return device_posture == DevicePosture::kBook;
     default:
       NOTREACHED();
       return false;
diff --git a/third_party/blink/renderer/core/css/media_query_evaluator_test.cc b/third_party/blink/renderer/core/css/media_query_evaluator_test.cc
index 54654c0c..4557600 100644
--- a/third_party/blink/renderer/core/css/media_query_evaluator_test.cc
+++ b/third_party/blink/renderer/core/css/media_query_evaluator_test.cc
@@ -278,72 +278,72 @@
     {nullptr, 0}  // Do not remove the terminator line.
 };
 
-MediaQueryEvaluatorTestCase g_screen_fold_posture_none_cases[] = {
-    {"(screen-fold-posture)", 1},
-    {"(screen-fold-posture: laptop)", 0},
-    {"(screen-fold-posture: flat)", 0},
-    {"(screen-fold-posture: tent)", 0},
-    {"(screen-fold-posture: tablet)", 0},
-    {"(screen-fold-posture: book)", 0},
-    {"(screen-fold-posture: no-fold)", 1},
-    {"(screen-fold-posture: 15)", 0},
-    {"(screen-fold-posture: 2px)", 0},
-    {"(screen-fold-posture: 16/9)", 0},
+MediaQueryEvaluatorTestCase g_device_posture_none_cases[] = {
+    {"(device-posture)", 1},
+    {"(device-posture: laptop)", 0},
+    {"(device-posture: flat)", 0},
+    {"(device-posture: tent)", 0},
+    {"(device-posture: tablet)", 0},
+    {"(device-posture: book)", 0},
+    {"(device-posture: no-fold)", 1},
+    {"(device-posture: 15)", 0},
+    {"(device-posture: 2px)", 0},
+    {"(device-posture: 16/9)", 0},
     {nullptr, 0}  // Do not remove the terminator line.
 };
 
-MediaQueryEvaluatorTestCase g_screen_fold_posture_laptop_cases[] = {
-    {"(screen-fold-posture)", 1},
-    {"(screen-fold-posture: laptop)", 1},
-    {"(screen-fold-posture: flat)", 0},
-    {"(screen-fold-posture: tent)", 0},
-    {"(screen-fold-posture: tablet)", 0},
-    {"(screen-fold-posture: book)", 0},
-    {"(screen-fold-posture: no-fold)", 0},
+MediaQueryEvaluatorTestCase g_device_posture_laptop_cases[] = {
+    {"(device-posture)", 1},
+    {"(device-posture: laptop)", 1},
+    {"(device-posture: flat)", 0},
+    {"(device-posture: tent)", 0},
+    {"(device-posture: tablet)", 0},
+    {"(device-posture: book)", 0},
+    {"(device-posture: no-fold)", 0},
     {nullptr, 0}  // Do not remove the terminator line.
 };
 
-MediaQueryEvaluatorTestCase g_screen_fold_posture_flat_cases[] = {
-    {"(screen-fold-posture)", 1},
-    {"(screen-fold-posture: laptop)", 0},
-    {"(screen-fold-posture: flat)", 1},
-    {"(screen-fold-posture: tent)", 0},
-    {"(screen-fold-posture: tablet)", 0},
-    {"(screen-fold-posture: book)", 0},
-    {"(screen-fold-posture: no-fold)", 0},
+MediaQueryEvaluatorTestCase g_device_posture_flat_cases[] = {
+    {"(device-posture)", 1},
+    {"(device-posture: laptop)", 0},
+    {"(device-posture: flat)", 1},
+    {"(device-posture: tent)", 0},
+    {"(device-posture: tablet)", 0},
+    {"(device-posture: book)", 0},
+    {"(device-posture: no-fold)", 0},
     {nullptr, 0}  // Do not remove the terminator line.
 };
 
-MediaQueryEvaluatorTestCase g_screen_fold_posture_tent_cases[] = {
-    {"(screen-fold-posture)", 1},
-    {"(screen-fold-posture: laptop)", 0},
-    {"(screen-fold-posture: flat)", 0},
-    {"(screen-fold-posture: tent)", 1},
-    {"(screen-fold-posture: tablet)", 0},
-    {"(screen-fold-posture: book)", 0},
-    {"(screen-fold-posture: no-fold)", 0},
+MediaQueryEvaluatorTestCase g_device_posture_tent_cases[] = {
+    {"(device-posture)", 1},
+    {"(device-posture: laptop)", 0},
+    {"(device-posture: flat)", 0},
+    {"(device-posture: tent)", 1},
+    {"(device-posture: tablet)", 0},
+    {"(device-posture: book)", 0},
+    {"(device-posture: no-fold)", 0},
     {nullptr, 0}  // Do not remove the terminator line.
 };
 
-MediaQueryEvaluatorTestCase g_screen_fold_posture_tablet_cases[] = {
-    {"(screen-fold-posture)", 1},
-    {"(screen-fold-posture: laptop)", 0},
-    {"(screen-fold-posture: flat)", 0},
-    {"(screen-fold-posture: tent)", 0},
-    {"(screen-fold-posture: tablet)", 1},
-    {"(screen-fold-posture: book)", 0},
-    {"(screen-fold-posture: no-fold)", 0},
+MediaQueryEvaluatorTestCase g_device_posture_tablet_cases[] = {
+    {"(device-posture)", 1},
+    {"(device-posture: laptop)", 0},
+    {"(device-posture: flat)", 0},
+    {"(device-posture: tent)", 0},
+    {"(device-posture: tablet)", 1},
+    {"(device-posture: book)", 0},
+    {"(device-posture: no-fold)", 0},
     {nullptr, 0}  // Do not remove the terminator line.
 };
 
-MediaQueryEvaluatorTestCase g_screen_fold_posture_book_cases[] = {
-    {"(screen-fold-posture)", 1},
-    {"(screen-fold-posture: laptop)", 0},
-    {"(screen-fold-posture: flat)", 0},
-    {"(screen-fold-posture: tent)", 0},
-    {"(screen-fold-posture: tablet)", 0},
-    {"(screen-fold-posture: book)", 1},
-    {"(screen-fold-posture: no-fold)", 0},
+MediaQueryEvaluatorTestCase g_device_posture_book_cases[] = {
+    {"(device-posture)", 1},
+    {"(device-posture: laptop)", 0},
+    {"(device-posture: flat)", 0},
+    {"(device-posture: tent)", 0},
+    {"(device-posture: tablet)", 0},
+    {"(device-posture: book)", 1},
+    {"(device-posture: no-fold)", 0},
     {nullptr, 0}  // Do not remove the terminator line.
 };
 
@@ -590,51 +590,51 @@
   }
 }
 
-TEST(MediaQueryEvaluatorTest, CachedScreenFoldPosture) {
-  ScopedScreenFoldForTest scoped_feature(true);
+TEST(MediaQueryEvaluatorTest, CachedDevicePosture) {
+  ScopedDevicePostureForTest scoped_feature(true);
 
   MediaValuesCached::MediaValuesCachedData data;
   {
-    data.screen_fold_posture = ScreenFoldPosture::kNoFold;
+    data.device_posture = DevicePosture::kNoFold;
     MediaValues* media_values = MakeGarbageCollected<MediaValuesCached>(data);
 
     MediaQueryEvaluator media_query_evaluator(*media_values);
-    TestMQEvaluator(g_screen_fold_posture_none_cases, media_query_evaluator);
+    TestMQEvaluator(g_device_posture_none_cases, media_query_evaluator);
   }
 
   {
-    data.screen_fold_posture = ScreenFoldPosture::kLaptop;
+    data.device_posture = DevicePosture::kLaptop;
     MediaValues* media_values = MakeGarbageCollected<MediaValuesCached>(data);
     MediaQueryEvaluator media_query_evaluator(*media_values);
-    TestMQEvaluator(g_screen_fold_posture_laptop_cases, media_query_evaluator);
+    TestMQEvaluator(g_device_posture_laptop_cases, media_query_evaluator);
   }
 
   {
-    data.screen_fold_posture = ScreenFoldPosture::kFlat;
+    data.device_posture = DevicePosture::kFlat;
     MediaValues* media_values = MakeGarbageCollected<MediaValuesCached>(data);
     MediaQueryEvaluator media_query_evaluator(*media_values);
-    TestMQEvaluator(g_screen_fold_posture_flat_cases, media_query_evaluator);
+    TestMQEvaluator(g_device_posture_flat_cases, media_query_evaluator);
   }
 
   {
-    data.screen_fold_posture = ScreenFoldPosture::kTent;
+    data.device_posture = DevicePosture::kTent;
     MediaValues* media_values = MakeGarbageCollected<MediaValuesCached>(data);
     MediaQueryEvaluator media_query_evaluator(*media_values);
-    TestMQEvaluator(g_screen_fold_posture_tent_cases, media_query_evaluator);
+    TestMQEvaluator(g_device_posture_tent_cases, media_query_evaluator);
   }
 
   {
-    data.screen_fold_posture = ScreenFoldPosture::kTablet;
+    data.device_posture = DevicePosture::kTablet;
     MediaValues* media_values = MakeGarbageCollected<MediaValuesCached>(data);
     MediaQueryEvaluator media_query_evaluator(*media_values);
-    TestMQEvaluator(g_screen_fold_posture_tablet_cases, media_query_evaluator);
+    TestMQEvaluator(g_device_posture_tablet_cases, media_query_evaluator);
   }
 
   {
-    data.screen_fold_posture = ScreenFoldPosture::kBook;
+    data.device_posture = DevicePosture::kBook;
     MediaValues* media_values = MakeGarbageCollected<MediaValuesCached>(data);
     MediaQueryEvaluator media_query_evaluator(*media_values);
-    TestMQEvaluator(g_screen_fold_posture_book_cases, media_query_evaluator);
+    TestMQEvaluator(g_device_posture_book_cases, media_query_evaluator);
   }
 }
 
diff --git a/third_party/blink/renderer/core/css/media_query_exp.cc b/third_party/blink/renderer/core/css/media_query_exp.cc
index 31adc9d..c91258c 100644
--- a/third_party/blink/renderer/core/css/media_query_exp.cc
+++ b/third_party/blink/renderer/core/css/media_query_exp.cc
@@ -114,8 +114,8 @@
     }
   }
 
-  if (RuntimeEnabledFeatures::ScreenFoldEnabled()) {
-    if (media_feature == media_feature_names::kScreenFoldPostureMediaFeature) {
+  if (RuntimeEnabledFeatures::DevicePostureEnabled()) {
+    if (media_feature == media_feature_names::kDevicePostureMediaFeature) {
       return ident == CSSValueID::kNoFold || ident == CSSValueID::kLaptop ||
              ident == CSSValueID::kFlat || ident == CSSValueID::kTent ||
              ident == CSSValueID::kTablet || ident == CSSValueID::kBook;
@@ -251,9 +251,8 @@
               execution_context)) ||
          (media_feature == media_feature_names::kScreenSpanningMediaFeature &&
           RuntimeEnabledFeatures::CSSFoldablesEnabled()) ||
-         (media_feature ==
-              media_feature_names::kScreenFoldPostureMediaFeature &&
-          RuntimeEnabledFeatures::ScreenFoldEnabled());
+         (media_feature == media_feature_names::kDevicePostureMediaFeature &&
+          RuntimeEnabledFeatures::DevicePostureEnabled());
 }
 
 bool MediaQueryExp::IsViewportDependent() const {
diff --git a/third_party/blink/renderer/core/css/media_query_set_test.cc b/third_party/blink/renderer/core/css/media_query_set_test.cc
index 69f675b..c7650b7 100644
--- a/third_party/blink/renderer/core/css/media_query_set_test.cc
+++ b/third_party/blink/renderer/core/css/media_query_set_test.cc
@@ -193,7 +193,7 @@
   ScopedForcedColorsForTest forced_colors_flag(false);
   ScopedMediaQueryNavigationControlsForTest navigation_controls_flag(false);
   ScopedCSSFoldablesForTest foldables_flag(false);
-  ScopedScreenFoldForTest screen_fold_flag(false);
+  ScopedDevicePostureForTest device_posture_flag(false);
 
   // The first string represents the input string, the second string represents
   // the output string.
@@ -201,12 +201,12 @@
       {"(forced-colors)", "not all"},
       {"(navigation-controls)", "not all"},
       {"(screen-spanning)", "not all"},
-      {"(screen-fold-posture)", "not all"},
+      {"(device-posture)", "not all"},
       {"(shape: rect)", "not all"},
       {"(forced-colors: none)", "not all"},
       {"(navigation-controls: none)", "not all"},
       {"(screen-spanning:none)", "not all"},
-      {"(screen-fold-posture:none)", "not all"},
+      {"(device-posture:none)", "not all"},
       {nullptr, nullptr}  // Do not remove the terminator line.
   };
 
diff --git a/third_party/blink/renderer/core/css/media_values.cc b/third_party/blink/renderer/core/css/media_values.cc
index 61e0ef7..2ef2ed4 100644
--- a/third_party/blink/renderer/core/css/media_values.cc
+++ b/third_party/blink/renderer/core/css/media_values.cc
@@ -277,9 +277,9 @@
   return ScreenSpanning::kNone;
 }
 
-ScreenFoldPosture MediaValues::CalculateScreenFoldPosture(LocalFrame* frame) {
+DevicePosture MediaValues::CalculateDevicePosture(LocalFrame* frame) {
   // TODO(darktears): Retrieve information from the host.
-  return ScreenFoldPosture::kNoFold;
+  return DevicePosture::kNoFold;
 }
 
 bool MediaValues::ComputeLengthImpl(double value,
diff --git a/third_party/blink/renderer/core/css/media_values.h b/third_party/blink/renderer/core/css/media_values.h
index babd2eb..604147c 100644
--- a/third_party/blink/renderer/core/css/media_values.h
+++ b/third_party/blink/renderer/core/css/media_values.h
@@ -24,7 +24,7 @@
 enum class ForcedColors;
 enum class NavigationControls;
 enum class ScreenSpanning { kNone, kSingleFoldHorizontal, kSingleFoldVertical };
-enum class ScreenFoldPosture { kNoFold, kLaptop, kFlat, kTent, kTablet, kBook };
+enum class DevicePosture { kNoFold, kLaptop, kFlat, kTent, kTablet, kBook };
 
 mojom::blink::PreferredColorScheme CSSValueIDToPreferredColorScheme(
     CSSValueID id);
@@ -93,7 +93,7 @@
   virtual ForcedColors GetForcedColors() const = 0;
   virtual NavigationControls GetNavigationControls() const = 0;
   virtual ScreenSpanning GetScreenSpanning() const = 0;
-  virtual ScreenFoldPosture GetScreenFoldPosture() const = 0;
+  virtual DevicePosture GetDevicePosture() const = 0;
 
  protected:
   static double CalculateViewportWidth(LocalFrame*);
@@ -123,7 +123,7 @@
   static ForcedColors CalculateForcedColors();
   static NavigationControls CalculateNavigationControls(LocalFrame*);
   static ScreenSpanning CalculateScreenSpanning(LocalFrame*);
-  static ScreenFoldPosture CalculateScreenFoldPosture(LocalFrame*);
+  static DevicePosture CalculateDevicePosture(LocalFrame*);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/media_values_cached.cc b/third_party/blink/renderer/core/css/media_values_cached.cc
index 44d8d0b..16c91688 100644
--- a/third_party/blink/renderer/core/css/media_values_cached.cc
+++ b/third_party/blink/renderer/core/css/media_values_cached.cc
@@ -41,7 +41,7 @@
       forced_colors(ForcedColors::kNone),
       navigation_controls(NavigationControls::kNone),
       screen_spanning(ScreenSpanning::kNone),
-      screen_fold_posture(ScreenFoldPosture::kNoFold) {}
+      device_posture(DevicePosture::kNoFold) {}
 
 MediaValuesCached::MediaValuesCachedData::MediaValuesCachedData(
     Document& document)
@@ -86,7 +86,7 @@
     forced_colors = MediaValues::CalculateForcedColors();
     navigation_controls = MediaValues::CalculateNavigationControls(frame);
     screen_spanning = MediaValues::CalculateScreenSpanning(frame);
-    screen_fold_posture = MediaValues::CalculateScreenFoldPosture(frame);
+    device_posture = MediaValues::CalculateDevicePosture(frame);
   }
 }
 
@@ -227,8 +227,8 @@
   return data_.screen_spanning;
 }
 
-ScreenFoldPosture MediaValuesCached::GetScreenFoldPosture() const {
-  return data_.screen_fold_posture;
+DevicePosture MediaValuesCached::GetDevicePosture() const {
+  return data_.device_posture;
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/media_values_cached.h b/third_party/blink/renderer/core/css/media_values_cached.h
index 76439c8..c38b20d 100644
--- a/third_party/blink/renderer/core/css/media_values_cached.h
+++ b/third_party/blink/renderer/core/css/media_values_cached.h
@@ -42,7 +42,7 @@
     ForcedColors forced_colors;
     NavigationControls navigation_controls;
     ScreenSpanning screen_spanning;
-    ScreenFoldPosture screen_fold_posture;
+    DevicePosture device_posture;
 
     MediaValuesCachedData();
     explicit MediaValuesCachedData(Document&);
@@ -74,7 +74,7 @@
       data.forced_colors = forced_colors;
       data.navigation_controls = navigation_controls;
       data.screen_spanning = screen_spanning;
-      data.screen_fold_posture = screen_fold_posture;
+      data.device_posture = device_posture;
       return data;
     }
   };
@@ -117,7 +117,7 @@
   ForcedColors GetForcedColors() const override;
   NavigationControls GetNavigationControls() const override;
   ScreenSpanning GetScreenSpanning() const override;
-  ScreenFoldPosture GetScreenFoldPosture() const override;
+  DevicePosture GetDevicePosture() const override;
 
   void OverrideViewportDimensions(double width, double height) override;
 
diff --git a/third_party/blink/renderer/core/css/media_values_dynamic.cc b/third_party/blink/renderer/core/css/media_values_dynamic.cc
index b75305e..9561a883 100644
--- a/third_party/blink/renderer/core/css/media_values_dynamic.cc
+++ b/third_party/blink/renderer/core/css/media_values_dynamic.cc
@@ -169,8 +169,8 @@
   return CalculateScreenSpanning(frame_);
 }
 
-ScreenFoldPosture MediaValuesDynamic::GetScreenFoldPosture() const {
-  return CalculateScreenFoldPosture(frame_);
+DevicePosture MediaValuesDynamic::GetDevicePosture() const {
+  return CalculateDevicePosture(frame_);
 }
 
 Document* MediaValuesDynamic::GetDocument() const {
diff --git a/third_party/blink/renderer/core/css/media_values_dynamic.h b/third_party/blink/renderer/core/css/media_values_dynamic.h
index b78c855..07ea92e1 100644
--- a/third_party/blink/renderer/core/css/media_values_dynamic.h
+++ b/third_party/blink/renderer/core/css/media_values_dynamic.h
@@ -54,7 +54,7 @@
   ForcedColors GetForcedColors() const override;
   NavigationControls GetNavigationControls() const override;
   ScreenSpanning GetScreenSpanning() const override;
-  ScreenFoldPosture GetScreenFoldPosture() const override;
+  DevicePosture GetDevicePosture() const override;
   Document* GetDocument() const override;
   bool HasValues() const override;
   void OverrideViewportDimensions(double width, double height) override;
diff --git a/third_party/blink/renderer/core/inspector/inspector_css_agent.cc b/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
index dac4927..84d0430 100644
--- a/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
@@ -2379,6 +2379,29 @@
   return response;
 }
 
+void InspectorCSSAgent::BuildRulesMap(
+    InspectorStyleSheet* style_sheet,
+    HeapHashMap<Member<const StyleRule>, Member<CSSStyleRule>>*
+        rule_to_css_rule) {
+  const CSSRuleVector& css_rules = style_sheet->FlatRules();
+  for (auto css_rule : css_rules) {
+    if (css_rule->GetType() == CSSRule::kStyleRule) {
+      CSSStyleRule* css_style_rule = DynamicTo<CSSStyleRule>(css_rule.Get());
+      rule_to_css_rule->Set(css_style_rule->GetStyleRule(), css_style_rule);
+    }
+    if (css_rule->GetType() == CSSRule::kImportRule) {
+      CSSImportRule* css_import_rule = DynamicTo<CSSImportRule>(css_rule.Get());
+      InspectorStyleSheet* imported_style_sheet =
+          css_style_sheet_to_inspector_style_sheet_.at(
+              const_cast<CSSStyleSheet*>(css_import_rule->styleSheet()));
+      if (!imported_style_sheet)
+        continue;
+
+      BuildRulesMap(imported_style_sheet, rule_to_css_rule);
+    }
+  }
+}
+
 Response InspectorCSSAgent::takeCoverageDelta(
     std::unique_ptr<protocol::Array<protocol::CSS::RuleUsage>>* result,
     double* out_timestamp) {
@@ -2401,17 +2424,21 @@
       continue;
 
     HeapHashMap<Member<const StyleRule>, Member<CSSStyleRule>> rule_to_css_rule;
-    const CSSRuleVector& css_rules = style_sheet->FlatRules();
-    for (auto css_rule : css_rules) {
-      if (css_rule->GetType() != CSSRule::kStyleRule)
-        continue;
-      CSSStyleRule* css_style_rule = AsCSSStyleRule(css_rule);
-      rule_to_css_rule.Set(css_style_rule->GetStyleRule(), css_style_rule);
-    }
+    BuildRulesMap(style_sheet, &rule_to_css_rule);
+
     for (auto used_rule : *entry.value) {
       CSSStyleRule* css_style_rule = rule_to_css_rule.at(used_rule);
+      if (!css_style_rule)
+        continue;
+      // If the rule comes from an @import'ed file, the `rule_style_sheet` is
+      // different from `style_sheet`.
+      InspectorStyleSheet* rule_style_sheet =
+          css_style_sheet_to_inspector_style_sheet_.at(
+              const_cast<CSSStyleSheet*>(css_style_rule->parentStyleSheet()));
+      if (!rule_style_sheet)
+        continue;
       if (std::unique_ptr<protocol::CSS::RuleUsage> rule_usage_object =
-              style_sheet->BuildObjectForRuleUsage(css_style_rule, true)) {
+              rule_style_sheet->BuildObjectForRuleUsage(css_style_rule, true)) {
         (*result)->emplace_back(std::move(rule_usage_object));
       }
     }
diff --git a/third_party/blink/renderer/core/inspector/inspector_css_agent.h b/third_party/blink/renderer/core/inspector/inspector_css_agent.h
index ed66a85..93ca98f3 100644
--- a/third_party/blink/renderer/core/inspector/inspector_css_agent.h
+++ b/third_party/blink/renderer/core/inspector/inspector_css_agent.h
@@ -255,6 +255,9 @@
   class SetElementStyleAction;
   class AddRuleAction;
 
+  void BuildRulesMap(InspectorStyleSheet* style_sheet,
+                     HeapHashMap<Member<const StyleRule>, Member<CSSStyleRule>>*
+                         rule_to_css_rule);
   static void CollectStyleSheets(CSSStyleSheet*,
                                  HeapVector<Member<CSSStyleSheet>>&);
 
diff --git a/third_party/blink/renderer/core/layout/collapsed_border_value.cc b/third_party/blink/renderer/core/layout/collapsed_border_value.cc
index 25da3d0..a0a3c52 100644
--- a/third_party/blink/renderer/core/layout/collapsed_border_value.cc
+++ b/third_party/blink/renderer/core/layout/collapsed_border_value.cc
@@ -11,22 +11,10 @@
 CollapsedBorderValue::CollapsedBorderValue(const BorderValue& border,
                                            const Color& color,
                                            EBorderPrecedence precedence)
-    : color_(color),
-      style_(static_cast<unsigned>(border.Style())),
-      precedence_(precedence) {
-  if (!ComputedStyle::BorderStyleIsVisible(border.Style())) {
-    width_ = 0;
-  } else {
-    if (border.Width() > 0.0f && border.Width() <= 1.0f)
-      width_ = 1;
-    else
-      width_ = border.Width();
-  }
-  DCHECK(precedence != kBorderPrecedenceOff);
-}
+    : CollapsedBorderValue(border.Style(), border.Width(), color, precedence) {}
 
 CollapsedBorderValue::CollapsedBorderValue(EBorderStyle style,
-                                           const float width,
+                                           const LayoutUnit width,
                                            const Color& color,
                                            EBorderPrecedence precedence)
     : color_(color),
@@ -35,10 +23,10 @@
   if (!ComputedStyle::BorderStyleIsVisible(style)) {
     width_ = 0;
   } else {
-    if (width > 0.0f && width <= 1.0f)
+    if (width > 0 && width <= 1)
       width_ = 1;
     else
-      width_ = width;
+      width_ = width.ToUnsigned();
   }
   DCHECK(precedence != kBorderPrecedenceOff);
 }
diff --git a/third_party/blink/renderer/core/layout/collapsed_border_value.h b/third_party/blink/renderer/core/layout/collapsed_border_value.h
index 36e20d7b0a..40f0a85 100644
--- a/third_party/blink/renderer/core/layout/collapsed_border_value.h
+++ b/third_party/blink/renderer/core/layout/collapsed_border_value.h
@@ -27,15 +27,12 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/style/border_value.h"
-#include "third_party/blink/renderer/core/style/computed_style.h"
 #include "third_party/blink/renderer/platform/geometry/layout_rect.h"
 #include "third_party/blink/renderer/platform/graphics/color.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 
 namespace blink {
 
-class ComputedStyle;
-
 enum EBorderPrecedence {
   kBorderPrecedenceOff,
   kBorderPrecedenceTable,
@@ -61,7 +58,7 @@
                        const Color&,
                        EBorderPrecedence);
   CollapsedBorderValue(EBorderStyle style,
-                       const float width,
+                       const LayoutUnit width,
                        const Color&,
                        EBorderPrecedence);
 
diff --git a/third_party/blink/renderer/core/layout/layout_list_item.cc b/third_party/blink/renderer/core/layout/layout_list_item.cc
index 0d5766c..5cd7442 100644
--- a/third_party/blink/renderer/core/layout/layout_list_item.cc
+++ b/third_party/blink/renderer/core/layout/layout_list_item.cc
@@ -346,7 +346,9 @@
     // If the marker is currently contained inside an anonymous box, then we
     // are the only item in that anonymous box (since no line box parent was
     // found). It's ok to just leave the marker where it is in this case.
-    if (marker_parent && marker_parent->IsAnonymousBlock()) {
+    // Also ok to leave it in a flow thread.
+    if (marker_parent && (marker_parent->IsAnonymousBlock() ||
+                          marker_parent->IsLayoutFlowThread())) {
       line_box_parent = marker_parent;
       // We could use marker_parent as line_box_parent only if marker is the
       // first leaf child of list item.
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.cc
index f584237..5d3c485 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.cc
@@ -53,6 +53,11 @@
   ClearInvalidationMask();
 }
 
+bool LayoutSVGResourceMarker::FindCycleFromSelf() const {
+  NOT_DESTROYED();
+  return FindCycleInSubtree(*this);
+}
+
 void LayoutSVGResourceMarker::RemoveAllClientsFromCache() {
   NOT_DESTROYED();
   MarkAllClientsForInvalidation(kLayoutInvalidation | kBoundariesInvalidation);
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.h b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.h
index c364852..1831376 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.h
@@ -76,6 +76,7 @@
  private:
   void UpdateLayout() override;
   SVGTransformChange CalculateLocalTransform(bool bounds_changed) final;
+  bool FindCycleFromSelf() const override;
 
   AffineTransform local_to_parent_transform_;
   FloatSize viewport_size_;
diff --git a/third_party/blink/renderer/core/scroll/mac_scrollbar_animator_impl.mm b/third_party/blink/renderer/core/scroll/mac_scrollbar_animator_impl.mm
index f703eac..67dc13d7 100644
--- a/third_party/blink/renderer/core/scroll/mac_scrollbar_animator_impl.mm
+++ b/third_party/blink/renderer/core/scroll/mac_scrollbar_animator_impl.mm
@@ -198,6 +198,19 @@
 
   void SetDuration(CFTimeInterval duration) { duration_ = duration; }
 
+  // This is a speculative fix for crbug.com/1183276.
+  // In BlinkScrollbarPainterDelegate::setUpAlphaAnimation we are
+  // deallocating BlinkScrollbarPartAnimation and create a new one.
+  // The problem seems to be with BlinkScrollbarPartAnimation, passing a
+  // pointer to itself to BlinkScrollbarPartAnimationTimer.
+  // BlinkScrollbarPartAnimationTimer uses a TaskRunnerTimer to schedule
+  // the animation to run 60 times second.
+  // When we deallocate BlinkScrollbarPartAnimation,
+  // BlinkScrollbarPartAnimationTimer fires again, I believe because it
+  // uses PostTaskDelayed to schedule the next animation.
+  // Ideally the timer won't fire again.
+  void CancelAnimation() { animation_ = nullptr; }
+
  private:
   void TimerFired(TimerBase*) {
     double current_time = base::Time::Now().ToDoubleT();
@@ -205,6 +218,9 @@
 
     if (delta >= duration_)
       timer_.Stop();
+    // This is a speculative fix for crbug.com/1183276.
+    if (!animation_)
+      return;
 
     double fraction = delta / duration_;
     fraction = clampTo(fraction, 0.0, 1.0);
@@ -224,11 +240,7 @@
 // This class handles the animation of a |_featureToAnimate| part of
 // |_scrollbar|.
 @interface BlinkScrollbarPartAnimation : NSObject {
-  // TODO(crbug.com/1185337): This WeakPersistent was added as a speculative
-  // because fix for crbug.com/1183276.
-  // We need to figure out how to correctly clear the scrollbar manually
-  // instead of relying on WeakPersistent which adds overhead.
-  blink::WeakPersistent<blink::Scrollbar> _scrollbar;
+  blink::Scrollbar* _scrollbar;
   std::unique_ptr<blink::BlinkScrollbarPartAnimationTimer> _timer;
   base::scoped_nsobject<ScrollbarPainter> _scrollbarPainter;
   FeatureToAnimate _featureToAnimate;
@@ -258,7 +270,7 @@
 
   _timer = std::make_unique<blink::BlinkScrollbarPartAnimationTimer>(
       self, duration, std::move(taskRunner));
-  _scrollbar = blink::WeakPersistent<blink::Scrollbar>(scrollbar);
+  _scrollbar = scrollbar;
   _featureToAnimate = featureToAnimate;
   _startValue = startValue;
   _endValue = endValue;
@@ -268,10 +280,6 @@
 
 - (void)startAnimation {
   DCHECK(_scrollbar);
-  // This was added as a speculative fix for crbug.com/1183276.
-  // Accessing scrollbar is problematic in _timer
-  if (!_scrollbar)
-    return;
   _scrollbarPainter.reset(ScrollbarPainterForScrollbar(*_scrollbar),
                           base::scoped_policy::RETAIN);
   _timer->Start();
@@ -295,11 +303,6 @@
 
 - (void)setCurrentProgress:(NSAnimationProgress)progress {
   DCHECK(_scrollbar);
-  // This was added as a speculative fix for crbug.com/1183276.
-  // Accessing scrollbar is problematic in _timer
-  if (!_scrollbar)
-    return;
-
   CGFloat currentValue;
   if (_startValue > _endValue)
     currentValue = 1 - progress;
@@ -333,6 +336,7 @@
   [self stopAnimation];
   END_BLOCK_OBJC_EXCEPTIONS;
   _scrollbar = nullptr;
+  _timer->CancelAnimation();
 }
 @end
 
@@ -437,7 +441,7 @@
 
   // If we are currently animating, stop
   if (scrollbarPartAnimation) {
-    [scrollbarPartAnimation stopAnimation];
+    [scrollbarPartAnimation invalidate];
     scrollbarPartAnimation.reset();
   }
 
diff --git a/third_party/blink/renderer/core/style/border_value.h b/third_party/blink/renderer/core/style/border_value.h
index 49f6cb1..72c58b9 100644
--- a/third_party/blink/renderer/core/style/border_value.h
+++ b/third_party/blink/renderer/core/style/border_value.h
@@ -27,31 +27,22 @@
 
 #include "third_party/blink/renderer/core/css/style_color.h"
 #include "third_party/blink/renderer/core/style/computed_style_constants.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/graphics/color.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 
 namespace blink {
 
-// In order to conserve memory, the border width uses fixed point,
-// which can be bitpacked.  This fixed point implementation is
-// essentially the same as in LayoutUnit.  Six bits are used for the
-// fraction, which leaves 20 bits for the integer part, making 1048575
-// the largest number.
-
-static const int kBorderWidthFractionalBits = 6;
-static const int kBorderWidthDenominator = 1 << kBorderWidthFractionalBits;
-static const int kMaxForBorderWidth = ((1 << 26) - 1) / kBorderWidthDenominator;
-
 class BorderValue {
   DISALLOW_NEW();
   friend class ComputedStyle;
 
  public:
   BorderValue() : style_(static_cast<unsigned>(EBorderStyle::kNone)) {
-    SetWidth(3);
+    SetWidth(LayoutUnit(3));
   }
 
-  BorderValue(EBorderStyle style, const StyleColor& color, float width) {
+  BorderValue(EBorderStyle style, const StyleColor& color, LayoutUnit width) {
     SetColor(color);
     SetStyle(style);
     SetWidth(width);
@@ -79,28 +70,33 @@
 
   StyleColor GetColor() const { return color_; }
 
-  float Width() const {
-    return static_cast<float>(width_) / kBorderWidthDenominator;
-  }
-  void SetWidth(float width) { width_ = WidthToFixedPoint(width); }
+  LayoutUnit Width() const { return LayoutUnit::FromRawValue(width_); }
+  void SetWidth(LayoutUnit width) { width_ = ClampToLimitedWidth(width); }
 
   // Since precision is lost with fixed point, comparisons also have
   // to be done in fixed point.
-  bool WidthEquals(float width) const {
-    return WidthToFixedPoint(width) == width_;
-  }
+  bool WidthEquals(LayoutUnit width) const { return width == Width(); }
 
   EBorderStyle Style() const { return static_cast<EBorderStyle>(style_); }
   void SetStyle(EBorderStyle style) { style_ = static_cast<unsigned>(style); }
 
+  static LayoutUnit MaxWidth() { return LayoutUnit::FromRawValue(kMaxValue); }
+
  protected:
-  static unsigned WidthToFixedPoint(float width) {
+  // In order to conserve memory, the border width uses fixed point, which can
+  // be bitpacked. This fixed point implementation is essentially the same as in
+  // LayoutUnit. Six bits are used for the fraction, which leaves 20 bits for
+  // the integer part, making 1048575.98 the largest number.
+  static constexpr int kMaxValue = (1 << 26) - 1;
+
+  static unsigned ClampToLimitedWidth(LayoutUnit width) {
     DCHECK_GE(width, 0);
     // Avoid min()/max() from std here in the header, because that would require
     // inclusion of <algorithm>, which is slow to compile.
-    if (width > float(kMaxForBorderWidth))
-      width = float(kMaxForBorderWidth);
-    return static_cast<unsigned>(width * kBorderWidthDenominator);
+    int raw_width = width.RawValue();
+    if (raw_width > kMaxValue)
+      raw_width = kMaxValue;
+    return static_cast<unsigned>(raw_width);
   }
 
   StyleColor color_;
diff --git a/third_party/blink/renderer/core/style/border_value_test.cc b/third_party/blink/renderer/core/style/border_value_test.cc
index 7bbf927..f137a9d 100644
--- a/third_party/blink/renderer/core/style/border_value_test.cc
+++ b/third_party/blink/renderer/core/style/border_value_test.cc
@@ -10,35 +10,36 @@
 namespace blink {
 
 TEST(BorderValueTest, BorderValueWidth) {
-  const float kTolerance = 1.0f / kBorderWidthDenominator;
+  const float kTolerance = LayoutUnit::Epsilon();
+  const LayoutUnit kMaxForBorderWidth = BorderValue::MaxWidth();
   BorderValue border;
 
-  border.SetWidth(1.0f);
+  border.SetWidth(LayoutUnit(1.0f));
   EXPECT_FLOAT_EQ(1.0f, border.Width());
-  border.SetWidth(1.25f);
+  border.SetWidth(LayoutUnit(1.25f));
   EXPECT_FLOAT_EQ(1.25f, border.Width());
-  border.SetWidth(1.1f);
+  border.SetWidth(LayoutUnit(1.1f));
   EXPECT_NEAR(border.Width(), 1.1f, kTolerance);
-  border.SetWidth(1.33f);
+  border.SetWidth(LayoutUnit(1.33f));
   EXPECT_NEAR(border.Width(), 1.33f, kTolerance);
-  border.SetWidth(1.3333f);
+  border.SetWidth(LayoutUnit(1.3333f));
   EXPECT_NEAR(border.Width(), 1.3333f, kTolerance);
-  border.SetWidth(1.53434f);
+  border.SetWidth(LayoutUnit(1.53434f));
   EXPECT_NEAR(border.Width(), 1.53434f, kTolerance);
-  border.SetWidth(345634);
+  border.SetWidth(LayoutUnit(345634));
   EXPECT_NEAR(border.Width(), 345634.0f, kTolerance);
-  border.SetWidth(345634.12335f);
+  border.SetWidth(LayoutUnit(345634.12335f));
   EXPECT_NEAR(border.Width(), 345634.12335f, kTolerance);
 
-  border.SetWidth(0);
+  border.SetWidth(LayoutUnit(0));
   EXPECT_EQ(0, border.Width());
-  border.SetWidth(1);
+  border.SetWidth(LayoutUnit(1));
   EXPECT_EQ(1, border.Width());
-  border.SetWidth(100);
+  border.SetWidth(LayoutUnit(100));
   EXPECT_EQ(100, border.Width());
-  border.SetWidth(1000);
+  border.SetWidth(LayoutUnit(1000));
   EXPECT_EQ(1000, border.Width());
-  border.SetWidth(10000);
+  border.SetWidth(LayoutUnit(10000));
   EXPECT_EQ(10000, border.Width());
   border.SetWidth(kMaxForBorderWidth / 2);
   EXPECT_EQ(kMaxForBorderWidth / 2, border.Width());
@@ -48,9 +49,9 @@
   EXPECT_EQ(kMaxForBorderWidth, border.Width());
   border.SetWidth(kMaxForBorderWidth + 1);
   EXPECT_EQ(kMaxForBorderWidth, border.Width());
-  border.SetWidth(INT_MAX / 2);
+  border.SetWidth(LayoutUnit::Max() / 2);
   EXPECT_EQ(kMaxForBorderWidth, border.Width());
-  border.SetWidth(INT_MAX);
+  border.SetWidth(LayoutUnit::Max());
   EXPECT_EQ(kMaxForBorderWidth, border.Width());
 }
 
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h
index 9aa8b262..e2f16dd 100644
--- a/third_party/blink/renderer/core/style/computed_style.h
+++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -1642,19 +1642,19 @@
   void SetBorderImageSlicesFill(bool);
   const BorderValue BorderLeft() const {
     return BorderValue(BorderLeftStyle(), BorderLeftColor(),
-                       BorderLeftWidthInternal().ToFloat());
+                       BorderLeftWidthInternal());
   }
   const BorderValue BorderRight() const {
     return BorderValue(BorderRightStyle(), BorderRightColor(),
-                       BorderRightWidthInternal().ToFloat());
+                       BorderRightWidthInternal());
   }
   const BorderValue BorderTop() const {
     return BorderValue(BorderTopStyle(), BorderTopColor(),
-                       BorderTopWidthInternal().ToFloat());
+                       BorderTopWidthInternal());
   }
   const BorderValue BorderBottom() const {
     return BorderValue(BorderBottomStyle(), BorderBottomColor(),
-                       BorderBottomWidthInternal().ToFloat());
+                       BorderBottomWidthInternal());
   }
 
   bool BorderSizeEquals(const ComputedStyle& o) const {
@@ -1682,20 +1682,22 @@
   BorderValue BorderStart() const { return BorderStartUsing(*this); }
   BorderValue BorderEnd() const { return BorderEndUsing(*this); }
 
-  float BorderAfterWidth() const {
+  LayoutUnit BorderAfterWidth() const {
     return PhysicalBorderWidthToLogical().After();
   }
-  float BorderBeforeWidth() const {
+  LayoutUnit BorderBeforeWidth() const {
     return PhysicalBorderWidthToLogical().Before();
   }
-  float BorderEndWidth() const { return PhysicalBorderWidthToLogical().End(); }
-  float BorderStartWidth() const {
+  LayoutUnit BorderEndWidth() const {
+    return PhysicalBorderWidthToLogical().End();
+  }
+  LayoutUnit BorderStartWidth() const {
     return PhysicalBorderWidthToLogical().Start();
   }
-  float BorderOverWidth() const {
+  LayoutUnit BorderOverWidth() const {
     return PhysicalBorderWidthToLogical().Over();
   }
-  float BorderUnderWidth() const {
+  LayoutUnit BorderUnderWidth() const {
     return PhysicalBorderWidthToLogical().Under();
   }
 
@@ -1751,7 +1753,7 @@
            BorderLeftColor() == o.BorderLeftColor();
   }
   bool BorderLeftEquals(const BorderValue& o) const {
-    return BorderLeftWidthInternal().ToFloat() == o.Width() &&
+    return BorderLeftWidthInternal() == o.Width() &&
            BorderLeftStyle() == o.Style() && BorderLeftColor() == o.GetColor();
   }
 
@@ -1771,7 +1773,7 @@
            BorderRightColor() == o.BorderRightColor();
   }
   bool BorderRightEquals(const BorderValue& o) const {
-    return BorderRightWidthInternal().ToFloat() == o.Width() &&
+    return BorderRightWidthInternal() == o.Width() &&
            BorderRightStyle() == o.Style() &&
            BorderRightColor() == o.GetColor();
   }
@@ -1802,7 +1804,7 @@
            BorderTopColor() == o.BorderTopColor();
   }
   bool BorderTopEquals(const BorderValue& o) const {
-    return BorderTopWidthInternal().ToFloat() == o.Width() &&
+    return BorderTopWidthInternal() == o.Width() &&
            BorderTopStyle() == o.Style() && BorderTopColor() == o.GetColor();
   }
 
@@ -1822,7 +1824,7 @@
            BorderBottomColor() == o.BorderBottomColor();
   }
   bool BorderBottomEquals(const BorderValue& o) const {
-    return BorderBottomWidthInternal().ToFloat() == o.Width() &&
+    return BorderBottomWidthInternal() == o.Width() &&
            BorderBottomStyle() == o.Style() &&
            BorderBottomColor() == o.GetColor();
   }
@@ -2930,10 +2932,10 @@
                                           BorderBottom(), BorderLeft());
   }
 
-  PhysicalToLogical<float> PhysicalBorderWidthToLogical() const {
-    return PhysicalToLogical<float>(GetWritingDirection(), BorderTopWidth(),
-                                    BorderRightWidth(), BorderBottomWidth(),
-                                    BorderLeftWidth());
+  PhysicalToLogical<LayoutUnit> PhysicalBorderWidthToLogical() const {
+    return PhysicalToLogical<LayoutUnit>(
+        GetWritingDirection(), BorderTopWidth(), BorderRightWidth(),
+        BorderBottomWidth(), BorderLeftWidth());
   }
 
   PhysicalToLogical<EBorderStyle> PhysicalBorderStyleToLogical() const {
diff --git a/third_party/blink/renderer/core/timing/background_tracing_helper.h b/third_party/blink/renderer/core/timing/background_tracing_helper.h
index ff2f345..f240171 100644
--- a/third_party/blink/renderer/core/timing/background_tracing_helper.h
+++ b/third_party/blink/renderer/core/timing/background_tracing_helper.h
@@ -10,7 +10,7 @@
 
 #include "base/strings/string_piece.h"
 #include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/heap/impl/heap.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
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 4e25c65..d716ade 100644
--- a/third_party/blink/renderer/core/workers/worker_global_scope.h
+++ b/third_party/blink/renderer/core/workers/worker_global_scope.h
@@ -231,6 +231,8 @@
     return agent_group_scheduler_compositor_task_runner_;
   }
 
+  bool IsUrlValid() { return url_.IsValid(); }
+
  protected:
   WorkerGlobalScope(std::unique_ptr<GlobalScopeCreationParams>,
                     WorkerThread*,
diff --git a/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc b/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc
index 976efbd3..47fee49 100644
--- a/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc
+++ b/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc
@@ -18,8 +18,8 @@
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/mediastream/media_stream.mojom-blink.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/webrtc/legacy_webrtc_video_frame_adapter.h"
 #include "third_party/blink/renderer/platform/webrtc/track_observer.h"
-#include "third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.h"
 #include "third_party/blink/renderer/platform/webrtc/webrtc_video_utils.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
@@ -177,7 +177,7 @@
 
   switch (buffer->type()) {
     case webrtc::VideoFrameBuffer::Type::kNative: {
-      video_frame = static_cast<WebRtcVideoFrameAdapter*>(buffer.get())
+      video_frame = static_cast<LegacyWebRtcVideoFrameAdapter*>(buffer.get())
                         ->getMediaVideoFrame();
       video_frame->set_timestamp(elapsed_timestamp);
       break;
diff --git a/third_party/blink/renderer/modules/url_pattern/url_pattern.cc b/third_party/blink/renderer/modules/url_pattern/url_pattern.cc
index 81b8c38e6..540ef56 100644
--- a/third_party/blink/renderer/modules/url_pattern/url_pattern.cc
+++ b/third_party/blink/renderer/modules/url_pattern/url_pattern.cc
@@ -31,6 +31,9 @@
 
   void Trace(Visitor* visitor) const { visitor->Trace(regexp); }
 
+  // The parsed pattern.
+  liburlpattern::Pattern pattern;
+
   // The pattern compiled down to a js regular expression.
   Member<ScriptRegexp> regexp;
 
@@ -38,12 +41,16 @@
   // liburlpattern regular expressions do not use named capture groups directly.
   Vector<String> name_list;
 
-  Component(ScriptRegexp* r, Vector<String> n)
-      : regexp(r), name_list(std::move(n)) {}
+  Component(liburlpattern::Pattern p, ScriptRegexp* r, Vector<String> n)
+      : pattern(p), regexp(r), name_list(std::move(n)) {}
 };
 
 namespace {
 
+// The default pattern string for components that are not specified in the
+// URLPattern constructor.
+const char* kDefaultPattern = "*";
+
 // The liburlpattern::Options to use for most component patterns.  We
 // default to strict mode and case sensitivity.  In addition, most
 // components have no concept of a delimiter or prefix character.
@@ -762,6 +769,62 @@
   return result;
 }
 
+String URLPattern::protocol() const {
+  if (!protocol_)
+    return kDefaultPattern;
+  std::string result = protocol_->pattern.GeneratePatternString();
+  return String::FromUTF8(result);
+}
+
+String URLPattern::username() const {
+  if (!username_)
+    return kDefaultPattern;
+  std::string result = username_->pattern.GeneratePatternString();
+  return String::FromUTF8(result);
+}
+
+String URLPattern::password() const {
+  if (!password_)
+    return kDefaultPattern;
+  std::string result = password_->pattern.GeneratePatternString();
+  return String::FromUTF8(result);
+}
+
+String URLPattern::hostname() const {
+  if (!hostname_)
+    return kDefaultPattern;
+  std::string result = hostname_->pattern.GeneratePatternString();
+  return String::FromUTF8(result);
+}
+
+String URLPattern::port() const {
+  if (!port_)
+    return kDefaultPattern;
+  std::string result = port_->pattern.GeneratePatternString();
+  return String::FromUTF8(result);
+}
+
+String URLPattern::pathname() const {
+  if (!pathname_)
+    return kDefaultPattern;
+  std::string result = pathname_->pattern.GeneratePatternString();
+  return String::FromUTF8(result);
+}
+
+String URLPattern::search() const {
+  if (!search_)
+    return kDefaultPattern;
+  std::string result = search_->pattern.GeneratePatternString();
+  return String::FromUTF8(result);
+}
+
+String URLPattern::hash() const {
+  if (!hash_)
+    return kDefaultPattern;
+  std::string result = hash_->pattern.GeneratePatternString();
+  return String::FromUTF8(result);
+}
+
 void URLPattern::Trace(Visitor* visitor) const {
   visitor->Trace(protocol_);
   visitor->Trace(username_);
@@ -807,7 +870,8 @@
                                           : WTF::kTextCaseASCIIInsensitive;
   DCHECK(base::IsStringASCII(regexp_string));
   ScriptRegexp* regexp = MakeGarbageCollected<ScriptRegexp>(
-      String(regexp_string.data(), regexp_string.size()), case_sensitive);
+      String(regexp_string.data(), regexp_string.size()), case_sensitive,
+      kMultilineDisabled, ScriptRegexp::UTF16);
   if (!regexp->IsValid()) {
     // TODO: Figure out which embedded regex expression caused the failure
     //       by compiling each pattern kRegex part individually.
@@ -823,8 +887,9 @@
     wtf_name_list.push_back(String::FromUTF8(name.data(), name.size()));
   }
 
-  return MakeGarbageCollected<URLPattern::Component>(std::move(regexp),
-                                                     std::move(wtf_name_list));
+  return MakeGarbageCollected<URLPattern::Component>(
+      std::move(parse_result.value()), std::move(regexp),
+      std::move(wtf_name_list));
 }
 
 bool URLPattern::Match(const USVStringOrURLPatternInit& input,
diff --git a/third_party/blink/renderer/modules/url_pattern/url_pattern.h b/third_party/blink/renderer/modules/url_pattern/url_pattern.h
index a780baa..9cb1adc 100644
--- a/third_party/blink/renderer/modules/url_pattern/url_pattern.h
+++ b/third_party/blink/renderer/modules/url_pattern/url_pattern.h
@@ -44,7 +44,14 @@
   URLPatternResult* exec(const USVStringOrURLPatternInit& input,
                          ExceptionState& exception_state) const;
 
-  // TODO: define a stringifier
+  String protocol() const;
+  String username() const;
+  String password() const;
+  String hostname() const;
+  String port() const;
+  String pathname() const;
+  String search() const;
+  String hash() const;
 
   void Trace(Visitor* visitor) const override;
 
diff --git a/third_party/blink/renderer/modules/url_pattern/url_pattern.idl b/third_party/blink/renderer/modules/url_pattern/url_pattern.idl
index 8764631..b4d47a6c 100644
--- a/third_party/blink/renderer/modules/url_pattern/url_pattern.idl
+++ b/third_party/blink/renderer/modules/url_pattern/url_pattern.idl
@@ -13,4 +13,13 @@
   [RaisesException] constructor(URLPatternInit init);
   [RaisesException] boolean test(URLPatternInput input);
   [RaisesException] URLPatternResult exec(URLPatternInput input);
+
+  readonly attribute USVString protocol;
+  readonly attribute USVString username;
+  readonly attribute USVString password;
+  readonly attribute USVString hostname;
+  readonly attribute USVString port;
+  readonly attribute USVString pathname;
+  readonly attribute USVString search;
+  readonly attribute USVString hash;
 };
diff --git a/third_party/blink/renderer/modules/webcodecs/BUILD.gn b/third_party/blink/renderer/modules/webcodecs/BUILD.gn
index 113f3a2..3c5a5489 100644
--- a/third_party/blink/renderer/modules/webcodecs/BUILD.gn
+++ b/third_party/blink/renderer/modules/webcodecs/BUILD.gn
@@ -33,7 +33,6 @@
     "encoded_audio_metadata.h",
     "encoded_video_chunk.cc",
     "encoded_video_chunk.h",
-    "encoded_video_metadata.h",
     "encoder_base.cc",
     "encoder_base.h",
     "hardware_preference.cc",
diff --git a/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.cc b/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.cc
index 177664c..436600b 100644
--- a/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.cc
+++ b/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.cc
@@ -14,37 +14,38 @@
 namespace blink {
 
 EncodedVideoChunk* EncodedVideoChunk::Create(EncodedVideoChunkInit* init) {
-  EncodedVideoMetadata metadata;
-  metadata.timestamp = base::TimeDelta::FromMicroseconds(init->timestamp());
-  metadata.key_frame = (init->type() == "key");
-  if (init->hasDuration()) {
-    metadata.duration = base::TimeDelta::FromMicroseconds(init->duration());
-  }
+  auto timestamp = base::TimeDelta::FromMicroseconds(init->timestamp());
+  bool key_frame = (init->type() == "key");
   DOMArrayPiece piece(init->data());
 
   // A full copy of the data happens here.
   auto* buffer = piece.IsNull()
                      ? nullptr
                      : DOMArrayBuffer::Create(piece.Data(), piece.ByteLength());
-  return MakeGarbageCollected<EncodedVideoChunk>(metadata, buffer);
+  auto* result =
+      MakeGarbageCollected<EncodedVideoChunk>(timestamp, key_frame, buffer);
+  if (init->hasDuration())
+    result->duration_ = base::TimeDelta::FromMicroseconds(init->duration());
+  return result;
 }
 
-EncodedVideoChunk::EncodedVideoChunk(EncodedVideoMetadata metadata,
+EncodedVideoChunk::EncodedVideoChunk(base::TimeDelta timestamp,
+                                     bool key_frame,
                                      DOMArrayBuffer* buffer)
-    : metadata_(metadata), buffer_(buffer) {}
+    : timestamp_(timestamp), key_frame_(key_frame), buffer_(buffer) {}
 
 String EncodedVideoChunk::type() const {
-  return metadata_.key_frame ? "key" : "delta";
+  return key_frame_ ? "key" : "delta";
 }
 
 uint64_t EncodedVideoChunk::timestamp() const {
-  return metadata_.timestamp.InMicroseconds();
+  return timestamp_.InMicroseconds();
 }
 
 base::Optional<uint64_t> EncodedVideoChunk::duration() const {
-  if (!metadata_.duration)
+  if (!duration_.has_value())
     return base::nullopt;
-  return metadata_.duration->InMicroseconds();
+  return duration_->InMicroseconds();
 }
 
 DOMArrayBuffer* EncodedVideoChunk::data() const {
diff --git a/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.h b/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.h
index 64ebb96..f56d109 100644
--- a/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.h
+++ b/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.h
@@ -7,7 +7,6 @@
 
 #include "third_party/blink/renderer/core/typed_arrays/dom_array_piece.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/modules/webcodecs/encoded_video_metadata.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 
 namespace blink {
@@ -19,7 +18,9 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  EncodedVideoChunk(EncodedVideoMetadata metadata, DOMArrayBuffer* buffer);
+  EncodedVideoChunk(base::TimeDelta timestamp,
+                    bool key_frame,
+                    DOMArrayBuffer* buffer);
 
   static EncodedVideoChunk* Create(EncodedVideoChunkInit* init);
 
@@ -35,7 +36,9 @@
   }
 
  private:
-  EncodedVideoMetadata metadata_;
+  base::TimeDelta timestamp_;
+  bool key_frame_ = false;
+  base::Optional<base::TimeDelta> duration_;
   Member<DOMArrayBuffer> buffer_;
 };
 
diff --git a/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_metadata.idl b/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_metadata.idl
new file mode 100644
index 0000000..da51cd23
--- /dev/null
+++ b/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_metadata.idl
@@ -0,0 +1,10 @@
+// Copyright 2021 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.
+
+// https://github.com/WICG/web-codecs
+
+dictionary EncodedVideoChunkMetadata {
+  VideoDecoderConfig decoderConfig;
+  unsigned long temporalLayerId;
+};
diff --git a/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_output_callback.idl b/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_output_callback.idl
new file mode 100644
index 0000000..d3d57dd1
--- /dev/null
+++ b/third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_output_callback.idl
@@ -0,0 +1,9 @@
+// Copyright 2021 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.
+
+// https://github.com/WICG/web-codecs
+
+// Handles a new encoded video chunk on the consumer side of the video encoder.
+callback EncodedVideoChunkOutputCallback =
+  void (EncodedVideoChunk chunk, EncodedVideoChunkMetadata metadata);
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/webcodecs/encoded_video_metadata.h b/third_party/blink/renderer/modules/webcodecs/encoded_video_metadata.h
deleted file mode 100644
index 6049f151..0000000
--- a/third_party/blink/renderer/modules/webcodecs/encoded_video_metadata.h
+++ /dev/null
@@ -1,21 +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.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_ENCODED_VIDEO_METADATA_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_ENCODED_VIDEO_METADATA_H_
-
-#include "base/optional.h"
-#include "base/time/time.h"
-
-namespace blink {
-
-struct EncodedVideoMetadata {
-  bool key_frame = false;
-  base::TimeDelta timestamp;
-  base::Optional<base::TimeDelta> duration;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_ENCODED_VIDEO_METADATA_H_
diff --git a/third_party/blink/renderer/modules/webcodecs/encoder_base.cc b/third_party/blink/renderer/modules/webcodecs/encoder_base.cc
index 8fddca4..83d2410e 100644
--- a/third_party/blink/renderer/modules/webcodecs/encoder_base.cc
+++ b/third_party/blink/renderer/modules/webcodecs/encoder_base.cc
@@ -24,7 +24,6 @@
 #include "third_party/blink/renderer/modules/webcodecs/audio_encoder.h"
 #include "third_party/blink/renderer/modules/webcodecs/codec_state_helper.h"
 #include "third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.h"
-#include "third_party/blink/renderer/modules/webcodecs/encoded_video_metadata.h"
 #include "third_party/blink/renderer/modules/webcodecs/video_encoder.h"
 #include "third_party/blink/renderer/platform/bindings/enumeration_base.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
diff --git a/third_party/blink/renderer/modules/webcodecs/idls.gni b/third_party/blink/renderer/modules/webcodecs/idls.gni
index 4fee9b8..46a701bc 100644
--- a/third_party/blink/renderer/modules/webcodecs/idls.gni
+++ b/third_party/blink/renderer/modules/webcodecs/idls.gni
@@ -18,7 +18,7 @@
 modules_callback_function_idl_files = [
   "audio_frame_output_callback.idl",
   "encoded_audio_chunk_output_callback.idl",
-  "video_encoder_output_callback.idl",
+  "encoded_video_chunk_output_callback.idl",
   "video_frame_output_callback.idl",
   "webcodecs_error_callback.idl",
 ]
@@ -33,6 +33,7 @@
   "avc_encoder_config.idl",
   "encoded_audio_chunk_init.idl",
   "encoded_video_chunk_init.idl",
+  "encoded_video_chunk_metadata.idl",
   "image_decode_options.idl",
   "image_decode_result.idl",
   "image_decoder_init.idl",
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
index fe54014..bf65851 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
@@ -30,6 +30,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_dom_exception.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_avc_encoder_config.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk_metadata.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_config.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_video_encoder_config.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_video_encoder_encode_options.h"
@@ -39,7 +40,6 @@
 #include "third_party/blink/renderer/core/streams/writable_stream.h"
 #include "third_party/blink/renderer/modules/webcodecs/codec_state_helper.h"
 #include "third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.h"
-#include "third_party/blink/renderer/modules/webcodecs/encoded_video_metadata.h"
 #include "third_party/blink/renderer/platform/bindings/enumeration_base.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
@@ -194,6 +194,18 @@
   if (config->hasBitrate())
     parsed->options.bitrate = config->bitrate();
 
+  // https://w3c.github.io/webrtc-svc/
+  if (config->hasScalabilityMode()) {
+    if (config->scalabilityMode() == "L1T2") {
+      parsed->options.temporal_layers = 2;
+    } else if (config->scalabilityMode() == "L1T3") {
+      parsed->options.temporal_layers = 3;
+    } else {
+      exception_state.ThrowTypeError("Unsupported scalabilityMode.");
+      return nullptr;
+    }
+  }
+
   // The IDL defines a default value of "allow".
   DCHECK(config->hasHardwareAcceleration());
 
@@ -625,18 +637,15 @@
       reset_count != reset_count_)
     return;
 
-  EncodedVideoMetadata metadata;
-  metadata.timestamp = output.timestamp;
-  metadata.key_frame = output.key_frame;
   auto deleter = [](void* data, size_t length, void*) {
     delete[] static_cast<uint8_t*>(data);
   };
   ArrayBufferContents data(output.data.release(), output.size, deleter);
   auto* dom_array = MakeGarbageCollected<DOMArrayBuffer>(std::move(data));
-  auto* chunk = MakeGarbageCollected<EncodedVideoChunk>(metadata, dom_array);
+  auto* chunk = MakeGarbageCollected<EncodedVideoChunk>(
+      output.timestamp, output.key_frame, dom_array);
 
-  VideoDecoderConfig* decoder_config =
-      MakeGarbageCollected<VideoDecoderConfig>();
+  auto* decoder_config = MakeGarbageCollected<VideoDecoderConfig>();
   decoder_config->setCodec(active_config->codec_string);
   decoder_config->setCodedHeight(active_config->options.frame_size.height());
   decoder_config->setCodedWidth(active_config->options.frame_size.width());
@@ -646,8 +655,13 @@
     decoder_config->setDescription(
         ArrayBufferOrArrayBufferView::FromArrayBuffer(desc_array_buf));
   }
+
+  auto* metadata = MakeGarbageCollected<EncodedVideoChunkMetadata>();
+  metadata->setDecoderConfig(decoder_config);
+  metadata->setTemporalLayerId(output.temporal_id);
+
   ScriptState::Scope scope(script_state_);
-  output_callback_->InvokeAndReportException(nullptr, chunk, decoder_config);
+  output_callback_->InvokeAndReportException(nullptr, chunk, metadata);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder.h b/third_party/blink/renderer/modules/webcodecs/video_encoder.h
index 7e18576..f2635f0e 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_encoder.h
+++ b/third_party/blink/renderer/modules/webcodecs/video_encoder.h
@@ -12,7 +12,7 @@
 #include "media/base/video_color_space.h"
 #include "media/base/video_encoder.h"
 #include "media/base/video_frame_pool.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_video_encoder_output_callback.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk_output_callback.h"
 #include "third_party/blink/renderer/modules/webcodecs/encoder_base.h"
 #include "third_party/blink/renderer/modules/webcodecs/hardware_preference.h"
 #include "third_party/blink/renderer/modules/webcodecs/video_frame.h"
@@ -51,7 +51,7 @@
   using Frame = VideoFrame;
   using EncodeOptions = VideoEncoderEncodeOptions;
   using OutputChunk = EncodedVideoChunk;
-  using OutputCallback = V8VideoEncoderOutputCallback;
+  using OutputCallback = V8EncodedVideoChunkOutputCallback;
   using MediaEncoder = media::VideoEncoder;
 
   // Can't be a virtual method, because it's used from base ctor.
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder_config.idl b/third_party/blink/renderer/modules/webcodecs/video_encoder_config.idl
index e849d30..89b9b2a 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_encoder_config.idl
+++ b/third_party/blink/renderer/modules/webcodecs/video_encoder_config.idl
@@ -16,4 +16,7 @@
   required unsigned long height;
 
   AvcEncoderConfig avc;
+
+  // Same as in WebRTC SVC (https://w3c.github.io/webrtc-svc/)
+  DOMString scalabilityMode;
 };
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder_fuzzer.cc b/third_party/blink/renderer/modules/webcodecs/video_encoder_fuzzer.cc
index 1f47371..52fd6881 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_encoder_fuzzer.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_encoder_fuzzer.cc
@@ -6,9 +6,9 @@
 #include "base/run_loop.h"
 #include "testing/libfuzzer/proto/lpm_interface.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk_output_callback.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_config.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_video_encoder_init.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_video_encoder_output_callback.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_webcodecs_error_callback.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
@@ -66,8 +66,8 @@
         V8WebCodecsErrorCallback::Create(error_function->Bind());
     Persistent<FakeFunction> output_function =
         FakeFunction::Create(script_state, "output");
-    Persistent<V8VideoEncoderOutputCallback> output_callback =
-        V8VideoEncoderOutputCallback::Create(output_function->Bind());
+    Persistent<V8EncodedVideoChunkOutputCallback> output_callback =
+        V8EncodedVideoChunkOutputCallback::Create(output_function->Bind());
 
     Persistent<VideoEncoderInit> video_encoder_init =
         MakeGarbageCollected<VideoEncoderInit>();
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder_init.idl b/third_party/blink/renderer/modules/webcodecs/video_encoder_init.idl
index 4155ad6..3451369 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_encoder_init.idl
+++ b/third_party/blink/renderer/modules/webcodecs/video_encoder_init.idl
@@ -6,7 +6,7 @@
 
 dictionary VideoEncoderInit {
   // Called whenever there is a new encoded video chunk available.
-  required VideoEncoderOutputCallback output;
+  required EncodedVideoChunkOutputCallback output;
 
   // Called when there is a decoding error.
   required WebCodecsErrorCallback error;
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder_output_callback.idl b/third_party/blink/renderer/modules/webcodecs/video_encoder_output_callback.idl
deleted file mode 100644
index f09eb32..0000000
--- a/third_party/blink/renderer/modules/webcodecs/video_encoder_output_callback.idl
+++ /dev/null
@@ -1,9 +0,0 @@
-// 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.
-
-// https://github.com/WICG/web-codecs
-
-// Handles a new encoded video chunk on the consumer side of the video encoder.
-callback VideoEncoderOutputCallback =
-  void (EncodedVideoChunk chunk, VideoDecoderConfig decoder_config);
\ No newline at end of file
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 9e2d616..a946609 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1470,14 +1470,14 @@
     "weborigin/security_origin_hash.h",
     "weborigin/security_policy.cc",
     "weborigin/security_policy.h",
+    "webrtc/legacy_webrtc_video_frame_adapter.cc",
+    "webrtc/legacy_webrtc_video_frame_adapter.h",
     "webrtc/peer_connection_remote_audio_source.cc",
     "webrtc/peer_connection_remote_audio_source.h",
     "webrtc/track_observer.cc",
     "webrtc/track_observer.h",
     "webrtc/webrtc_logging.cc",
     "webrtc/webrtc_source.h",
-    "webrtc/webrtc_video_frame_adapter.cc",
-    "webrtc/webrtc_video_frame_adapter.h",
     "webrtc/webrtc_video_utils.cc",
     "webrtc/webrtc_video_utils.h",
     "widget/compositing/layer_tree_settings.cc",
@@ -2145,7 +2145,7 @@
     "weborigin/scheme_registry_test.cc",
     "weborigin/security_origin_test.cc",
     "weborigin/security_policy_test.cc",
-    "webrtc/webrtc_video_frame_adapter_test.cc",
+    "webrtc/legacy_webrtc_video_frame_adapter_test.cc",
     "widget/compositing/layer_tree_settings_unittest.cc",
     "widget/compositing/layer_tree_view_unittest.cc",
     "widget/compositing/render_frame_metadata_observer_impl_unittest.cc",
diff --git a/third_party/blink/renderer/platform/bindings/v8_set_return_value.h b/third_party/blink/renderer/platform/bindings/v8_set_return_value.h
index 0771aba..7afac979 100644
--- a/third_party/blink/renderer/platform/bindings/v8_set_return_value.h
+++ b/third_party/blink/renderer/platform/bindings/v8_set_return_value.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_V8_SET_RETURN_VALUE_H_
 
 #include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/renderer/platform/bindings/dictionary_base.h"
 #include "third_party/blink/renderer/platform/bindings/dom_data_store.h"
 #include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
@@ -365,6 +366,16 @@
       wrappable->Wrap(info.GetIsolate(), creation_context->Global()));
 }
 
+// DictionaryBase
+template <typename CallbackInfo>
+void V8SetReturnValue(const CallbackInfo& info,
+                      const bindings::DictionaryBase* dictionary) {
+  DCHECK(dictionary);
+  v8::Local<v8::Value> v8_value = dictionary->CreateV8Object(
+      info.GetIsolate(), V8ReturnValue::CreationContext(info));
+  V8SetReturnValue(info, v8_value);
+}
+
 // Exposed objects
 PLATFORM_EXPORT v8::Local<v8::Value> GetExposedInterfaceObject(
     v8::Isolate* isolate,
diff --git a/third_party/blink/renderer/platform/graphics/compositor_element_id.cc b/third_party/blink/renderer/platform/graphics/compositor_element_id.cc
index c6ed784..52d230e 100644
--- a/third_party/blink/renderer/platform/graphics/compositor_element_id.cc
+++ b/third_party/blink/renderer/platform/graphics/compositor_element_id.cc
@@ -36,8 +36,8 @@
 CompositorElementId PLATFORM_EXPORT
 CompositorElementIdFromDOMNodeId(DOMNodeId id) {
   DCHECK_GE(id, 0);
-  return CreateCompositorElementId(
-      id, CompositorElementIdNamespace::kUniqueObjectId);
+  return CreateCompositorElementId(id,
+                                   CompositorElementIdNamespace::kDOMNodeId);
 }
 
 CompositorElementId PLATFORM_EXPORT
diff --git a/third_party/blink/renderer/platform/graphics/compositor_element_id_test.cc b/third_party/blink/renderer/platform/graphics/compositor_element_id_test.cc
index 0b7f398..77dc0fe 100644
--- a/third_party/blink/renderer/platform/graphics/compositor_element_id_test.cc
+++ b/third_party/blink/renderer/platform/graphics/compositor_element_id_test.cc
@@ -30,7 +30,7 @@
 TEST_F(CompositorElementIdTest, FromDOMNodeId) {
   auto element_id = CompositorElementIdFromDOMNodeId(1);
   EXPECT_EQ(1u, IdFromCompositorElementId(element_id));
-  EXPECT_EQ(CompositorElementIdNamespace::kUniqueObjectId,
+  EXPECT_EQ(CompositorElementIdNamespace::kDOMNodeId,
             NamespaceFromCompositorElementId(element_id));
 }
 
@@ -42,4 +42,11 @@
   EXPECT_EQ(1, DOMNodeIdFromCompositorElementId(element_id));
 }
 
+TEST_F(CompositorElementIdTest, EncodeDecodeDOMNodeId) {
+  auto element_id = CompositorElementIdFromDOMNodeId(1);
+  EXPECT_EQ(CompositorElementIdNamespace::kDOMNodeId,
+            NamespaceFromCompositorElementId(element_id));
+  EXPECT_EQ(1, DOMNodeIdFromCompositorElementId(element_id));
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/web_resource_request_sender.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/web_resource_request_sender.cc
index 0d99ea3b..744da0d0 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/web_resource_request_sender.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/web_resource_request_sender.cc
@@ -271,8 +271,8 @@
   // Compute a unique request_id for this renderer process.
   int request_id = MakeRequestID();
   request_info_ = std::make_unique<PendingRequestInfo>(
-      std::move(peer), request->destination, request->render_frame_id,
-      request->url, std::move(resource_load_info_notifier_wrapper));
+      std::move(peer), request->destination, request->url,
+      std::move(resource_load_info_notifier_wrapper));
 
   request_info_->resource_load_info_notifier_wrapper
       ->NotifyResourceLoadInitiated(
@@ -365,13 +365,11 @@
 WebResourceRequestSender::PendingRequestInfo::PendingRequestInfo(
     scoped_refptr<WebRequestPeer> peer,
     network::mojom::RequestDestination request_destination,
-    int render_frame_id,
     const GURL& request_url,
     std::unique_ptr<ResourceLoadInfoNotifierWrapper>
         resource_load_info_notifier_wrapper)
     : peer(std::move(peer)),
       request_destination(request_destination),
-      render_frame_id(render_frame_id),
       url(request_url),
       response_url(request_url),
       local_request_start(base::TimeTicks::Now()),
diff --git a/third_party/blink/renderer/platform/loader/web_url_request_extra_data.cc b/third_party/blink/renderer/platform/loader/web_url_request_extra_data.cc
index 9a341b2..89b6933 100644
--- a/third_party/blink/renderer/platform/loader/web_url_request_extra_data.cc
+++ b/third_party/blink/renderer/platform/loader/web_url_request_extra_data.cc
@@ -8,14 +8,12 @@
 
 namespace blink {
 
-WebURLRequestExtraData::WebURLRequestExtraData()
-    : render_frame_id_(MSG_ROUTING_NONE) {}
+WebURLRequestExtraData::WebURLRequestExtraData() = default;
 
 WebURLRequestExtraData::~WebURLRequestExtraData() = default;
 
 void WebURLRequestExtraData::CopyToResourceRequest(
     network::ResourceRequest* request) const {
-  request->render_frame_id = render_frame_id_.value();
   request->is_main_frame = is_main_frame_;
   request->transition_type = transition_type_;
   request->originated_from_service_worker = originated_from_service_worker_;
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc
index 5d7533f..b382c416 100644
--- a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc
@@ -32,7 +32,7 @@
 #include "media/video/video_decode_accelerator.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
-#include "third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.h"
+#include "third_party/blink/renderer/platform/webrtc/legacy_webrtc_video_frame_adapter.h"
 #include "third_party/blink/renderer/platform/webrtc/webrtc_video_utils.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
 #include "third_party/webrtc/api/video/video_frame.h"
@@ -592,7 +592,7 @@
   webrtc::VideoFrame rtc_frame =
       webrtc::VideoFrame::Builder()
           .set_video_frame_buffer(
-              new rtc::RefCountedObject<blink::WebRtcVideoFrameAdapter>(
+              new rtc::RefCountedObject<blink::LegacyWebRtcVideoFrameAdapter>(
                   std::move(frame)))
           .set_timestamp_rtp(static_cast<uint32_t>(timestamp.InMicroseconds()))
           .set_timestamp_us(0)
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.cc
index 097f4e0..8d5db14 100644
--- a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.cc
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.cc
@@ -32,7 +32,7 @@
 #include "media/video/video_decode_accelerator.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
-#include "third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.h"
+#include "third_party/blink/renderer/platform/webrtc/legacy_webrtc_video_frame_adapter.h"
 #include "third_party/blink/renderer/platform/webrtc/webrtc_video_utils.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
 #include "third_party/webrtc/api/video/video_frame.h"
@@ -640,7 +640,7 @@
   webrtc::VideoFrame rtc_frame =
       webrtc::VideoFrame::Builder()
           .set_video_frame_buffer(
-              new rtc::RefCountedObject<blink::WebRtcVideoFrameAdapter>(
+              new rtc::RefCountedObject<blink::LegacyWebRtcVideoFrameAdapter>(
                   std::move(frame)))
           .set_timestamp_rtp(static_cast<uint32_t>(timestamp.InMicroseconds()))
           .set_timestamp_us(0)
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc
index addf8c8..f8557449 100644
--- a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc
@@ -34,7 +34,7 @@
 #include "media/video/video_encode_accelerator.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
-#include "third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.h"
+#include "third_party/blink/renderer/platform/webrtc/legacy_webrtc_video_frame_adapter.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
 #include "third_party/blink/renderer/platform/wtf/deque.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
@@ -1061,7 +1061,7 @@
   // conditions are met.
   bool requires_copy = !is_native_frame;
   if (!requires_copy) {
-    frame = static_cast<blink::WebRtcVideoFrameAdapter*>(
+    frame = static_cast<blink::LegacyWebRtcVideoFrameAdapter*>(
                 next_frame->video_frame_buffer().get())
                 ->getMediaVideoFrame();
     const media::VideoFrame::StorageType storage = frame->storage_type();
@@ -1173,7 +1173,7 @@
     frame->set_timestamp(
         base::TimeDelta::FromMilliseconds(next_frame->ntp_time_ms()));
   } else {
-    frame = static_cast<blink::WebRtcVideoFrameAdapter*>(
+    frame = static_cast<blink::LegacyWebRtcVideoFrameAdapter*>(
                 next_frame->video_frame_buffer().get())
                 ->getMediaVideoFrame();
   }
diff --git a/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.cc b/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.cc
index 4e711b8..63f56d29 100644
--- a/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.cc
+++ b/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.cc
@@ -92,7 +92,7 @@
     media::GpuVideoAcceleratorFactories* gpu_factories)
     : AdaptedVideoTrackSource(/*required_alignment=*/1),
       adapter_resources_(
-          new WebRtcVideoFrameAdapter::SharedResources(gpu_factories)),
+          new LegacyWebRtcVideoFrameAdapter::SharedResources(gpu_factories)),
       is_screencast_(is_screencast),
       needs_denoising_(needs_denoising),
       callback_(callback) {
@@ -144,7 +144,7 @@
     scoped_refptr<media::VideoFrame> frame) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   TRACE_EVENT0("media", "WebRtcVideoSource::OnFrameCaptured");
-  if (!WebRtcVideoFrameAdapter::IsFrameAdaptable(frame.get())) {
+  if (!LegacyWebRtcVideoFrameAdapter::IsFrameAdaptable(frame.get())) {
     // Since connecting sources and sinks do not check the format, we need to
     // just ignore formats that we can not handle.
     LOG(ERROR) << "We cannot send frame with storage type: "
@@ -317,7 +317,7 @@
   webrtc::VideoFrame::Builder frame_builder =
       webrtc::VideoFrame::Builder()
           .set_video_frame_buffer(
-              new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(
+              new rtc::RefCountedObject<LegacyWebRtcVideoFrameAdapter>(
                   frame, adapter_resources_))
           .set_rotation(GetFrameRotation(frame.get()))
           .set_timestamp_us(timestamp_us);
diff --git a/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.h b/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.h
index d698b46d..0343b44 100644
--- a/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.h
+++ b/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.h
@@ -11,7 +11,7 @@
 #include "media/base/video_frame_pool.h"
 #include "media/capture/video_frame_feedback.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.h"
+#include "third_party/blink/renderer/platform/webrtc/legacy_webrtc_video_frame_adapter.h"
 #include "third_party/webrtc/media/base/adapted_video_track_source.h"
 #include "third_party/webrtc/rtc_base/timestamp_aligner.h"
 
@@ -76,7 +76,8 @@
 
   // |thread_checker_| is bound to the libjingle worker thread.
   THREAD_CHECKER(thread_checker_);
-  scoped_refptr<WebRtcVideoFrameAdapter::SharedResources> adapter_resources_;
+  scoped_refptr<LegacyWebRtcVideoFrameAdapter::SharedResources>
+      adapter_resources_;
   // State for the timestamp translation.
   rtc::TimestampAligner timestamp_aligner_;
 
diff --git a/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source_test.cc b/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source_test.cc
index f2f8c65..158a4b7 100644
--- a/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source_test.cc
+++ b/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source_test.cc
@@ -146,7 +146,7 @@
   std::vector<WebRtcVideoTrackSourceTest::ParamType> test_params;
   // All formats for owned memory.
   for (media::VideoPixelFormat format :
-       WebRtcVideoFrameAdapter::AdaptableMappablePixelFormats()) {
+       LegacyWebRtcVideoFrameAdapter::AdaptableMappablePixelFormats()) {
     test_params.emplace_back(
         media::VideoFrame::StorageType::STORAGE_OWNED_MEMORY, format);
   }
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 2447c80..fc61624 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -748,6 +748,10 @@
       status: "experimental",
     },
     {
+      name: "DevicePosture",
+      status: "experimental",
+    },
+    {
       name: "DigitalGoods",
       origin_trial_feature_name: "DigitalGoods",
       origin_trial_os: ["android", "chromeos"],
@@ -1803,10 +1807,6 @@
       status: "test",
     },
     {
-      name: "ScreenFold",
-      status: "experimental",
-    },
-    {
       name: "ScreenWakeLock",
       status: "stable",
     },
diff --git a/third_party/blink/renderer/platform/webrtc/DEPS b/third_party/blink/renderer/platform/webrtc/DEPS
index d3f385b8..53af1825 100644
--- a/third_party/blink/renderer/platform/webrtc/DEPS
+++ b/third_party/blink/renderer/platform/webrtc/DEPS
@@ -4,11 +4,11 @@
 ]
 
 specific_include_rules = {
-    "webrtc_video_frame_adapter\.cc": [
+    "legacy_webrtc_video_frame_adapter\.cc": [
         "+media/video/gpu_video_accelerator_factories.h",
         "+gpu/command_buffer/client/raster_interface.h",
     ],
-    "webrtc_video_frame_adapter\.h": [
+    "legacy_webrtc_video_frame_adapter\.h": [
         "+components/viz/common/gpu/raster_context_provider.h",
     ],
 }
diff --git a/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.cc b/third_party/blink/renderer/platform/webrtc/legacy_webrtc_video_frame_adapter.cc
similarity index 92%
rename from third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.cc
rename to third_party/blink/renderer/platform/webrtc/legacy_webrtc_video_frame_adapter.cc
index f6a2efa..90f8d45 100644
--- a/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.cc
+++ b/third_party/blink/renderer/platform/webrtc/legacy_webrtc_video_frame_adapter.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 "third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.h"
+#include "third_party/blink/renderer/platform/webrtc/legacy_webrtc_video_frame_adapter.h"
 
 #include "base/callback_helpers.h"
 #include "base/containers/span.h"
@@ -178,7 +178,7 @@
 
 scoped_refptr<media::VideoFrame> MakeScaledI420VideoFrame(
     scoped_refptr<media::VideoFrame> source_frame,
-    scoped_refptr<blink::WebRtcVideoFrameAdapter::SharedResources>
+    scoped_refptr<blink::LegacyWebRtcVideoFrameAdapter::SharedResources>
         shared_resources) {
   // ARGB pixel format may be produced by readback of texture backed frames.
   DCHECK(source_frame->format() == media::PIXEL_FORMAT_NV12 ||
@@ -301,7 +301,7 @@
 
 scoped_refptr<media::VideoFrame> MakeScaledNV12VideoFrame(
     scoped_refptr<media::VideoFrame> source_frame,
-    scoped_refptr<blink::WebRtcVideoFrameAdapter::SharedResources>
+    scoped_refptr<blink::LegacyWebRtcVideoFrameAdapter::SharedResources>
         shared_resources) {
   DCHECK_EQ(source_frame->format(), media::PIXEL_FORMAT_NV12);
   auto dst_frame = shared_resources->CreateFrame(
@@ -327,7 +327,7 @@
 
 scoped_refptr<media::VideoFrame> MaybeConvertAndScaleFrame(
     scoped_refptr<media::VideoFrame> source_frame,
-    scoped_refptr<blink::WebRtcVideoFrameAdapter::SharedResources>
+    scoped_refptr<blink::LegacyWebRtcVideoFrameAdapter::SharedResources>
         shared_resources) {
   if (!source_frame)
     return nullptr;
@@ -374,7 +374,7 @@
 namespace blink {
 
 scoped_refptr<media::VideoFrame>
-WebRtcVideoFrameAdapter::SharedResources::CreateFrame(
+LegacyWebRtcVideoFrameAdapter::SharedResources::CreateFrame(
     media::VideoPixelFormat format,
     const gfx::Size& coded_size,
     const gfx::Rect& visible_rect,
@@ -385,7 +385,7 @@
 }
 
 scoped_refptr<media::VideoFrame>
-WebRtcVideoFrameAdapter::SharedResources::CreateTemporaryFrame(
+LegacyWebRtcVideoFrameAdapter::SharedResources::CreateTemporaryFrame(
     media::VideoPixelFormat format,
     const gfx::Size& coded_size,
     const gfx::Rect& visible_rect,
@@ -396,7 +396,7 @@
 }
 
 scoped_refptr<viz::RasterContextProvider>
-WebRtcVideoFrameAdapter::SharedResources::GetRasterContextProvider() {
+LegacyWebRtcVideoFrameAdapter::SharedResources::GetRasterContextProvider() {
   base::AutoLock auto_lock(context_provider_lock_);
   if (raster_context_provider_) {
     // Reuse created context provider if it's alive.
@@ -423,7 +423,7 @@
 }
 
 scoped_refptr<media::VideoFrame>
-WebRtcVideoFrameAdapter::SharedResources::ConstructVideoFrameFromTexture(
+LegacyWebRtcVideoFrameAdapter::SharedResources::ConstructVideoFrameFromTexture(
     scoped_refptr<media::VideoFrame> source_frame) {
   RTC_DCHECK(source_frame->HasTextures());
 
@@ -447,7 +447,7 @@
 }
 
 scoped_refptr<media::VideoFrame>
-WebRtcVideoFrameAdapter::SharedResources::ConstructVideoFrameFromGpu(
+LegacyWebRtcVideoFrameAdapter::SharedResources::ConstructVideoFrameFromGpu(
     scoped_refptr<media::VideoFrame> source_frame) {
   CHECK(source_frame);
   // NV12 is the only supported format.
@@ -458,54 +458,55 @@
   return media::ConvertToMemoryMappedFrame(std::move(source_frame));
 }
 
-void WebRtcVideoFrameAdapter::SharedResources::SetFeedback(
+void LegacyWebRtcVideoFrameAdapter::SharedResources::SetFeedback(
     const media::VideoFrameFeedback& feedback) {
   base::AutoLock auto_lock(feedback_lock_);
   last_feedback_ = feedback;
 }
 
 media::VideoFrameFeedback
-WebRtcVideoFrameAdapter::SharedResources::GetFeedback() {
+LegacyWebRtcVideoFrameAdapter::SharedResources::GetFeedback() {
   base::AutoLock auto_lock(feedback_lock_);
   return last_feedback_;
 }
 
-WebRtcVideoFrameAdapter::SharedResources::SharedResources(
+LegacyWebRtcVideoFrameAdapter::SharedResources::SharedResources(
     media::GpuVideoAcceleratorFactories* gpu_factories)
     : gpu_factories_(gpu_factories) {}
 
-WebRtcVideoFrameAdapter::SharedResources::~SharedResources() = default;
+LegacyWebRtcVideoFrameAdapter::SharedResources::~SharedResources() = default;
 
-WebRtcVideoFrameAdapter::WebRtcVideoFrameAdapter(
+LegacyWebRtcVideoFrameAdapter::LegacyWebRtcVideoFrameAdapter(
     scoped_refptr<media::VideoFrame> frame)
-    : WebRtcVideoFrameAdapter(frame, nullptr) {}
+    : LegacyWebRtcVideoFrameAdapter(frame, nullptr) {}
 
-WebRtcVideoFrameAdapter::WebRtcVideoFrameAdapter(
+LegacyWebRtcVideoFrameAdapter::LegacyWebRtcVideoFrameAdapter(
     scoped_refptr<media::VideoFrame> frame,
     scoped_refptr<SharedResources> shared_resources)
     : frame_(std::move(frame)), shared_resources_(shared_resources) {}
 
-WebRtcVideoFrameAdapter::~WebRtcVideoFrameAdapter() {
+LegacyWebRtcVideoFrameAdapter::~LegacyWebRtcVideoFrameAdapter() {
   if (shared_resources_) {
     shared_resources_->SetFeedback(
         media::VideoFrameFeedback().RequireMapped(was_mapped_));
   }
 }
 
-webrtc::VideoFrameBuffer::Type WebRtcVideoFrameAdapter::type() const {
+webrtc::VideoFrameBuffer::Type LegacyWebRtcVideoFrameAdapter::type() const {
   return Type::kNative;
 }
 
-int WebRtcVideoFrameAdapter::width() const {
+int LegacyWebRtcVideoFrameAdapter::width() const {
   return frame_->natural_size().width();
 }
 
-int WebRtcVideoFrameAdapter::height() const {
+int LegacyWebRtcVideoFrameAdapter::height() const {
   return frame_->natural_size().height();
 }
 
 // static
-bool WebRtcVideoFrameAdapter::IsFrameAdaptable(const media::VideoFrame* frame) {
+bool LegacyWebRtcVideoFrameAdapter::IsFrameAdaptable(
+    const media::VideoFrame* frame) {
   // Currently accept I420, I420A, NV12 formats in a mapped frame,
   // or a texture or GPU memory buffer frame.
   return (frame->IsMappable() &&
@@ -517,7 +518,7 @@
 
 // static
 base::span<const media::VideoPixelFormat>
-WebRtcVideoFrameAdapter::AdaptableMappablePixelFormats() {
+LegacyWebRtcVideoFrameAdapter::AdaptableMappablePixelFormats() {
   static constexpr const media::VideoPixelFormat
       kAdaptableMappablePixelFormats[] = {media::PIXEL_FORMAT_I420,
                                           media::PIXEL_FORMAT_I420A,
@@ -526,7 +527,7 @@
 }
 
 rtc::scoped_refptr<webrtc::VideoFrameBuffer>
-WebRtcVideoFrameAdapter::CreateFrameAdapter() const {
+LegacyWebRtcVideoFrameAdapter::CreateFrameAdapter() const {
   DCHECK(IsFrameAdaptable(frame_.get()))
       << "Can not create WebRTC frame adapter for frame "
       << frame_->AsHumanReadableString();
@@ -566,7 +567,7 @@
 }
 
 rtc::scoped_refptr<webrtc::I420BufferInterface>
-WebRtcVideoFrameAdapter::ToI420() {
+LegacyWebRtcVideoFrameAdapter::ToI420() {
   base::AutoLock auto_lock(adapter_lock_);
   if (!frame_adapter_) {
     frame_adapter_ = CreateFrameAdapter();
@@ -575,7 +576,7 @@
 }
 
 rtc::scoped_refptr<webrtc::VideoFrameBuffer>
-WebRtcVideoFrameAdapter::GetMappedFrameBuffer(
+LegacyWebRtcVideoFrameAdapter::GetMappedFrameBuffer(
     rtc::ArrayView<webrtc::VideoFrameBuffer::Type> types) {
   base::AutoLock auto_lock(adapter_lock_);
   if (!frame_adapter_) {
@@ -587,7 +588,8 @@
   return nullptr;
 }
 
-const webrtc::I420BufferInterface* WebRtcVideoFrameAdapter::GetI420() const {
+const webrtc::I420BufferInterface* LegacyWebRtcVideoFrameAdapter::GetI420()
+    const {
   base::AutoLock auto_lock(adapter_lock_);
   if (!frame_adapter_) {
     frame_adapter_ = CreateFrameAdapter();
diff --git a/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.h b/third_party/blink/renderer/platform/webrtc/legacy_webrtc_video_frame_adapter.h
similarity index 87%
rename from third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.h
rename to third_party/blink/renderer/platform/webrtc/legacy_webrtc_video_frame_adapter.h
index dee47e27..ca93b27 100644
--- a/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.h
+++ b/third_party/blink/renderer/platform/webrtc/legacy_webrtc_video_frame_adapter.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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_WEBRTC_WEBRTC_VIDEO_FRAME_ADAPTER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WEBRTC_WEBRTC_VIDEO_FRAME_ADAPTER_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WEBRTC_LEGACY_WEBRTC_VIDEO_FRAME_ADAPTER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WEBRTC_LEGACY_WEBRTC_VIDEO_FRAME_ADAPTER_H_
 
 #include <stdint.h>
 #include <map>
@@ -34,9 +34,9 @@
 // - The frame is mappable in either I420, I420A or NV12 pixel formats.
 // - Or, the frame is on a GPU Memory Buffer in NV12.
 // - Or, the frame has textures.
-// Creators of WebRtcVideoFrameAdapter can ensure the frame is convertible by
-// calling |IsFrameAdaptable| before constructing this object.
-class PLATFORM_EXPORT WebRtcVideoFrameAdapter
+// Creators of LegacyWebRtcVideoFrameAdapter can ensure the frame is convertible
+// by calling |IsFrameAdaptable| before constructing this object.
+class PLATFORM_EXPORT LegacyWebRtcVideoFrameAdapter
     : public webrtc::VideoFrameBuffer {
  public:
   class PLATFORM_EXPORT SharedResources
@@ -113,9 +113,11 @@
   static base::span<const media::VideoPixelFormat>
   AdaptableMappablePixelFormats();
 
-  explicit WebRtcVideoFrameAdapter(scoped_refptr<media::VideoFrame> frame);
-  WebRtcVideoFrameAdapter(scoped_refptr<media::VideoFrame> frame,
-                          scoped_refptr<SharedResources> shared_resources);
+  explicit LegacyWebRtcVideoFrameAdapter(
+      scoped_refptr<media::VideoFrame> frame);
+  LegacyWebRtcVideoFrameAdapter(
+      scoped_refptr<media::VideoFrame> frame,
+      scoped_refptr<SharedResources> shared_resources);
 
   scoped_refptr<media::VideoFrame> getMediaVideoFrame() const { return frame_; }
 
@@ -130,7 +132,7 @@
       rtc::ArrayView<webrtc::VideoFrameBuffer::Type> types) override;
 
  protected:
-  ~WebRtcVideoFrameAdapter() override;
+  ~LegacyWebRtcVideoFrameAdapter() override;
 
   rtc::scoped_refptr<webrtc::VideoFrameBuffer> CreateFrameAdapter() const;
 
@@ -152,4 +154,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WEBRTC_WEBRTC_VIDEO_FRAME_ADAPTER_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WEBRTC_LEGACY_WEBRTC_VIDEO_FRAME_ADAPTER_H_
diff --git a/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter_test.cc b/third_party/blink/renderer/platform/webrtc/legacy_webrtc_video_frame_adapter_test.cc
similarity index 81%
rename from third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter_test.cc
rename to third_party/blink/renderer/platform/webrtc/legacy_webrtc_video_frame_adapter_test.cc
index 381d570..c747960 100644
--- a/third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter_test.cc
+++ b/third_party/blink/renderer/platform/webrtc/legacy_webrtc_video_frame_adapter_test.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 "third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.h"
+#include "third_party/blink/renderer/platform/webrtc/legacy_webrtc_video_frame_adapter.h"
 
 #include "base/strings/strcat.h"
 #include "base/test/scoped_feature_list.h"
@@ -21,23 +21,24 @@
 
 namespace blink {
 
-class WebRtcVideoFrameAdapterParamTest
+class LegacyWebRtcVideoFrameAdapterParamTest
     : public ::testing::TestWithParam<
           std::tuple<media::VideoFrame::StorageType, media::VideoPixelFormat>> {
  public:
-  WebRtcVideoFrameAdapterParamTest()
-      : resources_(new WebRtcVideoFrameAdapter::SharedResources(nullptr)) {}
+  LegacyWebRtcVideoFrameAdapterParamTest()
+      : resources_(
+            new LegacyWebRtcVideoFrameAdapter::SharedResources(nullptr)) {}
 
  protected:
-  scoped_refptr<WebRtcVideoFrameAdapter::SharedResources> resources_;
+  scoped_refptr<LegacyWebRtcVideoFrameAdapter::SharedResources> resources_;
 };
 
 namespace {
-std::vector<WebRtcVideoFrameAdapterParamTest::ParamType> TestParams() {
-  std::vector<WebRtcVideoFrameAdapterParamTest::ParamType> test_params;
+std::vector<LegacyWebRtcVideoFrameAdapterParamTest::ParamType> TestParams() {
+  std::vector<LegacyWebRtcVideoFrameAdapterParamTest::ParamType> test_params;
   // All formats for owned memory.
   for (media::VideoPixelFormat format :
-       WebRtcVideoFrameAdapter::AdaptableMappablePixelFormats()) {
+       LegacyWebRtcVideoFrameAdapter::AdaptableMappablePixelFormats()) {
     test_params.emplace_back(
         media::VideoFrame::StorageType::STORAGE_OWNED_MEMORY, format);
   }
@@ -48,7 +49,7 @@
 }
 }  // namespace
 
-TEST_P(WebRtcVideoFrameAdapterParamTest, WidthAndHeight) {
+TEST_P(LegacyWebRtcVideoFrameAdapterParamTest, WidthAndHeight) {
   const gfx::Size kCodedSize(1280, 960);
   const gfx::Rect kVisibleRect(0, 120, 1280, 720);
   const gfx::Size kNaturalSize(640, 360);
@@ -58,13 +59,13 @@
   scoped_refptr<media::VideoFrame> frame = CreateTestFrame(
       kCodedSize, kVisibleRect, kNaturalSize, storage_type, pixel_format);
   rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_adapter =
-      new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(std::move(frame),
-                                                         resources_);
+      new rtc::RefCountedObject<LegacyWebRtcVideoFrameAdapter>(std::move(frame),
+                                                               resources_);
   EXPECT_EQ(frame_adapter->width(), kNaturalSize.width());
   EXPECT_EQ(frame_adapter->height(), kNaturalSize.height());
 }
 
-TEST_P(WebRtcVideoFrameAdapterParamTest, ToI420) {
+TEST_P(LegacyWebRtcVideoFrameAdapterParamTest, ToI420) {
   const gfx::Size kCodedSize(1280, 960);
   const gfx::Rect kVisibleRect(0, 120, 1280, 720);
   const gfx::Size kNaturalSize(640, 360);
@@ -74,8 +75,8 @@
   scoped_refptr<media::VideoFrame> frame = CreateTestFrame(
       kCodedSize, kVisibleRect, kNaturalSize, storage_type, pixel_format);
   rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_adapter =
-      new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(std::move(frame),
-                                                         resources_);
+      new rtc::RefCountedObject<LegacyWebRtcVideoFrameAdapter>(std::move(frame),
+                                                               resources_);
 
   // The I420 frame should have the same size as the natural size.
   auto i420_frame = frame_adapter->ToI420();
@@ -84,8 +85,8 @@
 }
 
 INSTANTIATE_TEST_CASE_P(
-    WebRtcVideoFrameAdapterParamTest,
-    WebRtcVideoFrameAdapterParamTest,
+    LegacyWebRtcVideoFrameAdapterParamTest,
+    LegacyWebRtcVideoFrameAdapterParamTest,
     ::testing::ValuesIn(TestParams()),
     [](const auto& info) {
       return base::StrCat(
@@ -93,15 +94,15 @@
            media::VideoPixelFormatToString(std::get<1>(info.param))});
     });
 
-TEST(WebRtcVideoFrameAdapterTest, ToI420DownScaleGmb) {
+TEST(LegacyWebRtcVideoFrameAdapterTest, ToI420DownScaleGmb) {
   base::test::ScopedFeatureList scoped_feautre_list;
   scoped_feautre_list.InitAndDisableFeature(
       blink::features::kWebRtcLibvpxEncodeNV12);
   const gfx::Size kCodedSize(1280, 960);
   const gfx::Rect kVisibleRect(0, 120, 1280, 720);
   const gfx::Size kNaturalSize(640, 360);
-  scoped_refptr<WebRtcVideoFrameAdapter::SharedResources> resources =
-      new WebRtcVideoFrameAdapter::SharedResources(nullptr);
+  scoped_refptr<LegacyWebRtcVideoFrameAdapter::SharedResources> resources =
+      new LegacyWebRtcVideoFrameAdapter::SharedResources(nullptr);
   auto gmb_frame =
       CreateTestFrame(kCodedSize, kVisibleRect, kNaturalSize,
                       media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER);
@@ -109,8 +110,8 @@
   // The adapter should report width and height from the natural size for
   // VideoFrame backed by GpuMemoryBuffer.
   rtc::scoped_refptr<webrtc::VideoFrameBuffer> gmb_frame_adapter(
-      new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(std::move(gmb_frame),
-                                                         resources));
+      new rtc::RefCountedObject<LegacyWebRtcVideoFrameAdapter>(
+          std::move(gmb_frame), resources));
   EXPECT_EQ(gmb_frame_adapter->width(), kNaturalSize.width());
   EXPECT_EQ(gmb_frame_adapter->height(), kNaturalSize.height());
 
@@ -125,12 +126,12 @@
   EXPECT_EQ(get_i420_frame->height(), kNaturalSize.height());
 }
 
-TEST(WebRtcVideoFrameAdapterTest, ToI420ADownScale) {
+TEST(LegacyWebRtcVideoFrameAdapterTest, ToI420ADownScale) {
   const gfx::Size kCodedSize(1280, 960);
   const gfx::Rect kVisibleRect(0, 120, 1280, 720);
   const gfx::Size kNaturalSize(640, 360);
-  scoped_refptr<WebRtcVideoFrameAdapter::SharedResources> resources =
-      new WebRtcVideoFrameAdapter::SharedResources(nullptr);
+  scoped_refptr<LegacyWebRtcVideoFrameAdapter::SharedResources> resources =
+      new LegacyWebRtcVideoFrameAdapter::SharedResources(nullptr);
 
   // The adapter should report width and height from the natural size for
   // VideoFrame backed by owned memory.
@@ -139,7 +140,7 @@
                       media::VideoFrame::STORAGE_OWNED_MEMORY,
                       media::VideoPixelFormat::PIXEL_FORMAT_I420A);
   rtc::scoped_refptr<webrtc::VideoFrameBuffer> owned_memory_frame_adapter(
-      new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(
+      new rtc::RefCountedObject<LegacyWebRtcVideoFrameAdapter>(
           std::move(owned_memory_frame), resources));
   EXPECT_EQ(owned_memory_frame_adapter->width(), kNaturalSize.width());
   EXPECT_EQ(owned_memory_frame_adapter->height(), kNaturalSize.height());
@@ -152,7 +153,8 @@
   EXPECT_EQ(i420a_frame->height(), kNaturalSize.height());
 }
 
-TEST(WebRtcVideoFrameAdapterTest, Nv12WrapsGmbWhenNoScalingNeeededWithFeature) {
+TEST(LegacyWebRtcVideoFrameAdapterTest,
+     Nv12WrapsGmbWhenNoScalingNeeededWithFeature) {
   base::test::ScopedFeatureList scoped_feautre_list;
   scoped_feautre_list.InitAndEnableFeature(
       blink::features::kWebRtcLibvpxEncodeNV12);
@@ -160,8 +162,8 @@
   const gfx::Rect kVisibleRect(0, 120, 1280, 720);
   // Same size as visible rect so no scaling.
   const gfx::Size kNaturalSize = kVisibleRect.size();
-  scoped_refptr<WebRtcVideoFrameAdapter::SharedResources> resources =
-      new WebRtcVideoFrameAdapter::SharedResources(nullptr);
+  scoped_refptr<LegacyWebRtcVideoFrameAdapter::SharedResources> resources =
+      new LegacyWebRtcVideoFrameAdapter::SharedResources(nullptr);
 
   auto gmb_frame =
       CreateTestFrame(kCodedSize, kVisibleRect, kNaturalSize,
@@ -170,7 +172,8 @@
   // The adapter should report width and height from the natural size for
   // VideoFrame backed by GpuMemoryBuffer.
   rtc::scoped_refptr<webrtc::VideoFrameBuffer> gmb_frame_adapter(
-      new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(gmb_frame, resources));
+      new rtc::RefCountedObject<LegacyWebRtcVideoFrameAdapter>(gmb_frame,
+                                                               resources));
   EXPECT_EQ(gmb_frame_adapter->width(), kNaturalSize.width());
   EXPECT_EQ(gmb_frame_adapter->height(), kNaturalSize.height());
 
@@ -194,15 +197,15 @@
   EXPECT_EQ(i420_frame->height(), kNaturalSize.height());
 }
 
-TEST(WebRtcVideoFrameAdapterTest, Nv12ScalesGmbWithFeature) {
+TEST(LegacyWebRtcVideoFrameAdapterTest, Nv12ScalesGmbWithFeature) {
   base::test::ScopedFeatureList scoped_feautre_list;
   scoped_feautre_list.InitAndEnableFeature(
       blink::features::kWebRtcLibvpxEncodeNV12);
   const gfx::Size kCodedSize(1280, 960);
   const gfx::Rect kVisibleRect(0, 120, 1280, 720);
   const gfx::Size kNaturalSize(640, 360);
-  scoped_refptr<WebRtcVideoFrameAdapter::SharedResources> resources =
-      new WebRtcVideoFrameAdapter::SharedResources(nullptr);
+  scoped_refptr<LegacyWebRtcVideoFrameAdapter::SharedResources> resources =
+      new LegacyWebRtcVideoFrameAdapter::SharedResources(nullptr);
 
   auto gmb_frame =
       CreateTestFrame(kCodedSize, kVisibleRect, kNaturalSize,
@@ -211,7 +214,8 @@
   // The adapter should report width and height from the natural size for
   // VideoFrame backed by GpuMemoryBuffer.
   rtc::scoped_refptr<webrtc::VideoFrameBuffer> gmb_frame_adapter(
-      new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(gmb_frame, resources));
+      new rtc::RefCountedObject<LegacyWebRtcVideoFrameAdapter>(gmb_frame,
+                                                               resources));
   EXPECT_EQ(gmb_frame_adapter->width(), kNaturalSize.width());
   EXPECT_EQ(gmb_frame_adapter->height(), kNaturalSize.height());
 
@@ -235,12 +239,12 @@
   EXPECT_EQ(i420_frame->height(), kNaturalSize.height());
 }
 
-TEST(WebRtcVideoFrameAdapterTest, Nv12OwnedMemoryFrame) {
+TEST(LegacyWebRtcVideoFrameAdapterTest, Nv12OwnedMemoryFrame) {
   const gfx::Size kCodedSize(1280, 960);
   const gfx::Rect kVisibleRect(0, 120, 1280, 720);
   const gfx::Size kNaturalSize = kVisibleRect.size();
-  scoped_refptr<WebRtcVideoFrameAdapter::SharedResources> resources =
-      new WebRtcVideoFrameAdapter::SharedResources(nullptr);
+  scoped_refptr<LegacyWebRtcVideoFrameAdapter::SharedResources> resources =
+      new LegacyWebRtcVideoFrameAdapter::SharedResources(nullptr);
 
   // The adapter should report width and height from the natural size for
   // VideoFrame backed by owned memory.
@@ -249,7 +253,7 @@
                       media::VideoFrame::STORAGE_OWNED_MEMORY,
                       media::VideoPixelFormat::PIXEL_FORMAT_NV12);
   rtc::scoped_refptr<webrtc::VideoFrameBuffer> owned_memory_frame_adapter(
-      new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(
+      new rtc::RefCountedObject<LegacyWebRtcVideoFrameAdapter>(
           std::move(owned_memory_frame), resources));
   EXPECT_EQ(owned_memory_frame_adapter->width(), kNaturalSize.width());
   EXPECT_EQ(owned_memory_frame_adapter->height(), kNaturalSize.height());
@@ -264,12 +268,12 @@
   EXPECT_EQ(nv12_frame->height(), kVisibleRect.size().height());
 }
 
-TEST(WebRtcVideoFrameAdapterTest, Nv12ScaleOwnedMemoryFrame) {
+TEST(LegacyWebRtcVideoFrameAdapterTest, Nv12ScaleOwnedMemoryFrame) {
   const gfx::Size kCodedSize(1280, 960);
   const gfx::Rect kVisibleRect(0, 120, 1280, 720);
   const gfx::Size kNaturalSize(640, 360);
-  scoped_refptr<WebRtcVideoFrameAdapter::SharedResources> resources =
-      new WebRtcVideoFrameAdapter::SharedResources(nullptr);
+  scoped_refptr<LegacyWebRtcVideoFrameAdapter::SharedResources> resources =
+      new LegacyWebRtcVideoFrameAdapter::SharedResources(nullptr);
 
   // The adapter should report width and height from the natural size for
   // VideoFrame backed by owned memory.
@@ -278,7 +282,7 @@
                       media::VideoFrame::STORAGE_OWNED_MEMORY,
                       media::VideoPixelFormat::PIXEL_FORMAT_NV12);
   rtc::scoped_refptr<webrtc::VideoFrameBuffer> owned_memory_frame_adapter(
-      new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(
+      new rtc::RefCountedObject<LegacyWebRtcVideoFrameAdapter>(
           std::move(owned_memory_frame), resources));
   EXPECT_EQ(owned_memory_frame_adapter->width(), kNaturalSize.width());
   EXPECT_EQ(owned_memory_frame_adapter->height(), kNaturalSize.height());
@@ -293,7 +297,8 @@
   EXPECT_EQ(nv12_frame->height(), kNaturalSize.height());
 }
 
-TEST(WebRtcVideoFrameAdapterTest, TextureFrameIsBlackWithNoSharedResources) {
+TEST(LegacyWebRtcVideoFrameAdapterTest,
+     TextureFrameIsBlackWithNoSharedResources) {
   const gfx::Size kCodedSize(1280, 960);
   const gfx::Rect kVisibleRect(0, 120, 1280, 720);
   const gfx::Size kNaturalSize(640, 360);
@@ -304,7 +309,7 @@
       kCodedSize, kVisibleRect, kNaturalSize, media::VideoFrame::STORAGE_OPAQUE,
       media::VideoPixelFormat::PIXEL_FORMAT_NV12);
   rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_adapter(
-      new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(
+      new rtc::RefCountedObject<LegacyWebRtcVideoFrameAdapter>(
           std::move(owned_memory_frame), nullptr));
   EXPECT_EQ(frame_adapter->width(), kNaturalSize.width());
   EXPECT_EQ(frame_adapter->height(), kNaturalSize.height());
@@ -320,7 +325,8 @@
   EXPECT_EQ(0x80, i420_frame->DataV()[0]);
 }
 
-TEST(WebRtcVideoFrameAdapterTest, ConvertsTextureFrameWithSharedResources) {
+TEST(LegacyWebRtcVideoFrameAdapterTest,
+     ConvertsTextureFrameWithSharedResources) {
   const gfx::Size kCodedSize(1280, 960);
   const gfx::Rect kVisibleRect(0, 120, 1280, 720);
   const gfx::Size kNaturalSize(640, 360);
@@ -334,7 +340,7 @@
       kCodedSize, kVisibleRect, kNaturalSize, media::VideoFrame::STORAGE_OPAQUE,
       media::VideoPixelFormat::PIXEL_FORMAT_NV12);
   rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_adapter(
-      new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(
+      new rtc::RefCountedObject<LegacyWebRtcVideoFrameAdapter>(
           std::move(owned_memory_frame), resources));
   EXPECT_EQ(frame_adapter->width(), kNaturalSize.width());
   EXPECT_EQ(frame_adapter->height(), kNaturalSize.height());
diff --git a/third_party/blink/renderer/platform/webrtc/testing/mock_webrtc_video_frame_adapter_shared_resources.h b/third_party/blink/renderer/platform/webrtc/testing/mock_webrtc_video_frame_adapter_shared_resources.h
index cb1e9f3..d637106 100644
--- a/third_party/blink/renderer/platform/webrtc/testing/mock_webrtc_video_frame_adapter_shared_resources.h
+++ b/third_party/blink/renderer/platform/webrtc/testing/mock_webrtc_video_frame_adapter_shared_resources.h
@@ -5,15 +5,17 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WEBRTC_TESTING_MOCK_WEBRTC_VIDEO_FRAME_ADAPTER_SHARED_RESOURCES_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WEBRTC_TESTING_MOCK_WEBRTC_VIDEO_FRAME_ADAPTER_SHARED_RESOURCES_H_
 
-#include "third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.h"
+#include "third_party/blink/renderer/platform/webrtc/legacy_webrtc_video_frame_adapter.h"
 
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace blink {
 
-class MockSharedResources : public WebRtcVideoFrameAdapter::SharedResources {
+class MockSharedResources
+    : public LegacyWebRtcVideoFrameAdapter::SharedResources {
  public:
-  MockSharedResources() : WebRtcVideoFrameAdapter::SharedResources(nullptr) {}
+  MockSharedResources()
+      : LegacyWebRtcVideoFrameAdapter::SharedResources(nullptr) {}
 
   MOCK_METHOD(scoped_refptr<media::VideoFrame>,
               CreateFrame,
@@ -45,27 +47,28 @@
 
   void ExpectCreateFrameWithRealImplementation() {
     EXPECT_CALL(*this, CreateFrame)
-        .WillOnce(testing::Invoke(
-            [this](media::VideoPixelFormat format, const gfx::Size& coded_size,
-                   const gfx::Rect& visible_rect, const gfx::Size& natural_size,
-                   base::TimeDelta timestamp) {
-              return WebRtcVideoFrameAdapter::SharedResources::CreateFrame(
-                  format, coded_size, visible_rect, natural_size, timestamp);
-            }));
-  }
-
-  void ExpectCreateTemporaryFrameWithRealImplementation() {
-    EXPECT_CALL(*this, CreateTemporaryFrame)
         .WillOnce(testing::Invoke([this](media::VideoPixelFormat format,
                                          const gfx::Size& coded_size,
                                          const gfx::Rect& visible_rect,
                                          const gfx::Size& natural_size,
                                          base::TimeDelta timestamp) {
-          return WebRtcVideoFrameAdapter::SharedResources::CreateTemporaryFrame(
+          return LegacyWebRtcVideoFrameAdapter::SharedResources::CreateFrame(
               format, coded_size, visible_rect, natural_size, timestamp);
         }));
   }
 
+  void ExpectCreateTemporaryFrameWithRealImplementation() {
+    EXPECT_CALL(*this, CreateTemporaryFrame)
+        .WillOnce(testing::Invoke(
+            [this](media::VideoPixelFormat format, const gfx::Size& coded_size,
+                   const gfx::Rect& visible_rect, const gfx::Size& natural_size,
+                   base::TimeDelta timestamp) {
+              return LegacyWebRtcVideoFrameAdapter::SharedResources::
+                  CreateTemporaryFrame(format, coded_size, visible_rect,
+                                       natural_size, timestamp);
+            }));
+  }
+
  private:
   friend class base::RefCountedThreadSafe<MockSharedResources>;
 };
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests
index a3cee2a7..5bd03802 100644
--- a/third_party/blink/web_tests/SlowTests
+++ b/third_party/blink/web_tests/SlowTests
@@ -733,6 +733,7 @@
 crbug.com/1146221 [ Linux ] http/tests/devtools/sources/debugger-ui/debugger-inline-values.js [ Slow ]
 crbug.com/1182691 external/wpt/webcodecs/audio-encoder.any.html [ Slow ]
 crbug.com/1182691 external/wpt/webcodecs/video-encoder.any.html [ Slow ]
+crbug.com/1176474 wpt_internal/webcodecs/temporal_svc.any.html [ Slow ]
 
 # Composited scroll snap is not accelerated for testing.
 crbug.com/1186753 virtual/threaded-prefer-compositing/fast/scroll-snap/snaps-after-scrollbar-scrolling-arrow.html [ Slow ]
diff --git a/third_party/blink/web_tests/W3CImportExpectations b/third_party/blink/web_tests/W3CImportExpectations
index 4c3538a..40656cb 100644
--- a/third_party/blink/web_tests/W3CImportExpectations
+++ b/third_party/blink/web_tests/W3CImportExpectations
@@ -20,12 +20,10 @@
 external/wpt/WebIDL/readme.txt [ Skip ]
 external/wpt/WebIDL/testable_assertions.txt [ Skip ]
 external/wpt/WebIDL/valid [ Skip ]
-external/wpt/accname [ Skip ]
 external/wpt/annotation-model [ Skip ]
 external/wpt/annotation-protocol [ Skip ]
 external/wpt/annotation-vocab [ Skip ]
 external/wpt/conformance-checkers [ Skip ]
-external/wpt/core-aam [ Skip ]
 external/wpt/css/.htaccess [ Skip ]
 external/wpt/css/CSS1 [ Skip ]
 external/wpt/css/CSS2/LICENSE-BSD [ Skip ]
@@ -106,8 +104,6 @@
 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/ui3 [ Skip ]
 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/values3 [ Skip ]
 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/will-change [ Skip ]
-external/wpt/dpub-aam [ Skip ]
-external/wpt/dpub-aria [ Skip ]
 external/wpt/html-longdesc [ Skip ]
 external/wpt/infrastructure/metadata/infrastructure/browsers/firefox [ Skip ]
 external/wpt/infrastructure/browsers/firefox [ Skip ]
@@ -115,9 +111,7 @@
 external/wpt/old-tests [ Skip ]
 external/wpt/proximity [ Skip ]
 external/wpt/resources/test [ Skip ]
-external/wpt/svg-aam [ Skip ]
 external/wpt/svg/import [ Skip ]
-external/wpt/wai-aria [ Skip ]
 external/wpt/webgl [ Skip ]
 
 # Exceptions for individual files that fail due to bugs in the
@@ -396,6 +390,17 @@
 external/wpt/feature-policy/reporting/vr-report-only.https.html [ Skip ]
 external/wpt/feature-policy/reporting/vr-report-only.https.html.headers [ Skip ]
 
+# Manual tests related to accessibility for which we have parallel coverage,
+# e.g. porting them to content browser tests.
+external/wpt/accname [ Skip ]
+
+# Other manual tests related to accessibility.
+external/wpt/core-aam [ Skip ]
+external/wpt/dpub-aam [ Skip ]
+external/wpt/dpub-aria [ Skip ]
+external/wpt/svg-aam [ Skip ]
+external/wpt/wai-aria [ Skip ]
+
 # Manual tests for CSS Paged Media.
 external/wpt/css/css-page/forced-page-breaks-002.xht [ Skip ]
 external/wpt/css/css-page/page-background-000.xht [ Skip ]
diff --git a/third_party/blink/web_tests/external/wpt/cors/preflight-cache-expected.txt b/third_party/blink/web_tests/external/wpt/cors/preflight-cache-expected.txt
deleted file mode 100644
index d82bf39..0000000
--- a/third_party/blink/web_tests/external/wpt/cors/preflight-cache-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-This is a testharness.js-based test.
-PASS Test preflight
-PASS preflight for x-print should be cached
-FAIL age = blank, should be cached assert_equals: did preflight expected "0" but got "1"
-PASS age = 0, should not be cached
-PASS age = -1, should not be cached
-PASS preflight first request, second from cache, wait, third should preflight again
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-024-ref.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-024-ref.html
new file mode 100644
index 0000000..9ee03ee
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-024-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reference: ::marker pseudo elements styled with 'content' property</title>
+<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+div {
+  white-space: pre;
+  font: 25px/1 Ahem;
+  text-emphasis-style: circle;
+  -webkit-text-emphasis-style: circle;
+}
+</style>
+<div>XÉ  pÉ
+ Ép pp
+ XÉ pÉ
+ Ép pp
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-024.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-024.html
new file mode 100644
index 0000000..8a6ab0b5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-024.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Test: ::marker pseudo elements styled with 'content' property</title>
+<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
+<link rel="match" href="marker-content-024-ref.html">
+<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo">
+<link rel="help" href="https://drafts.csswg.org/css-multicol/">
+<link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#emphasis-marks">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/interaction.html#contenteditable">
+<meta name="assert" content="Checks ::marker in a multi-column can have emphasis marks and doesn't crash when made editable.">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ol {
+  margin: 0;
+  padding-left: 25px;
+  font: 25px/1 Ahem;
+}
+li {
+  width: 150px;
+  column-count: 2;
+  column-gap: 0;
+  text-emphasis-style: circle;
+  -webkit-text-emphasis-style: circle;
+}
+li + li {
+  list-style-position: inside;
+}
+::marker {
+  content: 'X';
+}
+</style>
+<ol>
+  <li>É<br>Ép<br>pÉ<br>pp</li>
+  <li>É<br>Ép<br>pÉ<br>pp</li>
+</ol>
+<script>
+// Force layout
+document.body.offsetLeft;
+// Enabling editability shouldn't crash
+document.querySelector("ol").contentEditable = "true";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-insertable-streams/DIR_METADATA b/third_party/blink/web_tests/external/wpt/mediacapture-insertable-streams/DIR_METADATA
new file mode 100644
index 0000000..563fa67
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-insertable-streams/DIR_METADATA
@@ -0,0 +1,6 @@
+monorail {
+  component: "Blink>MediaStream"
+}
+wpt {
+  notify: YES
+}
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-insertable-streams/MediaStreamTrackGenerator-audio.https.html b/third_party/blink/web_tests/external/wpt/mediacapture-insertable-streams/MediaStreamTrackGenerator-audio.https.html
new file mode 100644
index 0000000..8fdb353
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-insertable-streams/MediaStreamTrackGenerator-audio.https.html
@@ -0,0 +1,120 @@
+<!doctype html>
+<html>
+
+<head>
+  <title>MediaStreamTrackGenerator</title>
+  <link rel="help" href="https://w3c.github.io/mediacapture-insertable-streams">
+</head>
+
+<body>
+  <p class="instructions">When prompted, use the accept button to give permission to use your audio and video devices.</p>
+  <h1 class="instructions">Description</h1>
+  <p class="instructions">This test checks that generating audio MediaStreamTracks works as expected.</p>
+  <audio id="audioElement" autoplay=true></audio>
+  <script src=/resources/testharness.js></script>
+  <script src=/resources/testharnessreport.js></script>
+  <script>
+
+    function makeAudioFrame(timestamp) {
+      const sampleRate = 3000;
+      const buffer = new AudioBuffer({
+        length: sampleRate / 10, // 100ms
+        numberOfChannels: 1,
+        sampleRate: sampleRate
+      });
+      // Generate a simple sin wave, so we have something.
+      const array = buffer.getChannelData(0);
+      const hz = 100; // sound frequency
+      for (let i = 0; i < array.length; i++) {
+        const t = (i / sampleRate) * hz * (Math.PI * 2);
+        array[i] = Math.sin(t);
+      }
+
+      return new AudioFrame({
+        timestamp: timestamp,
+        buffer: buffer
+      });
+    }
+
+    promise_test(async t => {
+      const generator = new MediaStreamTrackGenerator("audio");
+
+      const writer = generator.writable.getWriter();
+      await writer.write(makeAudioFrame(1));
+
+      assert_equals(generator.kind, "audio");
+      assert_equals(generator.readyState, "live");
+
+      t.add_cleanup(() => generator.stop());
+    }, "Tests that creating a Audio MediaStreamTrackGenerator works as expected");
+
+    promise_test(async t => {
+      const capturedStream = await navigator.mediaDevices.getUserMedia({ audio: true });
+      assert_equals(capturedStream.getAudioTracks().length, 1);
+      const upstreamTrack = capturedStream.getAudioTracks()[0];
+      t.add_cleanup(() => upstreamTrack.stop());
+
+      const generator = new MediaStreamTrackGenerator({ signalTarget: upstreamTrack, kind: "audio" });
+      t.add_cleanup(() => generator.stop());
+
+      const writer = generator.writable.getWriter();
+      const frame = makeAudioFrame(1);
+      await writer.write(frame);
+
+      assert_equals(generator.kind, "audio");
+      assert_equals(generator.readyState, "live");
+    }, "Tests that creating an Audio MediaStreamTrackGenerator with a signal target works as expected");
+
+    promise_test(async t => {
+      assert_throws_js(TypeError, () => { new MediaStreamTrackGenerator({ kind: "invalid kind" }) });
+    }, "Creating Generator with an invalid kind throws");
+
+    promise_test(async t => {
+      const capturedStream = await navigator.mediaDevices.getUserMedia({ audio: true });
+      assert_equals(capturedStream.getAudioTracks().length, 1);
+      const upstreamTrack = capturedStream.getAudioTracks()[0];
+      t.add_cleanup(() => upstreamTrack.stop());
+
+      assert_throws_js(TypeError, () => { new MediaStreamTrackGenerator({ signalTarget: upstreamTrack }) });
+    }, "Creating Generator with a missing kind throws");
+
+    promise_test(async t => {
+      const capturedStream = await navigator.mediaDevices.getUserMedia({ audio: true });
+      assert_equals(capturedStream.getAudioTracks().length, 1);
+      const upstreamTrack = capturedStream.getAudioTracks()[0];
+      t.add_cleanup(() => upstreamTrack.stop());
+
+      assert_throws_js(TypeError, () => { new MediaStreamTrackGenerator({ signalTarget: upstreamTrack, kind: "video" }) });
+    }, "Creating Generator with mismatched kinds throws");
+
+    promise_test(async t => {
+      assert_throws_js(TypeError, () => { new MediaStreamTrackGenerator({ signalTarget: "IamNotATrack" }) });
+    }, "Creating Generator with invalid signalTarget throws");
+
+    promise_test(async t => {
+      const generator = new MediaStreamTrackGenerator({ kind: "video" });
+      t.add_cleanup(() => generator.stop());
+
+      const writer = generator.writable.getWriter();
+      const frame = makeAudioFrame(1);
+
+      writer.write(frame).then(t.step_func(() => assert_unreached("Write should reject")), t.step_func(f => assert_true(f instanceof TypeError, "write rejects with a TypeError")));
+    }, "Mismatched frame and generator kind throws on write.");
+
+    promise_test(async t => {
+      const generator = new MediaStreamTrackGenerator("audio");
+      t.add_cleanup(() => generator.stop());
+
+      const audioElement = document.getElementById("audioElement");
+      audioElement.srcObject = new MediaStream([generator]);
+      await audioElement.play();
+
+      const writer = generator.writable.getWriter();
+      await writer.write(makeAudioFrame(1));
+
+      // Wait for audio playout to actually happen.
+      await t.step_wait(() => audioElement.currentTime > 0, "audioElement played out generated track");
+    }, "Tests that audio actually flows to a connected audio element");
+  </script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-insertable-streams/MediaStreamTrackGenerator-video.https.html b/third_party/blink/web_tests/external/wpt/mediacapture-insertable-streams/MediaStreamTrackGenerator-video.https.html
index e1d1565d..a1289b60 100644
--- a/third_party/blink/web_tests/external/wpt/mediacapture-insertable-streams/MediaStreamTrackGenerator-video.https.html
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-insertable-streams/MediaStreamTrackGenerator-video.https.html
@@ -6,42 +6,152 @@
 <script src="/resources/testharnessreport.js"></script>
 </head>
 <body>
-<script>
+  <p class="instructions">When prompted, use the accept button to give permission to use your audio and video devices.</p>
+  <h1 class="instructions">Description</h1>
+  <p class="instructions">This test checks that generating video MediaStreamTracks works as expected.</p>
+  <script>
 
-async function getVideoFrame() {
-  const stream = await navigator.mediaDevices.getUserMedia({video: true});
-  const input_track = stream.getTracks()[0];
-  const processor = new MediaStreamTrackProcessor(input_track);
-  const reader = processor.readable.getReader();
-  const result = await reader.read();
-  input_track.stop();
-  return result.value;
-}
+    const pixelColour = [50, 100, 150, 255];
+    function makeVideoFrame(timestamp) {
+      const height = 240;
+      const width = 320;
+      const canvas = new OffscreenCanvas(width, height);
 
-promise_test(async t => {
-  const videoFrame = await getVideoFrame();
-  const originalWidth = videoFrame.displayWidth;
-  const originalHeight = videoFrame.displayHeight;
-  const originalTimestamp = videoFrame.timestamp;
-  const generator = new MediaStreamTrackGenerator({kind: 'video'});
+      const ctx = canvas.getContext('2d', { alpha: false });
+      ctx.fillStyle = `rgba(${pixelColour[0]}, ${pixelColour[1]}, ${pixelColour[2]}, ${pixelColour[3]})`;
+      ctx.fillRect(0, 0, width, height);
 
-  // Use a MediaStreamTrackProcessor as a sink for |generator| to verify
-  // that |processor| actually forwards the frames written to its writable
-  // field.
-  const processor = new MediaStreamTrackProcessor(generator);
-  const reader = processor.readable.getReader();
-  const readerPromise = new Promise(async resolve => {
-    const result = await reader.read();
-    assert_equals(result.value.displayWidth, originalWidth);
-    assert_equals(result.value.displayHeight, originalHeight);
-    assert_equals(result.value.timestamp, originalTimestamp);
-    resolve();
-  });
+      return new VideoFrame(canvas.transferToImageBitmap(), { timestamp });
+    }
 
-  generator.writable.getWriter().write(videoFrame);
-  return readerPromise;
-}, 'MediaStreamTrackGenerator forwards frames to sink');
+    async function getVideoFrame() {
+      const stream = await navigator.mediaDevices.getUserMedia({video: true});
+      const input_track = stream.getTracks()[0];
+      const processor = new MediaStreamTrackProcessor(input_track);
+      const reader = processor.readable.getReader();
+      const result = await reader.read();
+      input_track.stop();
+      return result.value;
+    }
 
-</script>
+    function assertPixel(t, bytes, expected) {
+      for (let i = 0; i < bytes.length; i++) {
+        t.step(() => {
+          assert_less_than(bytes[i], expected[i] + 2, "Mismatched pixel");
+          assert_greater_than(bytes[i], expected[i] - 2, "Mismatched pixel");
+        });
+      }
+    }
+
+    promise_test(async t => {
+      const videoFrame = await getVideoFrame();
+      const originalWidth = videoFrame.displayWidth;
+      const originalHeight = videoFrame.displayHeight;
+      const originalTimestamp = videoFrame.timestamp;
+      const generator = new MediaStreamTrackGenerator({kind: 'video'});
+      t.add_cleanup(() => generator.stop());
+
+      // Use a MediaStreamTrackProcessor as a sink for |generator| to verify
+      // that |processor| actually forwards the frames written to its writable
+      // field.
+      const processor = new MediaStreamTrackProcessor(generator);
+      const reader = processor.readable.getReader();
+      const readerPromise = new Promise(async resolve => {
+        const result = await reader.read();
+        assert_equals(result.value.displayWidth, originalWidth);
+        assert_equals(result.value.displayHeight, originalHeight);
+        assert_equals(result.value.timestamp, originalTimestamp);
+        resolve();
+      });
+
+      generator.writable.getWriter().write(videoFrame);
+
+      return readerPromise;
+    }, 'Tests that MediaStreamTrackGenerator forwards frames to sink');
+
+    promise_test(async t => {
+      const videoFrame = makeVideoFrame(1);
+      const originalWidth = videoFrame.displayWidth;
+      const originalHeight = videoFrame.displayHeight;
+      const originalTimestamp = videoFrame.timestamp;
+      const generator = new MediaStreamTrackGenerator({kind: 'video'});
+      t.add_cleanup(() => generator.stop());
+
+      const video = document.createElement("video");
+      video.autoplay = true;
+      video.width = 320;
+      video.height = 240;
+      video.srcObject = new MediaStream([generator]);
+      video.play();
+
+      // Allow async setup of the track generator and stream.
+      await new Promise(r => t.step_timeout(r, 1));
+
+      await generator.writable.getWriter().write(videoFrame);
+
+      await t.step_wait(() => video.currentTime > 0, "video has played");
+
+
+      const canvas = document.createElement("canvas");
+      canvas.width = originalWidth;
+      canvas.height = originalHeight;
+      const context = canvas.getContext('2d');
+      context.drawImage(video, 0, 0);
+      // Pick a pixel in the centre of the video and check that it has the colour of the frame provided.
+      const pixel = context.getImageData(videoFrame.displayWidth/2, videoFrame.displayHeight/2, 1, 1);
+      assertPixel(t, pixel.data, pixelColour);
+    }, 'Tests that frames are actually rendered correctly in a stream used for a video element.');
+
+
+    promise_test(async t => {
+      const generator = new MediaStreamTrackGenerator("video");
+      t.add_cleanup(() => generator.stop());
+
+      const writer = generator.writable.getWriter();
+      const frame = makeVideoFrame(1);
+      await writer.write(frame);
+
+      assert_equals(generator.kind, "video");
+      assert_equals(generator.readyState, "live");
+    }, "Tests that creating a Video MediaStreamTrackGenerator works as expected");
+
+    promise_test(async t => {
+      const generator = new MediaStreamTrackGenerator("video");
+      t.add_cleanup(() => generator.stop());
+
+      const writer = generator.writable.getWriter();
+      const frame = makeVideoFrame(1);
+      await writer.write(frame);
+
+      assert_throws_dom("InvalidStateError", () => frame.clone(), "VideoFrame wasn't destroyed on write.");
+    }, "Tests that VideoFrames are destroyed on write.");
+
+    promise_test(async t => {
+      const capturedStream = await navigator.mediaDevices.getUserMedia({ video: true });
+      assert_equals(capturedStream.getVideoTracks().length, 1);
+      const upstreamTrack = capturedStream.getVideoTracks()[0];
+      t.add_cleanup(() => upstreamTrack.stop());
+
+      const generator = new MediaStreamTrackGenerator({ signalTarget: upstreamTrack, kind: "video" });
+      t.add_cleanup(() => generator.stop());
+
+      const writer = generator.writable.getWriter();
+      const frame = makeVideoFrame(1);
+      await writer.write(frame);
+
+      assert_equals(generator.kind, "video");
+      assert_equals(generator.readyState, "live");
+    }, "Tests that creating a Video MediaStreamTrackGenerator with a signal target works as expected");
+
+
+    promise_test(async t => {
+      const generator = new MediaStreamTrackGenerator("audio");
+      t.add_cleanup(() => generator.stop());
+
+      const writer = generator.writable.getWriter();
+      const frame = makeVideoFrame(1);
+      assert_throws_js(TypeError, writer.write(frame));
+    }, "Mismatched frame and generator kind throws on write.");
+  </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-insertable-streams/MediaStreamTrackProcessor-audio.https.html b/third_party/blink/web_tests/external/wpt/mediacapture-insertable-streams/MediaStreamTrackProcessor-audio.https.html
new file mode 100644
index 0000000..8487f7d2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-insertable-streams/MediaStreamTrackProcessor-audio.https.html
@@ -0,0 +1,43 @@
+<!doctype html>
+<html>
+
+<head>
+  <title>MediaStreamTrackProcessor</title>
+  <link rel="help" href="https://w3c.github.io/mediacapture-insertable-streams">
+</head>
+
+<body>
+  <p class="instructions">When prompted, use the accept button to give permission to use your audio and video devices.</p>
+  <h1 class="instructions">Description</h1>
+  <p class="instructions">This test checks that processing captured audio MediaStreamTracks works as expected.</p>
+  <script src=/resources/testharness.js></script>
+  <script src=/resources/testharnessreport.js></script>
+  <script>
+
+    promise_test(async t => {
+      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
+      assert_equals(stream.getAudioTracks().length, 1);
+      const audioTrack = stream.getAudioTracks()[0];
+
+      return new Promise((resolve, reject) => {
+        const writableStream = new WritableStream({
+          write(audioFrame) {
+            assert_true(audioFrame instanceof AudioFrame);
+            assert_not_equals(audioFrame.timestamp, null);
+            resolve();
+          },
+          close() {
+            assert_unreached("Closed");
+          },
+          abort(err) {
+            assert_unreached("Sink error:" + err);
+          }
+        });
+        const audioTrackProcessor = new MediaStreamTrackProcessor(audioTrack);
+        audioTrackProcessor.readable.pipeTo(writableStream);
+      });
+    }, "Tests that creating an Audio MediaStreamTrackProcessor works as expected");
+  </script>
+</body>
+
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/CodingConventions.md b/third_party/blink/web_tests/external/wpt/resource-timing/CodingConventions.md
index e8cb33a..39b8d13 100644
--- a/third_party/blink/web_tests/external/wpt/resource-timing/CodingConventions.md
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/CodingConventions.md
@@ -26,6 +26,12 @@
 *   Consistent use of anonymous functions
     *   prefer
         ```
+        const func1 = param1 => {
+          body();
+        }
+        const func2 = (param1, param2) => {
+          body();
+        }
         fn(param => {
             body();
         });
@@ -34,6 +40,12 @@
         over
 
         ```
+        function func1(param1) {
+          body();
+        }
+        function func2(param1, param2) {
+          body();
+        }
         fn(function(param) {
             body();
         });
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/cross-origin-status-codes.html b/third_party/blink/web_tests/external/wpt/resource-timing/cross-origin-status-codes.html
index 512e437..197a7663 100644
--- a/third_party/blink/web_tests/external/wpt/resource-timing/cross-origin-status-codes.html
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/cross-origin-status-codes.html
@@ -19,7 +19,7 @@
 <script id="script_502"></script>
 <script>
 
-function listenForPerformanceEntries(num_expected) {
+const listenForPerformanceEntries = num_expected => {
   return new Promise(resolve => {
     let results = [];
     new PerformanceObserver(entryList => {
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/entry-attributes.html b/third_party/blink/web_tests/external/wpt/resource-timing/entry-attributes.html
index 5f330bb..9715626 100644
--- a/third_party/blink/web_tests/external/wpt/resource-timing/entry-attributes.html
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/entry-attributes.html
@@ -10,7 +10,7 @@
 
 // Returns a promise that settles once the given path has been fetched as an
 // image resource.
-function load_image(path) {
+const load_image = path => {
   return new Promise(resolve => {
     const img = new Image();
     img.onload = img.onerror = resolve;
@@ -20,7 +20,7 @@
 
 // Returns a promise that settles once the given path has been fetched as a
 // font resource.
-function load_font(path) {
+const load_font = path => {
   document.getElementById('forFonts').innerHTML = `
     <style>
     @font-face {
@@ -33,7 +33,7 @@
   return document.fonts.ready;
 }
 
-function assert_ordered(entry, attributes) {
+const assert_ordered = (entry, attributes) => {
   let before = attributes[0];
   attributes.slice(1).forEach(after => {
     assert_greater_than_equal(entry[after], entry[before],
@@ -42,27 +42,27 @@
   });
 }
 
-function assert_zeroed(entry, attributes) {
+const assert_zeroed = (entry, attributes) => {
   attributes.forEach(attribute => {
     assert_equals(entry[attribute], 0, `${attribute} should be 0`);
   });
 }
 
-function assert_not_negative(entry, attributes) {
+const assert_not_negative = (entry, attributes) => {
   attributes.forEach(attribute => {
     assert_greater_than_equal(entry[attribute], 0,
       `${attribute} should be greater than or equal to 0`);
   });
 }
 
-function assert_positive(entry, attributes) {
+const assert_positive = (entry, attributes) => {
   attributes.forEach(attribute => {
     assert_greater_than(entry[attribute], 0,
       `${attribute} should be greater than 0`);
   });
 }
 
-function assert_http_resource(entry) {
+const assert_http_resource = entry => {
   assert_ordered(entry, [
     "fetchStart",
     "domainLookupStart",
@@ -93,7 +93,7 @@
   ]);
 }
 
-function assert_same_origin_redirected_resource(entry) {
+const assert_same_origin_redirected_resource = entry => {
   assert_positive(entry, [
     "redirectStart",
   ]);
@@ -113,7 +113,7 @@
 
 // Given a resource-loader and a PerformanceResourceTiming validator, loads a
 // resource and validates the resulting entry.
-function attribute_test(load_resource, validate, test_label) {
+const attribute_test = (load_resource, validate, test_label) => {
   promise_test(
     async () => {
       // Clear out everything that isn't the one ResourceTiming entry under test.
diff --git a/third_party/blink/web_tests/external/wpt/urlpattern/resources/urlpatterntestdata.json b/third_party/blink/web_tests/external/wpt/urlpattern/resources/urlpatterntestdata.json
index ae9405e..61a228e 100644
--- a/third_party/blink/web_tests/external/wpt/urlpattern/resources/urlpatterntestdata.json
+++ b/third_party/blink/web_tests/external/wpt/urlpattern/resources/urlpatterntestdata.json
@@ -2,7 +2,7 @@
   {
     "pattern": { "pathname": "/foo/bar" },
     "input": { "pathname": "/foo/bar" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/bar" },
       "pathname": { "input": "/foo/bar", "groups": {} }
     }
@@ -10,22 +10,22 @@
   {
     "pattern": { "pathname": "/foo/bar" },
     "input": { "pathname": "/foo/ba" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/bar" },
     "input": { "pathname": "/foo/bar/" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/bar" },
     "input": { "pathname": "/foo/bar/baz" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/bar" },
     "input": "https://example.com/foo/bar",
-    "expected": {
+    "expected_match": {
       "input": "https://example.com/foo/bar",
       "hostname": { "input": "example.com", "groups": { "0": "example.com" } },
       "pathname": { "input": "/foo/bar", "groups": {} },
@@ -35,12 +35,12 @@
   {
     "pattern": { "pathname": "/foo/bar" },
     "input": "https://example.com/foo/bar/baz",
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/bar" },
     "input": { "hostname": "example.com", "pathname": "/foo/bar" },
-    "expected": {
+    "expected_match": {
       "input": { "hostname": "example.com", "pathname": "/foo/bar" },
       "hostname": { "input": "example.com", "groups": { "0": "example.com" } },
       "pathname": { "input": "/foo/bar", "groups": {} }
@@ -49,12 +49,12 @@
   {
     "pattern": { "pathname": "/foo/bar" },
     "input": { "hostname": "example.com", "pathname": "/foo/bar/baz" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/bar" },
     "input": { "pathname": "/foo/bar", "baseURL": "https://example.com" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/bar", "baseURL": "https://example.com" },
       "hostname": { "input": "example.com", "groups": { "0": "example.com" } },
       "pathname": { "input": "/foo/bar", "groups": {} },
@@ -64,26 +64,26 @@
   {
     "pattern": { "pathname": "/foo/bar" },
     "input": { "pathname": "/foo/bar/baz", "baseURL": "https://example.com" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/bar",
                  "baseURL": "https://example.com?query#hash" },
     "input": { "pathname": "/foo/bar" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/bar",
                  "baseURL": "https://example.com?query#hash" },
     "input": { "hostname": "example.com", "pathname": "/foo/bar" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/bar",
                  "baseURL": "https://example.com?query#hash" },
     "input": { "protocol": "https", "hostname": "example.com",
                "pathname": "/foo/bar" },
-    "expected": {
+    "expected_match": {
       "input": { "protocol": "https", "hostname": "example.com",
                  "pathname": "/foo/bar" },
       "exactly_empty_components": [ "username", "password", "port" ],
@@ -97,7 +97,7 @@
                  "baseURL": "https://example.com?query#hash" },
     "input": { "protocol": "https", "hostname": "example.com",
                "pathname": "/foo/bar/baz" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/bar",
@@ -105,7 +105,7 @@
     "input": { "protocol": "https", "hostname": "example.com",
                "pathname": "/foo/bar", "search": "otherquery",
                "hash": "otherhash" },
-    "expected": {
+    "expected_match": {
       "input": { "protocol": "https", "hostname": "example.com",
                  "pathname": "/foo/bar", "search": "otherquery",
                  "hash": "otherhash" },
@@ -121,7 +121,7 @@
     "pattern": { "pathname": "/foo/bar",
                  "baseURL": "https://example.com?query#hash" },
     "input": "https://example.com/foo/bar",
-    "expected": {
+    "expected_match": {
       "input": "https://example.com/foo/bar",
       "exactly_empty_components": [ "username", "password", "port" ],
       "hostname": { "input": "example.com", "groups": {} },
@@ -133,7 +133,7 @@
     "pattern": { "pathname": "/foo/bar",
                  "baseURL": "https://example.com?query#hash" },
     "input": "https://example.com/foo/bar?otherquery#otherhash",
-    "expected": {
+    "expected_match": {
       "input": "https://example.com/foo/bar?otherquery#otherhash",
       "exactly_empty_components": [ "username", "password", "port" ],
       "hash": { "input": "otherhash", "groups": { "0": "otherhash" } },
@@ -147,25 +147,25 @@
     "pattern": { "pathname": "/foo/bar",
                  "baseURL": "https://example.com?query#hash" },
     "input": "https://example.com/foo/bar/baz",
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/bar",
                  "baseURL": "https://example.com?query#hash" },
     "input": "https://other.com/foo/bar",
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/bar",
                  "baseURL": "https://example.com?query#hash" },
     "input": "http://other.com/foo/bar",
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/bar",
                  "baseURL": "https://example.com?query#hash" },
     "input": { "pathname": "/foo/bar", "baseURL": "https://example.com" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/bar", "baseURL": "https://example.com" },
       "exactly_empty_components": [ "username", "password", "port" ],
       "hostname": { "input": "example.com", "groups": {} },
@@ -177,24 +177,24 @@
     "pattern": { "pathname": "/foo/bar",
                  "baseURL": "https://example.com?query#hash" },
     "input": { "pathname": "/foo/bar/baz", "baseURL": "https://example.com" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/bar",
                  "baseURL": "https://example.com?query#hash" },
     "input": { "pathname": "/foo/bar", "baseURL": "https://other.com" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/bar",
                  "baseURL": "https://example.com?query#hash" },
     "input": { "pathname": "/foo/bar", "baseURL": "http://example.com" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/:bar" },
     "input": { "pathname": "/foo/bar" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/bar" },
       "pathname": { "input": "/foo/bar", "groups": { "bar": "bar" } }
     }
@@ -202,7 +202,7 @@
   {
     "pattern": { "pathname": "/foo/:bar" },
     "input": { "pathname": "/foo/index.html" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/index.html" },
       "pathname": { "input": "/foo/index.html", "groups": { "bar": "index.html" } }
     }
@@ -210,17 +210,20 @@
   {
     "pattern": { "pathname": "/foo/:bar" },
     "input": { "pathname": "/foo/bar/" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/:bar" },
     "input": { "pathname": "/foo/" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/(.*)" },
     "input": { "pathname": "/foo/bar" },
-    "expected": {
+    "expected_obj": {
+      "pathname": "/foo/*"
+    },
+    "expected_match": {
       "input": { "pathname": "/foo/bar" },
       "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } }
     }
@@ -228,7 +231,7 @@
   {
     "pattern": { "pathname": "/foo/*" },
     "input": { "pathname": "/foo/bar" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/bar" },
       "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } }
     }
@@ -236,7 +239,10 @@
   {
     "pattern": { "pathname": "/foo/(.*)" },
     "input": { "pathname": "/foo/bar/baz" },
-    "expected": {
+    "expected_obj": {
+      "pathname": "/foo/*"
+    },
+    "expected_match": {
       "input": { "pathname": "/foo/bar/baz" },
       "pathname": { "input": "/foo/bar/baz", "groups": { "0": "bar/baz" } }
     }
@@ -244,7 +250,7 @@
   {
     "pattern": { "pathname": "/foo/*" },
     "input": { "pathname": "/foo/bar/baz" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/bar/baz" },
       "pathname": { "input": "/foo/bar/baz", "groups": { "0": "bar/baz" } }
     }
@@ -252,7 +258,10 @@
   {
     "pattern": { "pathname": "/foo/(.*)" },
     "input": { "pathname": "/foo/" },
-    "expected": {
+    "expected_obj": {
+      "pathname": "/foo/*"
+    },
+    "expected_match": {
       "input": { "pathname": "/foo/" },
       "pathname": { "input": "/foo/", "groups": { "0": "" } }
     }
@@ -260,7 +269,7 @@
   {
     "pattern": { "pathname": "/foo/*" },
     "input": { "pathname": "/foo/" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/" },
       "pathname": { "input": "/foo/", "groups": { "0": "" } }
     }
@@ -268,17 +277,20 @@
   {
     "pattern": { "pathname": "/foo/(.*)" },
     "input": { "pathname": "/foo" },
-    "expected": null
+    "expected_obj": {
+      "pathname": "/foo/*"
+    },
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/*" },
     "input": { "pathname": "/foo" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/:bar(.*)" },
     "input": { "pathname": "/foo/bar" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/bar" },
       "pathname": { "input": "/foo/bar", "groups": { "bar": "bar" } }
     }
@@ -286,7 +298,7 @@
   {
     "pattern": { "pathname": "/foo/:bar(.*)" },
     "input": { "pathname": "/foo/bar/baz" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/bar/baz" },
       "pathname": { "input": "/foo/bar/baz", "groups": { "bar": "bar/baz" } }
     }
@@ -294,7 +306,7 @@
   {
     "pattern": { "pathname": "/foo/:bar(.*)" },
     "input": { "pathname": "/foo/" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/" },
       "pathname": { "input": "/foo/", "groups": { "bar": "" } }
     }
@@ -302,12 +314,12 @@
   {
     "pattern": { "pathname": "/foo/:bar(.*)" },
     "input": { "pathname": "/foo" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/:bar?" },
     "input": { "pathname": "/foo/bar" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/bar" },
       "pathname": { "input": "/foo/bar", "groups": { "bar": "bar" } }
     }
@@ -315,7 +327,7 @@
   {
     "pattern": { "pathname": "/foo/:bar?" },
     "input": { "pathname": "/foo" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo" },
       "pathname": { "input": "/foo", "groups": { "bar": "" } }
     }
@@ -323,22 +335,22 @@
   {
     "pattern": { "pathname": "/foo/:bar?" },
     "input": { "pathname": "/foo/" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/:bar?" },
     "input": { "pathname": "/foobar" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/:bar?" },
     "input": { "pathname": "/foo/bar/baz" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/:bar+" },
     "input": { "pathname": "/foo/bar" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/bar" },
       "pathname": { "input": "/foo/bar", "groups": { "bar": "bar" } }
     }
@@ -346,7 +358,7 @@
   {
     "pattern": { "pathname": "/foo/:bar+" },
     "input": { "pathname": "/foo/bar/baz" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/bar/baz" },
       "pathname": { "input": "/foo/bar/baz", "groups": { "bar": "bar/baz" } }
     }
@@ -354,22 +366,22 @@
   {
     "pattern": { "pathname": "/foo/:bar+" },
     "input": { "pathname": "/foo" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/:bar+" },
     "input": { "pathname": "/foo/" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/:bar+" },
     "input": { "pathname": "/foobar" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/:bar*" },
     "input": { "pathname": "/foo/bar" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/bar" },
       "pathname": { "input": "/foo/bar", "groups": { "bar": "bar" } }
     }
@@ -377,7 +389,7 @@
   {
     "pattern": { "pathname": "/foo/:bar*" },
     "input": { "pathname": "/foo/bar/baz" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/bar/baz" },
       "pathname": { "input": "/foo/bar/baz", "groups": { "bar": "bar/baz" } }
     }
@@ -385,7 +397,7 @@
   {
     "pattern": { "pathname": "/foo/:bar*" },
     "input": { "pathname": "/foo" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo" },
       "pathname": { "input": "/foo", "groups": { "bar": "" } }
     }
@@ -393,17 +405,20 @@
   {
     "pattern": { "pathname": "/foo/:bar*" },
     "input": { "pathname": "/foo/" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/:bar*" },
     "input": { "pathname": "/foobar" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/(.*)?" },
     "input": { "pathname": "/foo/bar" },
-    "expected": {
+    "expected_obj": {
+      "pathname": "/foo/*?"
+    },
+    "expected_match": {
       "input": { "pathname": "/foo/bar" },
       "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } }
     }
@@ -411,7 +426,7 @@
   {
     "pattern": { "pathname": "/foo/*?" },
     "input": { "pathname": "/foo/bar" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/bar" },
       "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } }
     }
@@ -419,7 +434,10 @@
   {
     "pattern": { "pathname": "/foo/(.*)?" },
     "input": { "pathname": "/foo/bar/baz" },
-    "expected": {
+    "expected_obj": {
+      "pathname": "/foo/*?"
+    },
+    "expected_match": {
       "input": { "pathname": "/foo/bar/baz" },
       "pathname": { "input": "/foo/bar/baz", "groups": { "0": "bar/baz" } }
     }
@@ -427,7 +445,7 @@
   {
     "pattern": { "pathname": "/foo/*?" },
     "input": { "pathname": "/foo/bar/baz" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/bar/baz" },
       "pathname": { "input": "/foo/bar/baz", "groups": { "0": "bar/baz" } }
     }
@@ -435,7 +453,10 @@
   {
     "pattern": { "pathname": "/foo/(.*)?" },
     "input": { "pathname": "/foo" },
-    "expected": {
+    "expected_obj": {
+      "pathname": "/foo/*?"
+    },
+    "expected_match": {
       "input": { "pathname": "/foo" },
       "pathname": { "input": "/foo", "groups": { "0": "" } }
     }
@@ -443,7 +464,7 @@
   {
     "pattern": { "pathname": "/foo/*?" },
     "input": { "pathname": "/foo" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo" },
       "pathname": { "input": "/foo", "groups": { "0": "" } }
     }
@@ -451,7 +472,10 @@
   {
     "pattern": { "pathname": "/foo/(.*)?" },
     "input": { "pathname": "/foo/" },
-    "expected": {
+    "expected_obj": {
+      "pathname": "/foo/*?"
+    },
+    "expected_match": {
       "input": { "pathname": "/foo/" },
       "pathname": { "input": "/foo/", "groups": { "0": "" } }
     }
@@ -459,7 +483,7 @@
   {
     "pattern": { "pathname": "/foo/*?" },
     "input": { "pathname": "/foo/" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/" },
       "pathname": { "input": "/foo/", "groups": { "0": "" } }
     }
@@ -467,27 +491,36 @@
   {
     "pattern": { "pathname": "/foo/(.*)?" },
     "input": { "pathname": "/foobar" },
-    "expected": null
+    "expected_obj": {
+      "pathname": "/foo/*?"
+    },
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/*?" },
     "input": { "pathname": "/foobar" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/(.*)?" },
     "input": { "pathname": "/fo" },
-    "expected": null
+    "expected_obj": {
+      "pathname": "/foo/*?"
+    },
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/*?" },
     "input": { "pathname": "/fo" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/(.*)+" },
     "input": { "pathname": "/foo/bar" },
-    "expected": {
+    "expected_obj": {
+      "pathname": "/foo/*+"
+    },
+    "expected_match": {
       "input": { "pathname": "/foo/bar" },
       "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } }
     }
@@ -495,7 +528,7 @@
   {
     "pattern": { "pathname": "/foo/*+" },
     "input": { "pathname": "/foo/bar" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/bar" },
       "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } }
     }
@@ -503,7 +536,10 @@
   {
     "pattern": { "pathname": "/foo/(.*)+" },
     "input": { "pathname": "/foo/bar/baz" },
-    "expected": {
+    "expected_obj": {
+      "pathname": "/foo/*+"
+    },
+    "expected_match": {
       "input": { "pathname": "/foo/bar/baz" },
       "pathname": { "input": "/foo/bar/baz", "groups": { "0": "bar/baz" } }
     }
@@ -511,7 +547,7 @@
   {
     "pattern": { "pathname": "/foo/*+" },
     "input": { "pathname": "/foo/bar/baz" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/bar/baz" },
       "pathname": { "input": "/foo/bar/baz", "groups": { "0": "bar/baz" } }
     }
@@ -519,17 +555,23 @@
   {
     "pattern": { "pathname": "/foo/(.*)+" },
     "input": { "pathname": "/foo" },
-    "expected": null
+    "expected_obj": {
+      "pathname": "/foo/*+"
+    },
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/*+" },
     "input": { "pathname": "/foo" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/(.*)+" },
     "input": { "pathname": "/foo/" },
-    "expected": {
+    "expected_obj": {
+      "pathname": "/foo/*+"
+    },
+    "expected_match": {
       "input": { "pathname": "/foo/" },
       "pathname": { "input": "/foo/", "groups": { "0": "" } }
     }
@@ -537,7 +579,7 @@
   {
     "pattern": { "pathname": "/foo/*+" },
     "input": { "pathname": "/foo/" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/" },
       "pathname": { "input": "/foo/", "groups": { "0": "" } }
     }
@@ -545,27 +587,36 @@
   {
     "pattern": { "pathname": "/foo/(.*)+" },
     "input": { "pathname": "/foobar" },
-    "expected": null
+    "expected_obj": {
+      "pathname": "/foo/*+"
+    },
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/*+" },
     "input": { "pathname": "/foobar" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/(.*)+" },
     "input": { "pathname": "/fo" },
-    "expected": null
+    "expected_obj": {
+      "pathname": "/foo/*+"
+    },
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/*+" },
     "input": { "pathname": "/fo" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/(.*)*" },
     "input": { "pathname": "/foo/bar" },
-    "expected": {
+    "expected_obj": {
+      "pathname": "/foo/**"
+    },
+    "expected_match": {
       "input": { "pathname": "/foo/bar" },
       "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } }
     }
@@ -573,7 +624,7 @@
   {
     "pattern": { "pathname": "/foo/**" },
     "input": { "pathname": "/foo/bar" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/bar" },
       "pathname": { "input": "/foo/bar", "groups": { "0": "bar" } }
     }
@@ -581,7 +632,10 @@
   {
     "pattern": { "pathname": "/foo/(.*)*" },
     "input": { "pathname": "/foo/bar/baz" },
-    "expected": {
+    "expected_obj": {
+      "pathname": "/foo/**"
+    },
+    "expected_match": {
       "input": { "pathname": "/foo/bar/baz" },
       "pathname": { "input": "/foo/bar/baz", "groups": { "0": "bar/baz" } }
     }
@@ -589,7 +643,7 @@
   {
     "pattern": { "pathname": "/foo/**" },
     "input": { "pathname": "/foo/bar/baz" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/bar/baz" },
       "pathname": { "input": "/foo/bar/baz", "groups": { "0": "bar/baz" } }
     }
@@ -597,7 +651,10 @@
   {
     "pattern": { "pathname": "/foo/(.*)*" },
     "input": { "pathname": "/foo" },
-    "expected": {
+    "expected_obj": {
+      "pathname": "/foo/**"
+    },
+    "expected_match": {
       "input": { "pathname": "/foo" },
       "pathname": { "input": "/foo", "groups": { "0": "" } }
     }
@@ -605,7 +662,7 @@
   {
     "pattern": { "pathname": "/foo/**" },
     "input": { "pathname": "/foo" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo" },
       "pathname": { "input": "/foo", "groups": { "0": "" } }
     }
@@ -613,7 +670,10 @@
   {
     "pattern": { "pathname": "/foo/(.*)*" },
     "input": { "pathname": "/foo/" },
-    "expected": {
+    "expected_obj": {
+      "pathname": "/foo/**"
+    },
+    "expected_match": {
       "input": { "pathname": "/foo/" },
       "pathname": { "input": "/foo/", "groups": { "0": "" } }
     }
@@ -621,7 +681,7 @@
   {
     "pattern": { "pathname": "/foo/**" },
     "input": { "pathname": "/foo/" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/" },
       "pathname": { "input": "/foo/", "groups": { "0": "" } }
     }
@@ -629,27 +689,36 @@
   {
     "pattern": { "pathname": "/foo/(.*)*" },
     "input": { "pathname": "/foobar" },
-    "expected": null
+    "expected_obj": {
+      "pathname": "/foo/**"
+    },
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/**" },
     "input": { "pathname": "/foobar" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/(.*)*" },
     "input": { "pathname": "/fo" },
-    "expected": null
+    "expected_obj": {
+      "pathname": "/foo/**"
+    },
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/**" },
     "input": { "pathname": "/fo" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo{/bar}" },
     "input": { "pathname": "/foo/bar" },
-    "expected": {
+    "expected_obj": {
+      "pathname": "/foo/bar"
+    },
+    "expected_match": {
       "input": { "pathname": "/foo/bar" },
       "pathname": { "input": "/foo/bar", "groups": {} }
     }
@@ -657,22 +726,31 @@
   {
     "pattern": { "pathname": "/foo{/bar}" },
     "input": { "pathname": "/foo/bar/baz" },
-    "expected": null
+    "expected_obj": {
+      "pathname": "/foo/bar"
+    },
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo{/bar}" },
     "input": { "pathname": "/foo" },
-    "expected": null
+    "expected_obj": {
+      "pathname": "/foo/bar"
+    },
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo{/bar}" },
     "input": { "pathname": "/foo/" },
-    "expected": null
+    "expected_obj": {
+      "pathname": "/foo/bar"
+    },
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo{/bar}?" },
     "input": { "pathname": "/foo/bar" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/bar" },
       "pathname": { "input": "/foo/bar", "groups": {} }
     }
@@ -680,12 +758,12 @@
   {
     "pattern": { "pathname": "/foo{/bar}?" },
     "input": { "pathname": "/foo/bar/baz" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo{/bar}?" },
     "input": { "pathname": "/foo" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo" },
       "pathname": { "input": "/foo", "groups": {} }
     }
@@ -693,12 +771,12 @@
   {
     "pattern": { "pathname": "/foo{/bar}?" },
     "input": { "pathname": "/foo/" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo{/bar}+" },
     "input": { "pathname": "/foo/bar" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/bar" },
       "pathname": { "input": "/foo/bar", "groups": {} }
     }
@@ -706,7 +784,7 @@
   {
     "pattern": { "pathname": "/foo{/bar}+" },
     "input": { "pathname": "/foo/bar/bar" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/bar/bar" },
       "pathname": { "input": "/foo/bar/bar", "groups": {} }
     }
@@ -714,22 +792,22 @@
   {
     "pattern": { "pathname": "/foo{/bar}+" },
     "input": { "pathname": "/foo/bar/baz" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo{/bar}+" },
     "input": { "pathname": "/foo" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo{/bar}+" },
     "input": { "pathname": "/foo/" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo{/bar}*" },
     "input": { "pathname": "/foo/bar" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/bar" },
       "pathname": { "input": "/foo/bar", "groups": {} }
     }
@@ -737,7 +815,7 @@
   {
     "pattern": { "pathname": "/foo{/bar}*" },
     "input": { "pathname": "/foo/bar/bar" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/bar/bar" },
       "pathname": { "input": "/foo/bar/bar", "groups": {} }
     }
@@ -745,12 +823,12 @@
   {
     "pattern": { "pathname": "/foo{/bar}*" },
     "input": { "pathname": "/foo/bar/baz" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo{/bar}*" },
     "input": { "pathname": "/foo" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo" },
       "pathname": { "input": "/foo", "groups": {} }
     }
@@ -758,7 +836,7 @@
   {
     "pattern": { "pathname": "/foo{/bar}*" },
     "input": { "pathname": "/foo/" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "protocol": "(café)" },
@@ -791,7 +869,7 @@
   {
     "pattern": { "protocol": ":café" },
     "input": { "protocol": "foo" },
-    "expected": {
+    "expected_match": {
       "input": { "protocol": "foo" },
       "protocol": { "input": "foo", "groups": { "café": "foo" } }
     }
@@ -799,7 +877,7 @@
   {
     "pattern": { "username": ":café" },
     "input": { "username": "foo" },
-    "expected": {
+    "expected_match": {
       "input": { "username": "foo" },
       "username": { "input": "foo", "groups": { "café": "foo" } }
     }
@@ -807,7 +885,7 @@
   {
     "pattern": { "password": ":café" },
     "input": { "password": "foo" },
-    "expected": {
+    "expected_match": {
       "input": { "password": "foo" },
       "password": { "input": "foo", "groups": { "café": "foo" } }
     }
@@ -815,7 +893,7 @@
   {
     "pattern": { "hostname": ":café" },
     "input": { "hostname": "foo" },
-    "expected": {
+    "expected_match": {
       "input": { "hostname": "foo" },
       "hostname": { "input": "foo", "groups": { "café": "foo" } }
     }
@@ -823,7 +901,7 @@
   {
     "pattern": { "pathname": "/:café" },
     "input": { "pathname": "/foo" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo" },
       "pathname": { "input": "/foo", "groups": { "café": "foo" } }
     }
@@ -831,7 +909,7 @@
   {
     "pattern": { "search": ":café" },
     "input": { "search": "foo" },
-    "expected": {
+    "expected_match": {
       "input": { "search": "foo" },
       "search": { "input": "foo", "groups": { "café": "foo" } }
     }
@@ -839,7 +917,7 @@
   {
     "pattern": { "hash": ":café" },
     "input": { "hash": "foo" },
-    "expected": {
+    "expected_match": {
       "input": { "hash": "foo" },
       "hash": { "input": "foo", "groups": { "café": "foo" } }
     }
@@ -847,7 +925,7 @@
   {
     "pattern": { "protocol": ":\u2118" },
     "input": { "protocol": "foo" },
-    "expected": {
+    "expected_match": {
       "input": { "protocol": "foo" },
       "protocol": { "input": "foo", "groups": { "\u2118": "foo" } }
     }
@@ -855,7 +933,7 @@
   {
     "pattern": { "username": ":\u2118" },
     "input": { "username": "foo" },
-    "expected": {
+    "expected_match": {
       "input": { "username": "foo" },
       "username": { "input": "foo", "groups": { "\u2118": "foo" } }
     }
@@ -863,7 +941,7 @@
   {
     "pattern": { "password": ":\u2118" },
     "input": { "password": "foo" },
-    "expected": {
+    "expected_match": {
       "input": { "password": "foo" },
       "password": { "input": "foo", "groups": { "\u2118": "foo" } }
     }
@@ -871,7 +949,7 @@
   {
     "pattern": { "hostname": ":\u2118" },
     "input": { "hostname": "foo" },
-    "expected": {
+    "expected_match": {
       "input": { "hostname": "foo" },
       "hostname": { "input": "foo", "groups": { "\u2118": "foo" } }
     }
@@ -879,7 +957,7 @@
   {
     "pattern": { "pathname": "/:\u2118" },
     "input": { "pathname": "/foo" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo" },
       "pathname": { "input": "/foo", "groups": { "\u2118": "foo" } }
     }
@@ -887,7 +965,7 @@
   {
     "pattern": { "search": ":\u2118" },
     "input": { "search": "foo" },
-    "expected": {
+    "expected_match": {
       "input": { "search": "foo" },
       "search": { "input": "foo", "groups": { "\u2118": "foo" } }
     }
@@ -895,7 +973,7 @@
   {
     "pattern": { "hash": ":\u2118" },
     "input": { "hash": "foo" },
-    "expected": {
+    "expected_match": {
       "input": { "hash": "foo" },
       "hash": { "input": "foo", "groups": { "\u2118": "foo" } }
     }
@@ -903,7 +981,7 @@
   {
     "pattern": { "protocol": ":\u3400" },
     "input": { "protocol": "foo" },
-    "expected": {
+    "expected_match": {
       "input": { "protocol": "foo" },
       "protocol": { "input": "foo", "groups": { "\u3400": "foo" } }
     }
@@ -911,7 +989,7 @@
   {
     "pattern": { "username": ":\u3400" },
     "input": { "username": "foo" },
-    "expected": {
+    "expected_match": {
       "input": { "username": "foo" },
       "username": { "input": "foo", "groups": { "\u3400": "foo" } }
     }
@@ -919,7 +997,7 @@
   {
     "pattern": { "password": ":\u3400" },
     "input": { "password": "foo" },
-    "expected": {
+    "expected_match": {
       "input": { "password": "foo" },
       "password": { "input": "foo", "groups": { "\u3400": "foo" } }
     }
@@ -927,7 +1005,7 @@
   {
     "pattern": { "hostname": ":\u3400" },
     "input": { "hostname": "foo" },
-    "expected": {
+    "expected_match": {
       "input": { "hostname": "foo" },
       "hostname": { "input": "foo", "groups": { "\u3400": "foo" } }
     }
@@ -935,7 +1013,7 @@
   {
     "pattern": { "pathname": "/:\u3400" },
     "input": { "pathname": "/foo" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo" },
       "pathname": { "input": "/foo", "groups": { "\u3400": "foo" } }
     }
@@ -943,7 +1021,7 @@
   {
     "pattern": { "search": ":\u3400" },
     "input": { "search": "foo" },
-    "expected": {
+    "expected_match": {
       "input": { "search": "foo" },
       "search": { "input": "foo", "groups": { "\u3400": "foo" } }
     }
@@ -951,7 +1029,7 @@
   {
     "pattern": { "hash": ":\u3400" },
     "input": { "hash": "foo" },
-    "expected": {
+    "expected_match": {
       "input": { "hash": "foo" },
       "hash": { "input": "foo", "groups": { "\u3400": "foo" } }
     }
@@ -959,12 +1037,18 @@
   {
     "pattern": { "protocol": "(.*)" },
     "input": { "protocol" : "café" },
-    "expected": null
+    "expected_obj": {
+      "protocol": "*"
+    },
+    "expected_match": null
   },
   {
     "pattern": { "protocol": "(.*)" },
     "input": { "protocol": "cafe" },
-    "expected": {
+    "expected_obj": {
+      "protocol": "*"
+    },
+    "expected_match": {
       "input": { "protocol": "cafe" },
       "protocol": { "input": "cafe", "groups": { "0": "cafe" }}
     }
@@ -972,7 +1056,7 @@
   {
     "pattern": { "protocol": "foo-bar" },
     "input": { "protocol": "foo-bar" },
-    "expected": {
+    "expected_match": {
       "input": { "protocol": "foo-bar" },
       "protocol": { "input": "foo-bar", "groups": {} }
     }
@@ -980,7 +1064,7 @@
   {
     "pattern": { "username": "caf%C3%A9" },
     "input": { "username" : "café" },
-    "expected": {
+    "expected_match": {
       "input": { "username" : "café" },
       "username": { "input": "caf%C3%A9", "groups": {}}
     }
@@ -988,7 +1072,10 @@
   {
     "pattern": { "username": "café" },
     "input": { "username" : "café" },
-    "expected": {
+    "expected_obj": {
+      "username": "caf%C3%A9"
+    },
+    "expected_match": {
       "input": { "username" : "café" },
       "username": { "input": "caf%C3%A9", "groups": {}}
     }
@@ -996,12 +1083,12 @@
   {
     "pattern": { "username": "caf%c3%a9" },
     "input": { "username" : "café" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "password": "caf%C3%A9" },
     "input": { "password" : "café" },
-    "expected": {
+    "expected_match": {
       "input": { "password" : "café" },
       "password": { "input": "caf%C3%A9", "groups": {}}
     }
@@ -1009,7 +1096,10 @@
   {
     "pattern": { "password": "café" },
     "input": { "password" : "café" },
-    "expected": {
+    "expected_obj": {
+      "password": "caf%C3%A9"
+    },
+    "expected_match": {
       "input": { "password" : "café" },
       "password": { "input": "caf%C3%A9", "groups": {}}
     }
@@ -1017,12 +1107,12 @@
   {
     "pattern": { "password": "caf%c3%a9" },
     "input": { "password" : "café" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "hostname": "xn--caf-dma.com" },
     "input": { "hostname" : "café.com" },
-    "expected": {
+    "expected_match": {
       "input": { "hostname" : "café.com" },
       "hostname": { "input": "xn--caf-dma.com", "groups": {}}
     }
@@ -1030,7 +1120,10 @@
   {
     "pattern": { "hostname": "café.com" },
     "input": { "hostname" : "café.com" },
-    "expected": {
+    "expected_obj": {
+      "hostname": "xn--caf-dma.com"
+    },
+    "expected_match": {
       "input": { "hostname" : "café.com" },
       "hostname": { "input": "xn--caf-dma.com", "groups": {}}
     }
@@ -1038,7 +1131,7 @@
   {
     "pattern": { "port": "" },
     "input": { "protocol": "http", "port": "80" },
-    "expected": {
+    "expected_match": {
       "input": { "protocol": "http", "port": "80" },
       "protocol": { "input": "http", "groups": { "0": "http" }},
       "port": { "input": "", "groups": {}}
@@ -1047,7 +1140,7 @@
   {
     "pattern": { "protocol": "http", "port": "80" },
     "input": { "protocol": "http", "port": "80" },
-    "expected": {
+    "expected_match": {
       "input": { "protocol": "http", "port": "80" },
       "protocol": { "input": "http", "groups": {}},
       "port": { "input": "", "groups": {}}
@@ -1056,7 +1149,7 @@
   {
     "pattern": { "protocol": "http", "port": "80{20}?" },
     "input": { "protocol": "http", "port": "80" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "protocol": "http", "port": "80 " },
@@ -1066,17 +1159,17 @@
   {
     "pattern": { "port": "80" },
     "input": { "protocol": "http", "port": "80" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "protocol": "http{s}?", "port": "80" },
     "input": { "protocol": "http", "port": "80" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "port": "80" },
     "input": { "port": "80" },
-    "expected": {
+    "expected_match": {
       "input": { "port": "80" },
       "port": { "input": "80", "groups": {}}
     }
@@ -1084,12 +1177,15 @@
   {
     "pattern": { "port": "(.*)" },
     "input": { "port": "invalid80" },
-    "expected": null
+    "expected_obj": {
+      "port": "*"
+    },
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/bar" },
     "input": { "pathname": "/foo/./bar" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/./bar" },
       "pathname": { "input": "/foo/bar", "groups": {}}
     }
@@ -1097,7 +1193,7 @@
   {
     "pattern": { "pathname": "/foo/baz" },
     "input": { "pathname": "/foo/bar/../baz" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/foo/bar/../baz" },
       "pathname": { "input": "/foo/baz", "groups": {}}
     }
@@ -1105,7 +1201,7 @@
   {
     "pattern": { "pathname": "/caf%C3%A9" },
     "input": { "pathname": "/café" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "/café" },
       "pathname": { "input": "/caf%C3%A9", "groups": {}}
     }
@@ -1113,7 +1209,10 @@
   {
     "pattern": { "pathname": "/café" },
     "input": { "pathname": "/café" },
-    "expected": {
+    "expected_obj": {
+      "pathname": "/caf%C3%A9"
+    },
+    "expected_match": {
       "input": { "pathname": "/café" },
       "pathname": { "input": "/caf%C3%A9", "groups": {}}
     }
@@ -1121,17 +1220,17 @@
   {
     "pattern": { "pathname": "/caf%c3%a9" },
     "input": { "pathname": "/café" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/bar" },
     "input": { "pathname": "foo/bar" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "/foo/bar" },
     "input": { "pathname": "foo/bar", "baseURL": "https://example.com" },
-    "expected": {
+    "expected_match": {
       "input": { "pathname": "foo/bar", "baseURL": "https://example.com" },
       "protocol": { "input": "https", "groups": { "0": "https" }},
       "hostname": { "input": "example.com", "groups": { "0": "example.com" }},
@@ -1141,7 +1240,10 @@
   {
     "pattern": { "pathname": "/foo/../bar" },
     "input": { "pathname": "/bar" },
-    "expected": {
+    "expected_obj": {
+      "pathname": "/bar"
+    },
+    "expected_match": {
       "input": { "pathname": "/bar" },
       "pathname": { "input": "/bar", "groups": {}}
     }
@@ -1149,7 +1251,10 @@
   {
     "pattern": { "pathname": "./foo/bar", "baseURL": "https://example.com" },
     "input": { "pathname": "foo/bar", "baseURL": "https://example.com" },
-    "expected": {
+    "expected_obj": {
+      "pathname": "/foo/bar"
+    },
+    "expected_match": {
       "input": { "pathname": "foo/bar", "baseURL": "https://example.com" },
       "exactly_empty_components": [ "username", "password", "port" ],
       "protocol": { "input": "https", "groups": {}},
@@ -1160,12 +1265,15 @@
   {
     "pattern": { "pathname": "foo/bar" },
     "input": "https://example.com/foo/bar",
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "pathname": "foo/bar", "baseURL": "https://example.com" },
     "input": "https://example.com/foo/bar",
-    "expected": {
+    "expected_obj": {
+      "pathname": "/foo/bar"
+    },
+    "expected_match": {
       "input": "https://example.com/foo/bar",
       "exactly_empty_components": [ "username", "password", "port" ],
       "protocol": { "input": "https", "groups": {}},
@@ -1176,7 +1284,10 @@
   {
     "pattern": { "pathname": ":name.html", "baseURL": "https://example.com" },
     "input": "https://example.com/foo.html",
-    "expected": {
+    "expected_obj": {
+      "pathname": "/:name.html"
+    },
+    "expected_match": {
       "input": "https://example.com/foo.html",
       "exactly_empty_components": [ "username", "password", "port" ],
       "protocol": { "input": "https", "groups": {}},
@@ -1187,7 +1298,7 @@
   {
     "pattern": { "search": "q=caf%C3%A9" },
     "input": { "search": "q=café" },
-    "expected": {
+    "expected_match": {
       "input": { "search": "q=café" },
       "search": { "input": "q=caf%C3%A9", "groups": {}}
     }
@@ -1195,7 +1306,10 @@
   {
     "pattern": { "search": "q=café" },
     "input": { "search": "q=café" },
-    "expected": {
+    "expected_obj": {
+      "search": "q=caf%C3%A9"
+    },
+    "expected_match": {
       "input": { "search": "q=café" },
       "search": { "input": "q=caf%C3%A9", "groups": {}}
     }
@@ -1203,12 +1317,12 @@
   {
     "pattern": { "search": "q=caf%c3%a9" },
     "input": { "search": "q=café" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "hash": "caf%C3%A9" },
     "input": { "hash": "café" },
-    "expected": {
+    "expected_match": {
       "input": { "hash": "café" },
       "hash": { "input": "caf%C3%A9", "groups": {}}
     }
@@ -1216,7 +1330,10 @@
   {
     "pattern": { "hash": "café" },
     "input": { "hash": "café" },
-    "expected": {
+    "expected_obj": {
+      "hash": "caf%C3%A9"
+    },
+    "expected_match": {
       "input": { "hash": "café" },
       "hash": { "input": "caf%C3%A9", "groups": {}}
     }
@@ -1224,12 +1341,12 @@
   {
     "pattern": { "hash": "caf%c3%a9" },
     "input": { "hash": "café" },
-    "expected": null
+    "expected_match": null
   },
   {
     "pattern": { "protocol": "about", "pathname": "(blank|sourcedoc)" },
     "input": "about:blank",
-    "expected": {
+    "expected_match": {
       "input": "about:blank",
       "protocol": { "input": "about", "groups": {}},
       "pathname": { "input": "blank", "groups": { "0": "blank" }}
@@ -1238,10 +1355,49 @@
   {
     "pattern": { "protocol": "data", "pathname": ":number([0-9]+)" },
     "input": "data:8675309",
-    "expected": {
+    "expected_match": {
       "input": "data:8675309",
       "protocol": { "input": "data", "groups": {}},
       "pathname": { "input": "8675309", "groups": { "number": "8675309" }}
     }
+  },
+  {
+    "pattern": { "pathname": "/(\\m)" },
+    "error": true
+  },
+  {
+    "pattern": { "pathname": "/foo!" },
+    "input": { "pathname": "/foo!" },
+    "expected_match": {
+      "input": { "pathname": "/foo!" },
+      "pathname": { "input": "/foo!", "groups": {}}
+    }
+  },
+  {
+    "pattern": { "pathname": "/foo\\:" },
+    "input": { "pathname": "/foo:" },
+    "expected_match": {
+      "input": { "pathname": "/foo:" },
+      "pathname": { "input": "/foo:", "groups": {}}
+    }
+  },
+  {
+    "pattern": { "pathname": "/foo\\{" },
+    "input": { "pathname": "/foo{" },
+    "expected_obj": {
+      "pathname": "/foo%7B"
+    },
+    "expected_match": {
+      "input": { "pathname": "/foo{" },
+      "pathname": { "input": "/foo%7B", "groups": {}}
+    }
+  },
+  {
+    "pattern": { "pathname": "/foo\\(" },
+    "input": { "pathname": "/foo(" },
+    "expected_match": {
+      "input": { "pathname": "/foo(" },
+      "pathname": { "input": "/foo(", "groups": {}}
+    }
   }
 ]
diff --git a/third_party/blink/web_tests/external/wpt/urlpattern/urlpattern.https.any.js b/third_party/blink/web_tests/external/wpt/urlpattern/urlpattern.https.any.js
index 3d47f57..183e401 100644
--- a/third_party/blink/web_tests/external/wpt/urlpattern/urlpattern.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/urlpattern/urlpattern.https.any.js
@@ -1,5 +1,16 @@
 // META: global=window,worker
 
+const kComponents = [
+  'protocol',
+  'username',
+  'password',
+  'hostname',
+  'password',
+  'pathname',
+  'search',
+  'hash',
+];
+
 function runTests(data) {
   for (let entry of data) {
     test(function() {
@@ -11,45 +22,86 @@
 
       const pattern = new URLPattern(entry.pattern);
 
+      // If the expected_obj property is not present we will automatically
+      // fill it with the most likely expected values.
+      entry.expected_obj = entry.expected_obj || {};
+
+      // The compiled URLPattern object should have a property for each
+      // component exposing the compiled pattern string.
+      for (let component of kComponents) {
+        // If the test case explicitly provides an expected pattern string,
+        // then use that.  This is necessary in cases where the original
+        // construction pattern gets canonicalized, etc.
+        let expected = entry.expected_obj[component];
+
+        // If there is no explicit expected pattern string, then compute
+        // the expected value based on the URLPattern constructor args.
+        if (!expected) {
+          // First determine if there is a baseURL present in the pattern
+          // input.  A baseURL can be the source for many component patterns.
+          let baseURL = null;
+          if (entry.pattern.baseURL)
+            baseURL = new URL(entry.pattern.baseURL);
+
+          // We automatically populate the expected pattern string using
+          // the following options in priority order:
+          //
+          //  1. If the original input explicitly provided a pattern, then
+          //     echo that back as the expected value.
+          //  2. If the baseURL exists and provides a component value then
+          //     use that for the expected pattern.  Note, the baseURL
+          //     does not provide search/hash component values.
+          //  3. Otherwise fall back on the default pattern of `*` for an
+          //     empty component pattern.
+          if (entry.pattern[component]) {
+            expected = entry.pattern[component];
+          } else if (baseURL &&
+                     component !== 'search' && component !== 'hash') {
+            let base_value = baseURL[component];
+            // Unfortunately the URL() protocol getter includes a trailing `:`
+            // that is not used by URLPattern.  Strip that off in necessary.
+            if (component === 'protocol')
+              base_value = base_value.substring(0, base_value.length - 1);
+            expected = base_value;
+          } else {
+            expected = '*';
+          }
+        }
+
+        // Finally, assert that the compiled object property matches the
+        // expected property.
+        assert_equals(pattern[component], expected,
+                      `compiled pattern property '${component}'`);
+      }
+
       // First, validate the test() method by converting the expected result to
       // a truthy value.
-      assert_equals(pattern.test(entry.input), !!entry.expected,
+      assert_equals(pattern.test(entry.input), !!entry.expected_match,
                     'test() result');
 
       // Next, start validating the exec() method.
       const result = pattern.exec(entry.input);
 
       // On a failed match exec() returns null.
-      if (!entry.expected) {
-        assert_equals(result, entry.expected, 'exec() failed match result');
+      if (!entry.expected_match) {
+        assert_equals(result, entry.expected_match, 'exec() failed match result');
         return;
       }
 
       // Next verify the result.input is correct.  This may be a structured
       // URLPatternInit dictionary object or a URL string.
-      if (typeof entry.expected.input === 'object') {
-        assert_object_equals(result.input, entry.expected.input,
+      if (typeof entry.expected_match.input === 'object') {
+        assert_object_equals(result.input, entry.expected_match.input,
                              'exec() result.input');
       } else {
-        assert_equals(result.input, entry.expected.input,
+        assert_equals(result.input, entry.expected_match.input,
                       'exec() result.input');
       }
 
       // Next we will compare the URLPatternComponentResult for each of these
       // expected components.
-      const component_list = [
-        'protocol',
-        'username',
-        'password',
-        'hostname',
-        'password',
-        'pathname',
-        'search',
-        'hash',
-      ];
-
-      for (let component of component_list) {
-        let expected_obj = entry.expected[component];
+      for (let component of kComponents) {
+        let expected_obj = entry.expected_match[component];
 
         // If the test expectations don't include a component object, then
         // we auto-generate one.  This is convenient for the many cases
@@ -63,8 +115,8 @@
           // string pattern does not.  The expectation object must list which
           // components should be empty instead of wildcards in
           // |exactly_empty_components|.
-          if (!entry.expected.exactly_empty_components ||
-              !entry.expected.exactly_empty_components.includes(component)) {
+          if (!entry.expected_match.exactly_empty_components ||
+              !entry.expected_match.exactly_empty_components.includes(component)) {
             expected_obj.groups['0'] = '';
           }
         }
diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/video-encoder.any.js b/third_party/blink/web_tests/external/wpt/webcodecs/video-encoder.any.js
index a63df99..a7fc327e 100644
--- a/third_party/blink/web_tests/external/wpt/webcodecs/video-encoder.any.js
+++ b/third_party/blink/web_tests/external/wpt/webcodecs/video-encoder.any.js
@@ -60,7 +60,10 @@
 promise_test(async t => {
   let output_chunks = [];
   let codecInit = getDefaultCodecInit(t);
-  codecInit.output = chunk => output_chunks.push(chunk);
+  codecInit.output = (chunk, metadata) => {
+    assert_not_equals(metadata, null);
+    output_chunks.push(chunk);
+  }
 
   let encoder = new VideoEncoder(codecInit);
 
@@ -102,7 +105,7 @@
   let bitmap = await generateBitmap(320, 200);
   let encoder = null;
   let reset_completed = false;
-  codecInit.output = chunk => {
+  codecInit.output = (chunk, metadata) => {
     if (chunk.timestamp % 2 == 0) {
       // pre-reset frames have even timestamp
       callbacks_before_reset++;
diff --git a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-css-import-expected.txt b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-css-import-expected.txt
new file mode 100644
index 0000000..df226a6
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-css-import-expected.txt
@@ -0,0 +1,10 @@
+Test if coverage view also shows completly uncovered css files
+
+Make sure all files are shown even when not covered so far
+.../devtools/coverage/resources/css-coverage-import.html CSS used: 0 unused: 27 total: 27
+.../devtools/coverage/resources/used.css CSS used: 24 unused: 0 total: 24
+Make sure files are added as they are loaded on reload
+Page reloaded.
+.../devtools/coverage/resources/css-coverage-import.html CSS used: 0 unused: 27 total: 27
+.../devtools/coverage/resources/used.css CSS used: 24 unused: 0 total: 24
+
diff --git a/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-css-import.js b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-css-import.js
new file mode 100644
index 0000000..c57955ca
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/coverage/coverage-view-css-import.js
@@ -0,0 +1,27 @@
+// Copyright 2021 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.
+
+(async function() {
+  TestRunner.addResult(
+      `Test if coverage view also shows completly uncovered css files\n`);
+  await TestRunner.loadModule('coverage_test_runner');
+  await TestRunner.navigatePromise(
+      TestRunner.url('resources/css-coverage-import.html'));
+
+  await CoverageTestRunner.startCoverage(true);
+
+  TestRunner.addResult(
+      'Make sure all files are shown even when not covered so far');
+  await CoverageTestRunner.pollCoverage();
+  CoverageTestRunner.dumpCoverageListView();
+
+  TestRunner.addResult(
+      'Make sure files are added as they are loaded on reload');
+  await TestRunner.reloadPagePromise();
+  await CoverageTestRunner.pollCoverage();
+  CoverageTestRunner.dumpCoverageListView();
+
+  await CoverageTestRunner.stopCoverage();
+  TestRunner.completeTest();
+})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/coverage/resources/css-coverage-import.html b/third_party/blink/web_tests/http/tests/devtools/coverage/resources/css-coverage-import.html
new file mode 100644
index 0000000..338946be
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/coverage/resources/css-coverage-import.html
@@ -0,0 +1,13 @@
+<html>
+
+<head>
+  <style>
+    @import 'used.css';
+  </style>
+</head>
+
+<body>
+  <h1>Hello World</h1>
+</body>
+
+</html>
diff --git a/third_party/blink/web_tests/http/tests/devtools/local-object-properties-section.js b/third_party/blink/web_tests/http/tests/devtools/local-object-properties-section.js
index 66ccb0c..8c5c8c8 100644
--- a/third_party/blink/web_tests/http/tests/devtools/local-object-properties-section.js
+++ b/third_party/blink/web_tests/http/tests/devtools/local-object-properties-section.js
@@ -5,6 +5,7 @@
 (async function() {
   TestRunner.addResult(`Test that ObjectPropertiesSection works with local remote objects.\n`);
   await TestRunner.loadModule('object_ui');
+  await TestRunner.loadLegacyModule('object_ui');
 
   var d = [];
   for (var i = 1000; i < 1256; ++i)
diff --git a/third_party/blink/web_tests/http/tests/devtools/throttling/mobile-throttling.js b/third_party/blink/web_tests/http/tests/devtools/throttling/mobile-throttling.js
index 735ce25..f379546 100644
--- a/third_party/blink/web_tests/http/tests/devtools/throttling/mobile-throttling.js
+++ b/third_party/blink/web_tests/http/tests/devtools/throttling/mobile-throttling.js
@@ -8,6 +8,7 @@
   await TestRunner.showPanel("timeline");
   await TestRunner.loadLegacyModule('emulation');
   await TestRunner.loadLegacyModule('mobile_throttling');
+  await TestRunner.loadLegacyModule('network');
   await UI.viewManager.showView("network.config");
 
   var deviceModeView = new Emulation.DeviceModeView();
diff --git a/third_party/blink/web_tests/http/tests/devtools/unit/object-properties-expand-recursively.js b/third_party/blink/web_tests/http/tests/devtools/unit/object-properties-expand-recursively.js
index dbf2e4f..778a595 100644
--- a/third_party/blink/web_tests/http/tests/devtools/unit/object-properties-expand-recursively.js
+++ b/third_party/blink/web_tests/http/tests/devtools/unit/object-properties-expand-recursively.js
@@ -5,6 +5,7 @@
 (async function() {
   TestRunner.addResult(`Test that ObjectPropertiesSection expands recursively.\n`);
   await TestRunner.loadModule('object_ui');
+  await TestRunner.loadLegacyModule('object_ui');
 
   var object = {
     "foo": {
diff --git a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 4c98679..bffd6dfb 100644
--- a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -1562,6 +1562,14 @@
     setter username
 interface URLPattern
     attribute @@toStringTag
+    getter hash
+    getter hostname
+    getter password
+    getter pathname
+    getter port
+    getter protocol
+    getter search
+    getter username
     method constructor
     method exec
     method test
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
index e200e13a..8c257b1 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -1606,6 +1606,14 @@
 [Worker]     setter username
 [Worker] interface URLPattern
 [Worker]     attribute @@toStringTag
+[Worker]     getter hash
+[Worker]     getter hostname
+[Worker]     getter password
+[Worker]     getter pathname
+[Worker]     getter port
+[Worker]     getter protocol
+[Worker]     getter search
+[Worker]     getter username
 [Worker]     method constructor
 [Worker]     method exec
 [Worker]     method test
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index 12458a3..27fd978c 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -11297,6 +11297,14 @@
     setter username
 interface URLPattern
     attribute @@toStringTag
+    getter hash
+    getter hostname
+    getter password
+    getter pathname
+    getter port
+    getter protocol
+    getter search
+    getter username
     method constructor
     method exec
     method test
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
index 27307e8..521bf47 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -1439,6 +1439,14 @@
 [Worker]     setter username
 [Worker] interface URLPattern
 [Worker]     attribute @@toStringTag
+[Worker]     getter hash
+[Worker]     getter hostname
+[Worker]     getter password
+[Worker]     getter pathname
+[Worker]     getter port
+[Worker]     getter protocol
+[Worker]     getter search
+[Worker]     getter username
 [Worker]     method constructor
 [Worker]     method exec
 [Worker]     method test
diff --git a/third_party/blink/web_tests/wpt_internal/webcodecs/avc_encoder_config.any.js b/third_party/blink/web_tests/wpt_internal/webcodecs/avc_encoder_config.any.js
index aed5ccf..a286a70 100644
--- a/third_party/blink/web_tests/wpt_internal/webcodecs/avc_encoder_config.any.js
+++ b/third_party/blink/web_tests/wpt_internal/webcodecs/avc_encoder_config.any.js
@@ -20,7 +20,8 @@
 
     let encoderInit = {
       error: () => t.unreached_func("Unexpected error"),
-      output: (chunk, config) => {
+      output: (chunk, metadata) => {
+        let config = metadata.decoderConfig;
         assert_equals(output, undefined, "output undefined sanity");
         output = {
           chunk: chunk,
diff --git a/third_party/blink/web_tests/wpt_internal/webcodecs/basic_video_encoding.any.js b/third_party/blink/web_tests/wpt_internal/webcodecs/basic_video_encoding.any.js
index c14660a..79f79b0 100644
--- a/third_party/blink/web_tests/wpt_internal/webcodecs/basic_video_encoding.any.js
+++ b/third_party/blink/web_tests/wpt_internal/webcodecs/basic_video_encoding.any.js
@@ -25,8 +25,8 @@
   });
 
   const encoder_init = {
-    output(chunk, config) {
-      var data = new Uint8Array(chunk.data);
+    output(chunk, metadata) {
+      let config = metadata.decoderConfig;
       if (decoder.state != "configured" || config.description) {
         decoder.configure(config);
       }
@@ -81,8 +81,9 @@
   let frames_processed = 0;
   let errors = 0;
 
-  let process_video_chunk = function (chunk, config) {
+  let process_video_chunk = function (chunk, metadata) {
     assert_greater_than_equal(chunk.timestamp, next_ts++);
+    let config = metadata.decoderConfig;
     let data = new Uint8Array(chunk.data);
     let type = (chunk.timestamp % 5 == 0) ? "key" : "delta";
     assert_equals(chunk.type, type);
diff --git a/third_party/blink/web_tests/wpt_internal/webcodecs/reconfiguring_encoder.any.js b/third_party/blink/web_tests/wpt_internal/webcodecs/reconfiguring_encoder.any.js
index eb18808..c600dfb 100644
--- a/third_party/blink/web_tests/wpt_internal/webcodecs/reconfiguring_encoder.any.js
+++ b/third_party/blink/web_tests/wpt_internal/webcodecs/reconfiguring_encoder.any.js
@@ -17,7 +17,8 @@
   let after_reconf_frames = 0;
   let errors = 0;
 
-  let process_video_chunk = function (chunk, config) {
+  let process_video_chunk = function (chunk, metadata) {
+    let config = metadata.decoderConfig;
     var data = new Uint8Array(chunk.data);
     assert_greater_than_equal(data.length, 0);
     let after_reconf = (reconf_ts != 0) && (chunk.timestamp >= reconf_ts);
diff --git a/third_party/blink/web_tests/wpt_internal/webcodecs/temporal_svc.any.js b/third_party/blink/web_tests/wpt_internal/webcodecs/temporal_svc.any.js
new file mode 100644
index 0000000..91aa006
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webcodecs/temporal_svc.any.js
@@ -0,0 +1,95 @@
+// META: global=window,dedicatedworker
+// META: script=/wpt_internal/webcodecs/encoder_utils.js
+
+async function svc_test(codec, layers, base_layer_decimator) {
+  const w = 320;
+  const h = 200;
+  let acc = "deny";
+  let frames_to_encode = 40;
+  let frames_decoded = 0;
+  let frames_encoded = 0;
+  let errors = 0;
+  let chunks = [];
+
+  const encoder_init = {
+    output(chunk, metadata) {
+      frames_encoded++;
+
+      // Filter out all frames, but base layer.
+      assert_less_than(metadata.temporalLayerId, layers);
+      if (metadata.temporalLayerId == 0)
+        chunks.push(chunk);
+    },
+    error(e) {
+      errors++;
+    }
+  };
+
+  let encoder_config = {
+    codec: codec,
+    hardwareAcceleration: acc,
+    width: w,
+    height: h,
+    bitrate: 5000000,
+    scalabilityMode: "L1T" + layers,
+  };
+
+  if (codec.includes("avc"))
+    encoder_config.avc = {format: "annexb"};
+
+  let encoder = new VideoEncoder(encoder_init);
+  encoder.configure(encoder_config);
+
+  for (let i = 0; i < frames_to_encode; i++) {
+    let frame = await createFrame(w, h, i);
+    encoder.encode(frame, { keyFrame: false });
+    await delay(1);
+  }
+  await encoder.flush();
+  assert_equals(errors, 0);
+
+  let decoder = new VideoDecoder({
+    output(frame) {
+      frames_decoded++;
+      frame.close();
+    },
+    error(e) {
+      errors++;
+    }
+  });
+
+  let decoder_config = {
+    codec: codec,
+    hardwareAcceleration: acc,
+    codedWidth: w,
+    codedHeight: h,
+  };
+  decoder.configure(decoder_config);
+
+  for (let chunk of chunks) {
+    decoder.decode(chunk);
+    await delay(1);
+  }
+  await decoder.flush();
+  assert_equals(errors, 0);
+
+  encoder.close();
+  decoder.close();
+  assert_equals(frames_encoded, frames_to_encode);
+
+  let base_layer_frames = frames_to_encode / base_layer_decimator;
+  assert_equals(chunks.length, base_layer_frames);
+  assert_equals(frames_decoded, base_layer_frames);
+}
+
+promise_test(svc_test.bind(null, "avc1.42001E", 2, 2), "SVC H264 L1T2");
+promise_test(svc_test.bind(null, "avc1.42001E", 3, 4), "SVC H264 L1T3");
+
+promise_test(svc_test.bind(null, "vp8", 2, 2), "SVC VP8 L1T2");
+promise_test(svc_test.bind(null, "vp8", 3, 4), "SVC VP8 L1T3");
+
+promise_test(svc_test.bind(null, "vp09.00.10.08", 2, 2), "SVC VP9 8 L1T2");
+promise_test(svc_test.bind(null, "vp09.00.10.08", 3, 4), "SVC VP9 8 L1T3");
+
+promise_test(svc_test.bind(null, "vp09.02.10.10", 2, 2), "SVC VP9 10 L1T2");
+promise_test(svc_test.bind(null, "vp09.02.10.10", 3, 4), "SVC VP9 10 L1T3");
\ No newline at end of file
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index 4bace058..bf1e0bf 100644
--- a/third_party/freetype/README.chromium
+++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@
 Name: FreeType
 URL: http://www.freetype.org/
-Version: VER-2-10-4-183-g2149b51f2
-Revision: 2149b51f2543719b1ee78fb50ecf4e6e80f84ad7
+Version: VER-2-10-4-187-gb0729b8fb
+Revision: b0729b8fbb18dc1340ade628facf3f1cee498bfb
 CPEPrefix: cpe:/a:freetype:freetype:2.10.4
 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent
          JPEG Group) licenses"
diff --git a/third_party/harfbuzz-ng/README.chromium b/third_party/harfbuzz-ng/README.chromium
index 058f3a3..129a13b 100644
--- a/third_party/harfbuzz-ng/README.chromium
+++ b/third_party/harfbuzz-ng/README.chromium
@@ -1,10 +1,10 @@
 Name: harfbuzz-ng
 Short Name: harfbuzz-ng
 URL: http://harfbuzz.org
-Version: 2.7.4-211
+Version: 2.7.4-246
 CPEPrefix: cpe:/a:harfbuzz_project:harfbuzz:2.6.4
-Date: 20210305
-Revision: 7686ff854bbb9698bb1469dcfe6d288c695a76b7
+Date: 20210316
+Revision: 4c34478b28497acfce02b8a544fed4ae20526336
 Security Critical: yes
 License: MIT
 License File: src/COPYING
diff --git a/third_party/liburlpattern/parse.cc b/third_party/liburlpattern/parse.cc
index 715e1f0..e9c9f1a 100644
--- a/third_party/liburlpattern/parse.cc
+++ b/third_party/liburlpattern/parse.cc
@@ -29,8 +29,8 @@
         encode_callback_(std::move(encode_callback)),
         options_(std::move(options)),
         segment_wildcard_regex_(
-            absl::StrFormat("[^%s]+?", EscapeString(options_.delimiter_list))) {
-  }
+            absl::StrFormat("[^%s]+?",
+                            EscapeRegexpString(options_.delimiter_list))) {}
 
   // Return true if there are more tokens to process.
   bool HasMoreTokens() const { return index_ < token_list_.size(); }
diff --git a/third_party/liburlpattern/parse_unittest.cc b/third_party/liburlpattern/parse_unittest.cc
index a27fe9c..28752f5 100644
--- a/third_party/liburlpattern/parse_unittest.cc
+++ b/third_party/liburlpattern/parse_unittest.cc
@@ -7,12 +7,16 @@
 #include "third_party/abseil-cpp/absl/strings/str_format.h"
 #include "third_party/liburlpattern/pattern.h"
 
-namespace liburlpattern {
+namespace {
 
 absl::StatusOr<std::string> PassThrough(absl::string_view input) {
   return std::string(input);
 }
 
+}  // namespace
+
+namespace liburlpattern {
+
 absl::StatusOr<std::string> ToUpper(absl::string_view input) {
   std::string output;
   std::transform(input.begin(), input.end(), std::back_inserter(output),
@@ -264,6 +268,10 @@
   RunParseTest("/foo:bar", expected_parts);
 }
 
+TEST(ParseTest, NameStartsWithNumber) {
+  RunParseTest("/foo/:0", absl::InvalidArgumentError("Missing parameter name"));
+}
+
 TEST(ParseTest, NameInGroup) {
   std::vector<Part> expected_parts = {
       Part(PartType::kFixed, "/foo", Modifier::kNone),
diff --git a/third_party/liburlpattern/pattern.cc b/third_party/liburlpattern/pattern.cc
index 3740748..52d78bc 100644
--- a/third_party/liburlpattern/pattern.cc
+++ b/third_party/liburlpattern/pattern.cc
@@ -80,6 +80,107 @@
       options_(std::move(options)),
       segment_wildcard_regex_(std::move(segment_wildcard_regex)) {}
 
+std::string Pattern::GeneratePatternString() const {
+  std::string result;
+
+  // Estimate the final length and reserve a reasonable sized string
+  // buffer to avoid reallocations.
+  size_t estimated_length = 0;
+  for (const Part& part : part_list_) {
+    // Add an arbitrary extra 3 per Part to account for braces, modifier, etc.
+    estimated_length +=
+        part.prefix.size() + part.value.size() + part.suffix.size() + 3;
+  }
+  result.reserve(estimated_length);
+
+  for (const Part& part : part_list_) {
+    //
+    if (part.type == PartType::kFixed) {
+      // A simple fixed string part.
+      if (part.modifier == Modifier::kNone) {
+        EscapePatternStringAndAppend(part.value, result);
+        continue;
+      }
+
+      // A fixed string, but with a modifier which requires a grouping.
+      // For example, `{foo}?`.
+      result += "{";
+      EscapePatternStringAndAppend(part.value, result);
+      result += "}";
+      AppendModifier(part.modifier, result);
+      continue;
+    }
+
+    // Determine if the part needs a grouping like `{ ... }`.  This is only
+    // necessary when using a non-automatic prefix or any suffix.
+    bool needs_grouping =
+        !part.suffix.empty() ||
+        (!part.prefix.empty() &&
+         (part.prefix.size() != 1 ||
+          options_.prefix_list.find(part.prefix[0]) == std::string::npos));
+
+    // Determine if the part name was custom, like `:foo`, or an
+    // automatically assigned numeric value.  Since custom group
+    // names follow javascript identifier rules the first character
+    // cannot be a digit, so that is all we need to check here.
+    ABSL_ASSERT(!part.name.empty());
+    bool custom_name = !std::isdigit(part.name[0]);
+
+    // This is a full featured part.  We must generate a string that looks
+    // like:
+    //
+    //  { <prefix> <value> <suffix> } <modifier>
+    //
+    // Where the { and } may not be needed.  The <value> will be a regexp,
+    // named group, or wildcard.
+    if (needs_grouping)
+      result += "{";
+
+    EscapePatternStringAndAppend(part.prefix, result);
+
+    if (custom_name) {
+      result += ":";
+      result += part.name;
+    }
+
+    if (part.type == PartType::kRegex) {
+      result += "(";
+      result += part.value;
+      result += ")";
+    } else if (part.type == PartType::kSegmentWildcard) {
+      // We only need to emit a regexp if a custom name was
+      // not specified.  A custom name like `:foo` gets the
+      // kSegmentWildcard type automatically.
+      if (!custom_name) {
+        result += "(";
+        result += segment_wildcard_regex_;
+        result += ")";
+      }
+    } else if (part.type == PartType::kFullWildcard) {
+      // We can only use the `*` wildcard card if the automatic
+      // numeric name is used for the group.  A custom name
+      // requires the regexp `(.*)` explicitly.
+      if (!custom_name) {
+        result += "*";
+      } else {
+        result += "(";
+        result += kFullWildcardRegex;
+        result += ")";
+      }
+    }
+
+    EscapePatternStringAndAppend(part.suffix, result);
+
+    if (needs_grouping)
+      result += "}";
+
+    if (part.modifier != Modifier::kNone)
+      AppendModifier(part.modifier, result);
+  }
+
+  return result;
+}
+
 // The following code is a translation from the path-to-regexp typescript at:
 //
 //  https://github.com/pillarjs/path-to-regexp/blob/125c43e6481f68cc771a5af22b914acdb8c5ba1f/src/index.ts#L532-L596
@@ -114,10 +215,10 @@
     //
     if (part.type == PartType::kFixed) {
       if (part.modifier == Modifier::kNone) {
-        EscapeStringAndAppend(part.value, result);
+        EscapeRegexpStringAndAppend(part.value, result);
       } else {
         result += "(?:";
-        EscapeStringAndAppend(part.value, result);
+        EscapeRegexpStringAndAppend(part.value, result);
         result += ")";
         AppendModifier(part.modifier, result);
       }
@@ -161,9 +262,9 @@
     if (part.modifier == Modifier::kNone ||
         part.modifier == Modifier::kOptional) {
       result += "(?:";
-      EscapeStringAndAppend(part.prefix, result);
+      EscapeRegexpStringAndAppend(part.prefix, result);
       absl::StrAppendFormat(&result, "(%s)", regex_value);
-      EscapeStringAndAppend(part.suffix, result);
+      EscapeRegexpStringAndAppend(part.suffix, result);
       result += ")";
       AppendModifier(part.modifier, result);
       continue;
@@ -180,12 +281,12 @@
     //  (?:<prefix>((?:<regex-value>)(?:<suffix><prefix>(?:<regex-value>))*)<suffix>)?
     //
     result += "(?:";
-    EscapeStringAndAppend(part.prefix, result);
+    EscapeRegexpStringAndAppend(part.prefix, result);
     absl::StrAppendFormat(&result, "((?:%s)(?:", regex_value);
-    EscapeStringAndAppend(part.suffix, result);
-    EscapeStringAndAppend(part.prefix, result);
+    EscapeRegexpStringAndAppend(part.suffix, result);
+    EscapeRegexpStringAndAppend(part.prefix, result);
     absl::StrAppendFormat(&result, "(?:%s))*)", regex_value);
-    EscapeStringAndAppend(part.suffix, result);
+    EscapeRegexpStringAndAppend(part.suffix, result);
     result += ")";
     if (part.modifier == Modifier::kZeroOrMore)
       result += "?";
@@ -283,10 +384,11 @@
     if (part.type == PartType::kFixed) {
       if (part.modifier == Modifier::kNone) {
         // <escaped-fixed-value>
-        result += EscapedLength(part.value);
+        result += EscapedRegexpStringLength(part.value);
       } else {
         // (?:<escaped-fixed-value>)<modifier>
-        result += EscapedLength(part.value) + 4 + ModifierLength(part.modifier);
+        result += EscapedRegexpStringLength(part.value) + 4 +
+                  ModifierLength(part.modifier);
       }
       continue;
     }
@@ -303,8 +405,8 @@
       continue;
     }
 
-    size_t prefix_length = EscapedLength(part.prefix);
-    size_t suffix_length = EscapedLength(part.suffix);
+    size_t prefix_length = EscapedRegexpStringLength(part.prefix);
+    size_t suffix_length = EscapedRegexpStringLength(part.suffix);
 
     if (part.modifier == Modifier::kNone ||
         part.modifier == Modifier::kOptional) {
@@ -362,22 +464,22 @@
 
 void Pattern::AppendDelimiterList(std::string& append_target) const {
   append_target += "[";
-  EscapeStringAndAppend(options_.delimiter_list, append_target);
+  EscapeRegexpStringAndAppend(options_.delimiter_list, append_target);
   append_target += "]";
 }
 
 size_t Pattern::DelimiterListLength() const {
-  return EscapedLength(options_.delimiter_list) + 2;
+  return EscapedRegexpStringLength(options_.delimiter_list) + 2;
 }
 
 void Pattern::AppendEndsWith(std::string& append_target) const {
   append_target += "[";
-  EscapeStringAndAppend(options_.ends_with, append_target);
+  EscapeRegexpStringAndAppend(options_.ends_with, append_target);
   append_target += "]|$";
 }
 
 size_t Pattern::EndsWithLength() const {
-  return EscapedLength(options_.ends_with) + 4;
+  return EscapedRegexpStringLength(options_.ends_with) + 4;
 }
 
 }  // namespace liburlpattern
diff --git a/third_party/liburlpattern/pattern.h b/third_party/liburlpattern/pattern.h
index 22127b5..692f419 100644
--- a/third_party/liburlpattern/pattern.h
+++ b/third_party/liburlpattern/pattern.h
@@ -106,6 +106,15 @@
           Options options,
           std::string segment_wildcard_regex);
 
+  // Generate a canonical string for the parsed pattern.  This may result
+  // in a value different from the pattern string originally passed to
+  // Parse().  For example, no-op syntax like `{bar}` will be simplified to
+  // `bar`.  In addition, the generated string will include any changes mad
+  // by EncodingCallback hooks.  Finally, regular expressions equivalent to
+  // `*` and named group default matching will be simplified; e.g. `(.*)`
+  // will become just `*`.
+  std::string GeneratePatternString() const;
+
   // Generate an ECMA-262 regular expression string that is equivalent to this
   // pattern.  A vector of strings can be optionally passed to |name_list_out|
   // to be populated with the list of group names.  These correspond
diff --git a/third_party/liburlpattern/pattern_unittest.cc b/third_party/liburlpattern/pattern_unittest.cc
index 68afbbc0..a6f4b9e 100644
--- a/third_party/liburlpattern/pattern_unittest.cc
+++ b/third_party/liburlpattern/pattern_unittest.cc
@@ -6,15 +6,21 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/liburlpattern/parse.h"
 
+namespace {
+
+absl::StatusOr<std::string> PassThrough(absl::string_view input) {
+  return std::string(input);
+}
+
+}  // namespace
+
 namespace liburlpattern {
 
 void RunRegexTest(absl::string_view input,
                   absl::string_view expected_regex,
                   std::vector<std::string> expected_name_list,
                   Options options = Options()) {
-  auto result = Parse(
-      input, [](absl::string_view input) { return std::string(input); },
-      options);
+  auto result = Parse(input, PassThrough, options);
   ASSERT_TRUE(result.ok());
   auto& pattern = result.value();
   std::vector<std::string> name_list;
@@ -182,4 +188,134 @@
                {"bar"}, {.end = false, .ends_with = "#"});
 }
 
+void RunPatternStringTest(absl::string_view input,
+                          absl::string_view expected_pattern_string) {
+  auto result = Parse(input, PassThrough);
+  ASSERT_TRUE(result.ok());
+  auto& pattern = result.value();
+  std::string pattern_string = pattern.GeneratePatternString();
+  EXPECT_EQ(pattern_string, expected_pattern_string);
+
+  // The computed pattern string should be valid and parse correctly.
+  auto result2 = Parse(pattern_string, PassThrough);
+  EXPECT_TRUE(result.ok());
+
+  // The second Pattern object may or may not be identical to the first
+  // due to normalization.  For example, stripping the unnecessary grouping
+  // from a `{foo}` term.
+
+  // Computing a second pattern string should result in an identical
+  // value, however.
+  std::string pattern_string2 = result2.value().GeneratePatternString();
+  EXPECT_EQ(pattern_string2, pattern_string);
+}
+
+TEST(PatternStringTest, Fixed) {
+  RunPatternStringTest("/foo/bar", "/foo/bar");
+}
+
+TEST(PatternStringTest, Group) {
+  RunPatternStringTest("/foo/{bar}", "/foo/bar");
+}
+
+TEST(PatternStringTest, GroupWithRegexp) {
+  RunPatternStringTest("/foo/{(bar)}", "/foo/(bar)");
+}
+
+TEST(PatternStringTest, GroupWithPrefixAndRegexp) {
+  RunPatternStringTest("/foo/{b(ar)}", "/foo/{b(ar)}");
+}
+
+TEST(PatternStringTest, GroupWithDefaultPrefixAndRegexp) {
+  RunPatternStringTest("/foo{/(bar)}", "/foo/(bar)");
+}
+
+TEST(PatternStringTest, GroupWithRegexpAndSuffix) {
+  RunPatternStringTest("/foo/{(ba)r}", "/foo/{(ba)r}");
+}
+
+TEST(PatternStringTest, GroupWithDefaultPrefixRegexpAndSuffix) {
+  RunPatternStringTest("/foo{/(ba)r}", "/foo{/(ba)r}");
+}
+
+TEST(PatternStringTest, GroupWithQuestionModifier) {
+  RunPatternStringTest("/foo/{bar}?", "/foo/{bar}?");
+}
+
+TEST(PatternStringTest, GroupWithStarModifier) {
+  RunPatternStringTest("/foo/{bar}*", "/foo/{bar}*");
+}
+
+TEST(PatternStringTest, GroupWithPlusModifier) {
+  RunPatternStringTest("/foo/{bar}+", "/foo/{bar}+");
+}
+
+TEST(PatternStringTest, NamedGroup) {
+  RunPatternStringTest("/foo/:bar", "/foo/:bar");
+}
+
+TEST(PatternStringTest, NamedGroupWithRegexp) {
+  RunPatternStringTest("/foo/:bar(baz)", "/foo/:bar(baz)");
+}
+
+TEST(PatternStringTest, NamedGroupWithEquivalentRegexp) {
+  RunPatternStringTest("/foo/:bar([^\\/#\\?]+?)", "/foo/:bar");
+}
+
+TEST(PatternStringTest, NamedGroupWithWildcardEquivalentRegexp) {
+  RunPatternStringTest("/foo/:bar(.*)", "/foo/:bar(.*)");
+}
+
+TEST(PatternStringTest, NamedGroupWithQuestionModifier) {
+  RunPatternStringTest("/foo/:bar?", "/foo/:bar?");
+}
+
+TEST(PatternStringTest, NamedGroupWithStarModifier) {
+  RunPatternStringTest("/foo/:bar*", "/foo/:bar*");
+}
+
+TEST(PatternStringTest, NamedGroupWithPlusModifier) {
+  RunPatternStringTest("/foo/:bar+", "/foo/:bar+");
+}
+
+TEST(PatternStringTest, Regexp) {
+  RunPatternStringTest("/foo/(bar)", "/foo/(bar)");
+}
+
+TEST(PatternStringTest, RegexpWithQuestionModifier) {
+  RunPatternStringTest("/foo/(bar)?", "/foo/(bar)?");
+}
+
+TEST(PatternStringTest, RegexpWithStarModifier) {
+  RunPatternStringTest("/foo/(bar)*", "/foo/(bar)*");
+}
+
+TEST(PatternStringTest, RegexpWithPlusModifier) {
+  RunPatternStringTest("/foo/(bar)+", "/foo/(bar)+");
+}
+
+TEST(PatternStringTest, Wildcard) {
+  RunPatternStringTest("/foo/*", "/foo/*");
+}
+
+TEST(PatternStringTest, RegexpWildcardEquivalent) {
+  RunPatternStringTest("/foo/(.*)", "/foo/*");
+}
+
+TEST(PatternStringTest, RegexpEscapedNonPatternChar) {
+  RunPatternStringTest("/foo/\\bar", "/foo/bar");
+}
+
+TEST(PatternStringTest, RegexpEscapedPatternChar) {
+  RunPatternStringTest("/foo/\\:bar", "/foo/\\:bar");
+}
+
+TEST(PatternStringTest, RegexpEscapedPatternCharInPrefix) {
+  RunPatternStringTest("/foo/{\\:bar(foo)}", "/foo/{\\:bar(foo)}");
+}
+
+TEST(PatternStringTest, RegexpEscapedPatternCharInSuffix) {
+  RunPatternStringTest("/foo/{(foo)\\:bar}", "/foo/{(foo)\\:bar}");
+}
+
 }  // namespace liburlpattern
diff --git a/third_party/liburlpattern/utils.cc b/third_party/liburlpattern/utils.cc
index 0242699..c9955e1d 100644
--- a/third_party/liburlpattern/utils.cc
+++ b/third_party/liburlpattern/utils.cc
@@ -8,31 +8,47 @@
 namespace liburlpattern {
 
 namespace {
-constexpr absl::string_view kSpecialCharacters(".+*?=^!:${}()[]|/\\");
-}  // namespace
 
-size_t EscapedLength(absl::string_view input) {
-  size_t count = input.size();
-  for (auto& c : input) {
-    if (kSpecialCharacters.find(c) != std::string::npos)
-      count += 1;
-  }
-  return count;
-}
+constexpr absl::string_view kRegexpSpecialCharacters(".+*?^${}()[]|/\\");
+constexpr absl::string_view kPatternSpecialCharacters("+*?:{}()\\");
 
-void EscapeStringAndAppend(absl::string_view input,
-                           std::string& append_target) {
+void EscapeStringAndAppendInternal(absl::string_view input,
+                                   std::string& append_target,
+                                   absl::string_view special_chars) {
   for (auto& c : input) {
-    if (kSpecialCharacters.find(c) != std::string::npos)
+    if (special_chars.find(c) != std::string::npos)
       append_target += '\\';
     append_target += c;
   }
 }
 
-std::string EscapeString(absl::string_view input) {
+}  // namespace
+
+size_t EscapedRegexpStringLength(absl::string_view input) {
+  size_t count = input.size();
+  for (auto& c : input) {
+    if (kRegexpSpecialCharacters.find(c) != std::string::npos)
+      count += 1;
+  }
+  return count;
+}
+
+void EscapeRegexpStringAndAppend(absl::string_view input,
+                                 std::string& append_target) {
+  return EscapeStringAndAppendInternal(input, append_target,
+                                       kRegexpSpecialCharacters);
+}
+
+void EscapePatternStringAndAppend(absl::string_view input,
+                                  std::string& append_target) {
+  return EscapeStringAndAppendInternal(input, append_target,
+                                       kPatternSpecialCharacters);
+}
+
+std::string EscapeRegexpString(absl::string_view input) {
   std::string result;
-  result.reserve(EscapedLength(input));
-  EscapeStringAndAppend(input, result);
+  result.reserve(EscapedRegexpStringLength(input));
+  EscapeRegexpStringAndAppend(input, result);
   return result;
 }
 
diff --git a/third_party/liburlpattern/utils.h b/third_party/liburlpattern/utils.h
index 581956a..02826b5 100644
--- a/third_party/liburlpattern/utils.h
+++ b/third_party/liburlpattern/utils.h
@@ -18,16 +18,23 @@
 
 // Return the expected length of the value returned by EscapeString().
 COMPONENT_EXPORT(LIBURLPATTERN)
-size_t EscapedLength(absl::string_view input);
+size_t EscapedRegexpStringLength(absl::string_view input);
 
 // Escape an input string so that it may be safely included in a
 // regular expression.
 COMPONENT_EXPORT(LIBURLPATTERN)
-std::string EscapeString(absl::string_view input);
+std::string EscapeRegexpString(absl::string_view input);
 
 // Escape the input string so that it may be safely included in a
 // regular expression and append the result directly to the given target.
-void EscapeStringAndAppend(absl::string_view input, std::string& append_target);
+void EscapeRegexpStringAndAppend(absl::string_view input,
+                                 std::string& append_target);
+
+// Escape a fixed input string so that it may be safely included in a
+// pattern string.  Appends the result directly to the given target.
+COMPONENT_EXPORT(LIBURLPATTERN)
+void EscapePatternStringAndAppend(absl::string_view input,
+                                  std::string& append_target);
 
 }  // namespace liburlpattern
 
diff --git a/third_party/liburlpattern/utils_unittest.cc b/third_party/liburlpattern/utils_unittest.cc
index 60e58c3..1e2f32b9 100644
--- a/third_party/liburlpattern/utils_unittest.cc
+++ b/third_party/liburlpattern/utils_unittest.cc
@@ -7,70 +7,110 @@
 
 namespace liburlpattern {
 
-void RunEscapeStringTest(absl::string_view input, absl::string_view expected) {
-  std::string result = EscapeString(input);
+void RunEscapeRegexpStringTest(absl::string_view input,
+                               absl::string_view expected) {
+  std::string result = EscapeRegexpString(input);
   EXPECT_EQ(result, expected);
-  EXPECT_EQ(EscapedLength(input), result.size());
+  EXPECT_EQ(EscapedRegexpStringLength(input), result.size());
 }
 
-TEST(UtilsTest, EscapeStringDot) {
-  RunEscapeStringTest("index.html", "index\\.html");
+TEST(UtilsTest, EscapeRegexpStringDot) {
+  RunEscapeRegexpStringTest("index.html", "index\\.html");
 }
 
-TEST(UtilsTest, EscapeStringPlus) {
-  RunEscapeStringTest("foo+", "foo\\+");
+TEST(UtilsTest, EscapeRegexpStringPlus) {
+  RunEscapeRegexpStringTest("foo+", "foo\\+");
 }
 
-TEST(UtilsTest, EscapeStringStar) {
-  RunEscapeStringTest("foo*", "foo\\*");
+TEST(UtilsTest, EscapeRegexpStringStar) {
+  RunEscapeRegexpStringTest("foo*", "foo\\*");
 }
 
-TEST(UtilsTest, EscapeStringQuestion) {
-  RunEscapeStringTest("foo?", "foo\\?");
+TEST(UtilsTest, EscapeRegexpStringQuestion) {
+  RunEscapeRegexpStringTest("foo?", "foo\\?");
 }
 
-TEST(UtilsTest, EscapeStringEquals) {
-  RunEscapeStringTest("foo=bar", "foo\\=bar");
+TEST(UtilsTest, EscapeRegexpStringEquals) {
+  RunEscapeRegexpStringTest("foo=bar", "foo=bar");
 }
 
-TEST(UtilsTest, EscapeStringCaret) {
-  RunEscapeStringTest("^foo", "\\^foo");
+TEST(UtilsTest, EscapeRegexpStringCaret) {
+  RunEscapeRegexpStringTest("^foo", "\\^foo");
 }
 
-TEST(UtilsTest, EscapeStringBang) {
-  RunEscapeStringTest("!foo", "\\!foo");
+TEST(UtilsTest, EscapeRegexpStringBang) {
+  RunEscapeRegexpStringTest("!foo", "!foo");
 }
 
-TEST(UtilsTest, EscapeStringColon) {
-  RunEscapeStringTest(":foo", "\\:foo");
+TEST(UtilsTest, EscapeRegexpStringColon) {
+  RunEscapeRegexpStringTest(":foo", ":foo");
 }
 
-TEST(UtilsTest, EscapeStringDollar) {
-  RunEscapeStringTest("foo$", "foo\\$");
+TEST(UtilsTest, EscapeRegexpStringDollar) {
+  RunEscapeRegexpStringTest("foo$", "foo\\$");
 }
 
-TEST(UtilsTest, EscapeStringCurlyBraces) {
-  RunEscapeStringTest("{foo}", "\\{foo\\}");
+TEST(UtilsTest, EscapeRegexpStringCurlyBraces) {
+  RunEscapeRegexpStringTest("{foo}", "\\{foo\\}");
 }
 
-TEST(UtilsTest, EscapeStringParens) {
-  RunEscapeStringTest("(foo)", "\\(foo\\)");
+TEST(UtilsTest, EscapeRegexpStringParens) {
+  RunEscapeRegexpStringTest("(foo)", "\\(foo\\)");
 }
 
-TEST(UtilsTest, EscapeStringSquareBrackets) {
-  RunEscapeStringTest("[foo]", "\\[foo\\]");
+TEST(UtilsTest, EscapeRegexpStringSquareBrackets) {
+  RunEscapeRegexpStringTest("[foo]", "\\[foo\\]");
 }
 
-TEST(UtilsTest, EscapeStringPipe) {
-  RunEscapeStringTest("foo|bar", "foo\\|bar");
+TEST(UtilsTest, EscapeRegexpStringPipe) {
+  RunEscapeRegexpStringTest("foo|bar", "foo\\|bar");
 }
 
-TEST(UtilsTest, EscapeStringSlash) {
-  RunEscapeStringTest("/foo/bar", "\\/foo\\/bar");
+TEST(UtilsTest, EscapeRegexpStringSlash) {
+  RunEscapeRegexpStringTest("/foo/bar", "\\/foo\\/bar");
 }
 
-TEST(UtilsTest, EscapeStringBackslash) {
-  RunEscapeStringTest("\\d", "\\\\d");
+TEST(UtilsTest, EscapeRegexpStringBackslash) {
+  RunEscapeRegexpStringTest("\\d", "\\\\d");
+}
+
+void RunEscapePatternStringTest(absl::string_view input,
+                                absl::string_view expected) {
+  std::string result;
+  EscapePatternStringAndAppend(input, result);
+  EXPECT_EQ(result, expected);
+}
+
+TEST(UtilsTest, EscapePatternStringPlus) {
+  RunEscapePatternStringTest("foo+", "foo\\+");
+}
+
+TEST(UtilsTest, EscapePatternStringStar) {
+  RunEscapePatternStringTest("foo*", "foo\\*");
+}
+
+TEST(UtilsTest, EscapePatternStringQuestion) {
+  RunEscapePatternStringTest("foo?", "foo\\?");
+}
+
+TEST(UtilsTest, EscapePatternStringColon) {
+  RunEscapePatternStringTest("foo:", "foo\\:");
+}
+
+TEST(UtilsTest, EscapePatternStringBraces) {
+  RunEscapePatternStringTest("foo{}", "foo\\{\\}");
+}
+
+TEST(UtilsTest, EscapePatternStringParens) {
+  RunEscapePatternStringTest("foo()", "foo\\(\\)");
+}
+
+TEST(UtilsTest, EscapePatternStringBackslash) {
+  RunEscapePatternStringTest("foo\\", "foo\\\\");
+}
+
+TEST(UtilsTest, EscapePatternStringSlash) {
+  RunEscapePatternStringTest("foo/", "foo/");
 }
 
 }  // namespace liburlpattern
diff --git a/third_party/mozilla/DEPS b/third_party/mozilla/DEPS
index cdb4930..118b753 100644
--- a/third_party/mozilla/DEPS
+++ b/third_party/mozilla/DEPS
@@ -1,3 +1,4 @@
 include_rules = [
+  '+base/mac/scoped_nsobject.h',
   '+url/gurl.h',
 ]
diff --git a/third_party/mozilla/NSPasteboard+Utils.mm b/third_party/mozilla/NSPasteboard+Utils.mm
index 98070cae..e669c44 100644
--- a/third_party/mozilla/NSPasteboard+Utils.mm
+++ b/third_party/mozilla/NSPasteboard+Utils.mm
@@ -40,6 +40,8 @@
 #import "NSURL+Utils.h"
 #import "NSString+Utils.h"
 
+#import "base/mac/scoped_nsobject.h"
+
 NSString* const kCorePasteboardFlavorType_url  = @"CorePasteboardFlavorType 0x75726C20"; // 'url '  url
 NSString* const kCorePasteboardFlavorType_urln = @"CorePasteboardFlavorType 0x75726C6E"; // 'urln'  title
 NSString* const kCorePasteboardFlavorType_urld = @"CorePasteboardFlavorType 0x75726C64"; // 'urld' URL description
@@ -163,7 +165,9 @@
     convertingFilenames:(BOOL)convertFilenames
     convertingTextToURL:(BOOL)convertTextToURL
 {
-  NSArray* types = [self types];
+  // -types returns an ivar that might be invalidated by further manipulation of
+  // NSPasteboard; retain it. https://crbug.com/1016740#c21
+  base::scoped_nsobject<NSArray> types([[self types] retain]);
   NSURL* urlFromNSURL = nil;  // Used below in getting an URL from the NSURLPboardType.
   if ([types containsObject:kWebURLsWithTitlesPboardType]) {
     NSArray* urlAndTitleContainer = [self propertyListForType:kWebURLsWithTitlesPboardType];
diff --git a/third_party/mozilla/README.chromium b/third_party/mozilla/README.chromium
index 9103429e..af92b886 100644
--- a/third_party/mozilla/README.chromium
+++ b/third_party/mozilla/README.chromium
@@ -31,5 +31,7 @@
   modified to accept an additional parameter convertingTextToURL:, which
   indicates whether the string contents of the pasteboard should be
   interpreted as a URL if possible.
+- -[NSPasteboard getURLs:andTitles:convertingFilenames:convertingTextToURL:]
+  was modified to retain the -types array.
 - NSWorkspace+Utils.m was modified to compile on the x86_64 architecture.
 - MOZILLA_EXPORT was added to some constants in NSPasteboard+Utils.h.
diff --git a/tools/android/avd/proto/generic_android30.textpb b/tools/android/avd/proto/generic_android30.textpb
index 9bb890a..79964f2 100644
--- a/tools/android/avd/proto/generic_android30.textpb
+++ b/tools/android/avd/proto/generic_android30.textpb
@@ -6,20 +6,20 @@
 
 emulator_package {
   package_name: "chromium/third_party/android_sdk/public/emulator"
-  version: "lcFZFeb_iFtXXguUl1Bq-NOl9zqYh1urBlxF924akmcC"
+  version: "BeYJuG1ilcWCX2YvYk3EEC5nPZENQv0vkKVlT1aWI4EC" # version:30.4.5
   dest_path: ".emulator_sdk"
 }
 
 system_image_package {
   package_name: "chromium/third_party/android_sdk/public/system-images/android-30/google_apis/x86"
-  version: "VlHrJlRzoBJr_TnKKVh6d22nJ_9lXE6GeVMNPXix5AkC"
+  version: "BAAt_NTZdaRpOj5DInuK5VYR5GqL-orbuH8uCj2Z90IC" # version:9
   dest_path: ".emulator_sdk"
 }
 system_image_name: "system-images;android-30;google_apis;x86"
 
 avd_package {
   package_name: "chromium/third_party/android_sdk/public/avds/android-30/google_apis/x86"
-  version: "Bud8SmWeJxzNJOoetfm0FST9ZBHI2h_J4uUMEasVdV4C"
+  version: "as_f843PKT629y3EIeT8JFyEyTGEV155qyuCC3Zy-eQC"
   dest_path: ".android"
 }
 avd_name: "android_30_google_apis_x86"
diff --git a/tools/android/avd/proto/generic_playstore_android30.textpb b/tools/android/avd/proto/generic_playstore_android30.textpb
index 617eb2a..77395278 100644
--- a/tools/android/avd/proto/generic_playstore_android30.textpb
+++ b/tools/android/avd/proto/generic_playstore_android30.textpb
@@ -6,20 +6,20 @@
 
 emulator_package {
   package_name: "chromium/third_party/android_sdk/public/emulator"
-  version: "lcFZFeb_iFtXXguUl1Bq-NOl9zqYh1urBlxF924akmcC"
+  version: "BeYJuG1ilcWCX2YvYk3EEC5nPZENQv0vkKVlT1aWI4EC" # version:30.4.5
   dest_path: ".emulator_sdk"
 }
 
 system_image_package {
   package_name: "chromium/third_party/android_sdk/public/system-images/android-30/google_apis_playstore/x86"
-  version: "fueHa-G5JHEqRY3uETtXr91GnRZlDW9W03BtTPPrzDsC"
+  version: "cNV2i4K6NcTDm3Pl8LpYzolNS7ZfK_zxWuzAMR8DlnUC" # version:9
   dest_path: ".emulator_sdk"
 }
 system_image_name: "system-images;android-30;google_apis_playstore;x86"
 
 avd_package {
   package_name: "chromium/third_party/android_sdk/public/avds/android-30/google_apis_playstore/x86"
-  version: "c33inxhADKqeNPF45ieyfOvthbHHVOr-OMJDNRkwjKkC"
+  version: "shnebPCM2o_pXzPjewSftA_lDR378PjGpOliF2VztOIC"
   dest_path: ".android"
 }
 avd_name: "android_30_google_apis_playstore_x86"
diff --git a/tools/clang/rewrite_raw_ptr_fields/rewrite-multiple-platforms.sh b/tools/clang/rewrite_raw_ptr_fields/rewrite-multiple-platforms.sh
new file mode 100755
index 0000000..44db803
--- /dev/null
+++ b/tools/clang/rewrite_raw_ptr_fields/rewrite-multiple-platforms.sh
@@ -0,0 +1,160 @@
+#!/bin/bash
+# Copyright 2021 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.
+
+# IMPORTANT! Before running this script you have to run
+# `rm -r ~/scratch && mkdir ~/scratch` first
+#
+#
+# For more fine-grained instructions, see:
+# https://docs.google.com/document/d/1chTvr3fSofQNV_PDPEHRyUgcJCQBgTDOOBriW9gIm9M/edit?ts=5e9549a2#heading=h.fjdnrdg1gcty
+
+set -e  # makes the script quit on any command failure
+
+PLATFORMS="win,android"
+if [ "$1" != "" ]
+then
+  PLATFORMS="$1"
+fi
+
+SCRIPT_PATH=$(realpath $0)
+REWRITER_SRC_DIR=$(dirname $SCRIPT_PATH)
+
+COMPILE_DIRS=.
+EDIT_DIRS=.
+
+# Save llvm-build as it is about to be overwritten.
+mv third_party/llvm-build third_party/llvm-build-upstream
+
+# Build and test the rewriter.
+echo "*** Building the rewriter ***"
+time tools/clang/scripts/build.py \
+    --without-android \
+    --without-fuchsia \
+    --extra-tools rewrite_raw_ptr_fields
+tools/clang/rewrite_raw_ptr_fields/tests/run_all_tests.py
+
+args_for_platform() {
+    case "$1" in
+
+    android)
+        cat <<EOF
+target_os = "android"
+clang_use_chrome_plugins = false
+is_chrome_branded = true
+is_debug = false
+is_official_build = true
+symbol_level = 1
+use_goma = false
+enable_remoting = true
+enable_webview_bundles = true
+ffmpeg_branding = "Chrome"
+proprietary_codecs = true
+EOF
+        ;;
+
+    win)
+        cat <<EOF
+target_os = "win"
+clang_use_chrome_plugins = false
+enable_precompiled_headers = false
+is_chrome_branded = true
+is_debug = false
+is_official_build = true
+symbol_level = 1
+use_goma = false
+chrome_pgo_phase = 0
+EOF
+        ;;
+
+    *)
+        echo "unknown platform"
+        exit 1
+        ;;
+    esac
+}
+
+pre_process() {
+    PLATFORM="$1"
+    OUT_DIR="out/rewrite-$PLATFORM"
+
+    mkdir -p "$OUT_DIR"
+    args_for_platform "$PLATFORM" > "$OUT_DIR/args.gn"
+
+    # Build generated files that a successful compilation depends on.
+    echo "*** Preparing targets for $PLATFORM ***"
+    gn gen $OUT_DIR
+    GEN_H_TARGETS=`ninja -C $OUT_DIR -t targets all | grep '^gen/.*\(\.h\|inc\|css_tokenizer_codepoints.cc\)' | cut -d : -f 1`
+    time ninja -C $OUT_DIR $GEN_H_TARGETS
+
+    TARGET_OS_OPTION=""
+    if [ $PLATFORM = "win" ]; then
+        TARGET_OS_OPTION="--target_os=win"
+    fi
+
+    # A preliminary rewriter run in a special mode that generates a list of fields
+    # to ignore. These fields would likely lead to compiler errors if rewritten.
+    echo "*** Generating the ignore list for $PLATFORM ***"
+    time tools/clang/scripts/run_tool.py \
+        $TARGET_OS_OPTION \
+        --tool rewrite_raw_ptr_fields \
+        --tool-arg=--exclude-paths=$REWRITER_SRC_DIR/manual-paths-to-ignore.txt \
+        --generate-compdb \
+        -p $OUT_DIR \
+        $COMPILE_DIRS > ~/scratch/rewriter-$PLATFORM.out
+    cat ~/scratch/rewriter-$PLATFORM.out >> ~/scratch/rewriter.out
+}
+
+main_rewrite() {
+    PLATFORM=$1
+    OUT_DIR="out/rewrite-${PLATFORM}"
+
+    TARGET_OS_OPTION=""
+    if [ $PLATFORM = "win" ]; then
+        TARGET_OS_OPTION="--target_os=win"
+    fi
+
+    # Main rewrite.
+    echo "*** Running the main rewrite phase for $PLATFORM ***"
+    time tools/clang/scripts/run_tool.py \
+        $TARGET_OS_OPTION \
+        --tool rewrite_raw_ptr_fields \
+        --tool-arg=--exclude-fields=~/scratch/combined-fields-to-ignore.txt \
+        --tool-arg=--exclude-paths=$REWRITER_SRC_DIR/manual-paths-to-ignore.txt \
+        -p $OUT_DIR \
+        $COMPILE_DIRS > ~/scratch/rewriter-$PLATFORM.main.out
+    cat ~/scratch/rewriter-$PLATFORM.main.out >> ~/scratch/rewriter.main.out
+}
+
+for PLATFORM in ${PLATFORMS//,/ }
+do
+    pre_process "$PLATFORM"
+done
+
+cat ~/scratch/rewriter.out \
+    | sed '/^==== BEGIN FIELD FILTERS ====$/,/^==== END FIELD FILTERS ====$/{//!b};d' \
+    | sort | uniq > ~/scratch/automated-fields-to-ignore.txt
+cat ~/scratch/automated-fields-to-ignore.txt \
+    tools/clang/rewrite_raw_ptr_fields/manual-fields-to-ignore.txt \
+    | grep -v "base::FileDescriptorWatcher::Controller::watcher_" \
+    > ~/scratch/combined-fields-to-ignore.txt
+
+for PLATFORM in ${PLATFORMS//,/ }
+do
+    main_rewrite "$PLATFORM"
+done
+
+# Apply edits generated by the main rewrite.
+echo "*** Applying edits ***"
+cat ~/scratch/rewriter.main.out | \
+    tools/clang/scripts/extract_edits.py | \
+    tools/clang/scripts/apply_edits.py -p out/rewrite-win $EDIT_DIRS
+
+# Format sources, as many lines are likely over 80 chars now.
+echo "*** Formatting ***"
+time git cl format
+
+# Restore llvm-build. Without this, your future builds will be painfully slow.
+rm -r -f third_party/llvm-build
+mv third_party/llvm-build-upstream third_party/llvm-build
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index 69ba5b63..fe2d9860 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -38,8 +38,8 @@
 # https://chromium.googlesource.com/chromium/src/+/master/docs/updating_clang.md
 # Reverting problematic clang rolls is safe, though.
 # This is the output of `git describe` and is usable as a commit-ish.
-CLANG_REVISION = 'llvmorg-13-init-3462-gfe5c2c3c'
-CLANG_SUB_REVISION = 2
+CLANG_REVISION = 'llvmorg-13-init-4330-g08a5277a'
+CLANG_SUB_REVISION = 1
 
 PACKAGE_VERSION = '%s-%s' % (CLANG_REVISION, CLANG_SUB_REVISION)
 RELEASE_VERSION = '13.0.0'
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
index cecbbaf..365d429 100644
--- a/tools/gritsettings/resource_ids.spec
+++ b/tools/gritsettings/resource_ids.spec
@@ -316,7 +316,8 @@
    "META": {"sizes": {"includes": [10],}},
    "includes": [2230],
   },
-  "components/sync/driver/resources.grd": {
+  "<(SHARED_INTERMEDIATE_DIR)/components/sync/driver/resources/resources.grd": {
+   "META": {"sizes": {"includes": [30],}},
     "includes": [2240],
   },
   "components/resources/dev_ui_components_resources.grd": {
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index de3b3e70..cc6de42 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -67,6 +67,13 @@
   <int value="2" label="ScrolledMainFrameWithUnacceleratedFixedRootBackground"/>
 </enum>
 
+<enum name="AcceptChEntries">
+  <int value="0" label="no entries"/>
+  <int value="1" label="only valid entries"/>
+  <int value="2" label="only invalid entries"/>
+  <int value="3" label="both valid and invalid entries"/>
+</enum>
+
 <enum name="AccessibilityAndroidAnimationsEnabled">
   <obsolete>
     Removed from code 2020/10.
@@ -48305,6 +48312,12 @@
   <int value="16" label="Cryptohome is corrupted"/>
 </enum>
 
+<enum name="LoginFeatureFlagMappingStatus">
+  <int value="0" label="No switches present in device settings"/>
+  <int value="1" label="All switches mapped successfully"/>
+  <int value="2" label="Unknown or invalid switch found"/>
+</enum>
+
 <enum name="LoginIsKnownUser">
   <int value="0" label="Unknown user"/>
   <int value="1" label="Known user"/>
@@ -61250,6 +61263,7 @@
   <int value="3" label="VM missing"/>
   <int value="4" label="Expired license"/>
   <int value="5" label="Network error"/>
+  <int value="6" label="Insufficient disk space"/>
 </enum>
 
 <enum name="PluginVmSetupFailureReason">
@@ -61373,12 +61387,18 @@
 </enum>
 
 <enum name="PolicyLoadStatus">
+  <obsolete>
+    Removed in M91 since the data is not monitored.
+  </obsolete>
   <int value="0" label="Success"/>
   <int value="1" label="No Policy File"/>
   <int value="2" label="Load Error"/>
 </enum>
 
 <enum name="PolicyValidationStatus">
+  <obsolete>
+    Removed in M91 since the data is not monitored.
+  </obsolete>
   <int value="0" label="OK"/>
   <int value="1" label="Bad Initial Signature"/>
   <int value="2" label="Bad Signature"/>
@@ -78521,6 +78541,9 @@
 </enum>
 
 <enum name="ValidationFailures">
+  <obsolete>
+    Removed in M91 since the data is not monitored.
+  </obsolete>
   <int value="0" label="DBus"/>
   <int value="1" label="Load Key"/>
 </enum>
diff --git a/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml b/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml
index 905696c..c4e776b2 100644
--- a/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml
@@ -215,7 +215,7 @@
 </histogram>
 
 <histogram name="Accessibility.CrosCursorHighlight" enum="BooleanEnabled"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>dmazzoni@chromium.org</owner>
   <owner>chrome-a11y-core@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/android/histograms.xml b/tools/metrics/histograms/histograms_xml/android/histograms.xml
index e0fd9eb..2520973 100644
--- a/tools/metrics/histograms/histograms_xml/android/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/android/histograms.xml
@@ -1614,7 +1614,7 @@
 </histogram>
 
 <histogram name="Android.NativeStartupBridge.LoadFullBrowser"
-    enum="BooleanRequested" expires_after="2021-06-01">
+    enum="BooleanRequested" expires_after="2021-09-12">
   <owner>mheikal@chromium.org</owner>
   <owner>hnakashima@chromium.org</owner>
   <owner>hanxi@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/apps/histograms.xml b/tools/metrics/histograms/histograms_xml/apps/histograms.xml
index 27f220d..19481f1 100644
--- a/tools/metrics/histograms/histograms_xml/apps/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/apps/histograms.xml
@@ -1846,7 +1846,7 @@
 </histogram>
 
 <histogram name="Apps.StateTransition.AnimationSmoothness" units="%"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
 <!-- Name completed by histogram_suffixes
      name="TabletOrClamshellMode" and
      name="EnterOrExitOverview" and
diff --git a/tools/metrics/histograms/histograms_xml/ash/histograms.xml b/tools/metrics/histograms/histograms_xml/ash/histograms.xml
index 881e39f..4188952 100644
--- a/tools/metrics/histograms/histograms_xml/ash/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/ash/histograms.xml
@@ -1400,7 +1400,7 @@
 </histogram>
 
 <histogram name="Ash.NightLight.ScheduleType" enum="AshNightLightScheduleType"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>afakhry@chromium.org</owner>
   <summary>
     The selected Night Light schedule type. Emitted when the user changes the
diff --git a/tools/metrics/histograms/histograms_xml/assistant/histograms.xml b/tools/metrics/histograms/histograms_xml/assistant/histograms.xml
index c631031b..0d75d78 100644
--- a/tools/metrics/histograms/histograms_xml/assistant/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/assistant/histograms.xml
@@ -265,7 +265,7 @@
 </histogram>
 
 <histogram name="QuickAnswers.ActiveImpression.Duration" units="ms"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>llin@google.com</owner>
   <owner>croissant-eng@chromium.org</owner>
   <summary>
@@ -324,7 +324,7 @@
 </histogram>
 
 <histogram name="QuickAnswers.ContextMenu.Close" enum="BooleanClicked"
-    expires_after="2021-09-05">
+    expires_after="2021-09-12">
   <owner>updowndota@google.com</owner>
   <owner>croissant-eng@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/background/histograms.xml b/tools/metrics/histograms/histograms_xml/background/histograms.xml
index d538f00..709c5033 100644
--- a/tools/metrics/histograms/histograms_xml/background/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/background/histograms.xml
@@ -160,7 +160,7 @@
 </histogram>
 
 <histogram name="BackgroundMode.BackgroundApplicationsCount" units="units"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>atwilson@chromium.org</owner>
   <owner>mvanouwerkerk@chromium.org</owner>
   <summary>
@@ -360,7 +360,7 @@
 
 <histogram
     name="BackgroundSync.Registration.OneShot.EventSucceededAtCompletion"
-    enum="BooleanSuccess" expires_after="2021-07-11">
+    enum="BooleanSuccess" expires_after="2021-09-12">
   <owner>nator@chromium.org</owner>
   <owner>rayankans@chromium.org</owner>
   <owner>peter@chromium.org</owner>
@@ -382,7 +382,7 @@
 
 <histogram
     name="BackgroundSync.Registration.OneShot.NumAttemptsForSuccessfulEvent"
-    units="attempts" expires_after="2021-07-11">
+    units="attempts" expires_after="2021-09-12">
   <owner>nator@chromium.org</owner>
   <owner>rayankans@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/blink/histograms.xml b/tools/metrics/histograms/histograms_xml/blink/histograms.xml
index ff0e041d..2fd24b3 100644
--- a/tools/metrics/histograms/histograms_xml/blink/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/blink/histograms.xml
@@ -1197,7 +1197,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.ImageDecoders.IncrementallyDecodedByteSize"
-    units="bytes" expires_after="2021-07-11">
+    units="bytes" expires_after="2021-09-12">
   <owner>mbarowsky@chromium.org</owner>
   <owner>andrescj@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/bluetooth/histograms.xml b/tools/metrics/histograms/histograms_xml/bluetooth/histograms.xml
index 5d10c743..d152a08 100644
--- a/tools/metrics/histograms/histograms_xml/bluetooth/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/bluetooth/histograms.xml
@@ -104,7 +104,7 @@
 </histogram>
 
 <histogram name="Bluetooth.ChromeOS.Pairing.Result" enum="BooleanSuccess"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
 <!-- Name completed by histogram_suffixes name="BluetoothTransportTypes" -->
 
   <owner>hansberry@chromium.org</owner>
@@ -148,7 +148,7 @@
 </histogram>
 
 <histogram name="Bluetooth.ChromeOS.UserInitiatedReconnectionAttempt.Result"
-    enum="BooleanSuccess" expires_after="2021-07-11">
+    enum="BooleanSuccess" expires_after="2021-09-12">
 <!-- Name completed by histogram_suffixes name="BluetoothUISurfaces" -->
 
   <owner>hansberry@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/browser/histograms.xml b/tools/metrics/histograms/histograms_xml/browser/histograms.xml
index 9aa83982..f63cc51 100644
--- a/tools/metrics/histograms/histograms_xml/browser/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/browser/histograms.xml
@@ -491,7 +491,7 @@
 </histogram>
 
 <histogram base="true" name="Browser.Tabs.TabSwitchResult"
-    enum="TabSwitchResult" expires_after="2021-07-11">
+    enum="TabSwitchResult" expires_after="2021-09-12">
 <!-- Name completed by histogram_suffixes name="TabSwitchingType" -->
 
   <owner>fdoray@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml b/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml
index d1d28dbc..717d7e59 100644
--- a/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml
@@ -803,7 +803,7 @@
 </histogram>
 
 <histogram name="ChromeOS.SAML.InSessionPasswordChangeEvent"
-    enum="SamlInSessionPasswordChangeEvent" expires_after="2021-07-11">
+    enum="SamlInSessionPasswordChangeEvent" expires_after="2021-09-12">
   <owner>mslus@chromium.org</owner>
   <owner>rsorokin@chromium.org</owner>
   <summary>
@@ -1305,7 +1305,7 @@
 </histogram>
 
 <histogram name="ChromeOS.SystemTray.FeaturePodCountOnOpen" units="count"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>tengs@chromium.org</owner>
   <owner>amehfooz@chromium.org</owner>
   <summary>
@@ -1351,7 +1351,7 @@
 </histogram>
 
 <histogram name="ChromeOS.SystemTray.NotificationsRemovedByClearAll"
-    units="notifications" expires_after="2021-07-11">
+    units="notifications" expires_after="2021-09-12">
   <owner>tengs@chromium.org</owner>
   <owner>gzadina@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/cros/histograms.xml b/tools/metrics/histograms/histograms_xml/cros/histograms.xml
index 1431dd8..35f73f24 100644
--- a/tools/metrics/histograms/histograms_xml/cros/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/cros/histograms.xml
@@ -84,7 +84,7 @@
 </histogram>
 
 <histogram name="CrosDisksClient.FormatCompletedError"
-    enum="CrosDisksClientFormatError" expires_after="2021-07-11">
+    enum="CrosDisksClientFormatError" expires_after="2021-09-12">
   <owner>austinct@chromium.org</owner>
   <summary>
     The error code of disk format signals received from the Chrome OS cros-disks
diff --git a/tools/metrics/histograms/histograms_xml/cryptohome/histograms.xml b/tools/metrics/histograms/histograms_xml/cryptohome/histograms.xml
index 2e52dbc..808eca4 100644
--- a/tools/metrics/histograms/histograms_xml/cryptohome/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/cryptohome/histograms.xml
@@ -213,7 +213,7 @@
 </histogram>
 
 <histogram name="Cryptohome.Errors" enum="CryptohomeError"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>apronin@chromium.org</owner>
   <owner>cros-hwsec+uma@chromium.org</owner>
   <summary>Cryptohome errors.</summary>
@@ -395,7 +395,7 @@
 </histogram>
 
 <histogram name="Cryptohome.ParallelTasks" units="count"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>zuan@chromium.org</owner>
   <owner>cros-hwsec+uma@chromium.org</owner>
   <summary>
@@ -556,7 +556,7 @@
 </histogram>
 
 <histogram name="Cryptohome.TimeToTakeTpmOwnership" units="ms"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>apronin@chromium.org</owner>
   <owner>cros-hwsec+uma@chromium.org</owner>
   <summary>
@@ -588,7 +588,7 @@
   </summary>
 </histogram>
 
-<histogram name="CryptohomeClient" units="ms" expires_after="2021-07-11">
+<histogram name="CryptohomeClient" units="ms" expires_after="2021-09-12">
   <owner>zuan@chromium.org</owner>
   <owner>cros-hwsec+uma@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/custom_tabs/histograms.xml b/tools/metrics/histograms/histograms_xml/custom_tabs/histograms.xml
index 241a0df..8c0a581 100644
--- a/tools/metrics/histograms/histograms_xml/custom_tabs/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/custom_tabs/histograms.xml
@@ -35,7 +35,7 @@
 </histogram>
 
 <histogram name="CustomTabs.ClientAppId" enum="ClientAppId"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>yusufo@chromium.org</owner>
   <summary>
     Android: AppId declared by the launching application in EXTRA_APPLICATION_ID
@@ -227,7 +227,7 @@
 </histogram>
 
 <histogram name="CustomTabs.ShareOptionLocation" enum="ShareOptionLocation"
-    expires_after="M91">
+    expires_after="M94">
   <owner>sophey@chromium.org</owner>
   <owner>src/components/send_tab_to_self/OWNERS</owner>
   <summary>Records the location of the share option in the Custom Tab.</summary>
diff --git a/tools/metrics/histograms/histograms_xml/data_reduction_proxy/histograms.xml b/tools/metrics/histograms/histograms_xml/data_reduction_proxy/histograms.xml
index 388a672..65517c7 100644
--- a/tools/metrics/histograms/histograms_xml/data_reduction_proxy/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/data_reduction_proxy/histograms.xml
@@ -385,7 +385,7 @@
 </histogram>
 
 <histogram name="DataReductionProxy.StartupState"
-    enum="DataReductionProxyStartupState" expires_after="2021-07-11">
+    enum="DataReductionProxyStartupState" expires_after="2021-09-12">
   <owner>rajendrant@chromium.org</owner>
   <owner>tbansal@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/download/histograms.xml b/tools/metrics/histograms/histograms_xml/download/histograms.xml
index fac7cd03..31665c9 100644
--- a/tools/metrics/histograms/histograms_xml/download/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/download/histograms.xml
@@ -69,7 +69,7 @@
 </histogram>
 
 <histogram name="Download.ContentType.Text" enum="DownloadTextType"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>xingliu@chromium.org</owner>
   <summary>Types of text files that are downloaded.</summary>
 </histogram>
@@ -83,7 +83,7 @@
 </histogram>
 
 <histogram base="true" name="Download.Counts" enum="DownloadCountType"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
 <!-- Name completed by histogram_suffixes name="DownloadSource" -->
 
   <owner>xingliu@chromium.org</owner>
@@ -279,7 +279,7 @@
 </histogram>
 
 <histogram name="Download.IOSDownloadedFileAction" enum="DownloadedFileAction"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>sdefresne@chromium.org</owner>
   <owner>ewannpv@chromium.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/enterprise/histograms.xml b/tools/metrics/histograms/histograms_xml/enterprise/histograms.xml
index 25679e4..199111d8 100644
--- a/tools/metrics/histograms/histograms_xml/enterprise/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/enterprise/histograms.xml
@@ -1511,6 +1511,9 @@
 
 <histogram name="Enterprise.UserCloudPolicyStore.LoadStatus"
     enum="PolicyLoadStatus" expires_after="M77">
+  <obsolete>
+    Removed in M91 since the data is not monitored.
+  </obsolete>
   <owner>atwilson@chromium.org</owner>
   <summary>
     Result of the attempted policy load during profile initialization.
@@ -1519,6 +1522,9 @@
 
 <histogram name="Enterprise.UserCloudPolicyStore.LoadValidationStatus"
     enum="PolicyValidationStatus" expires_after="M77">
+  <obsolete>
+    Removed in M91 since the data is not monitored.
+  </obsolete>
   <owner>atwilson@chromium.org</owner>
   <summary>
     Result of validating the policy that has just been loaded from disk.
@@ -1527,6 +1533,9 @@
 
 <histogram name="Enterprise.UserCloudPolicyStore.StoreValidationStatus"
     enum="PolicyValidationStatus" expires_after="M77">
+  <obsolete>
+    Removed in M91 since the data is not monitored.
+  </obsolete>
   <owner>atwilson@chromium.org</owner>
   <summary>
     Result of validating the policy sent down from the server, before writing to
@@ -1613,12 +1622,18 @@
 
 <histogram name="Enterprise.UserPolicyValidationFailure"
     enum="ValidationFailures" expires_after="M85">
+  <obsolete>
+    Removed in M91 since the data is not monitored.
+  </obsolete>
   <owner>mnissler@chromium.org</owner>
   <summary>Source of policy validation errors on Chrome OS.</summary>
 </histogram>
 
 <histogram name="Enterprise.UserPolicyValidationLoadStatus"
     enum="PolicyValidationStatus" expires_after="M77">
+  <obsolete>
+    Removed in M91 since the data is not monitored.
+  </obsolete>
   <owner>mnissler@chromium.org</owner>
   <summary>
     Validation result when loading user policy from the policy store.
@@ -1627,6 +1642,9 @@
 
 <histogram name="Enterprise.UserPolicyValidationStoreStatus"
     enum="PolicyValidationStatus" expires_after="M77">
+  <obsolete>
+    Removed in M91 since the data is not monitored.
+  </obsolete>
   <owner>mnissler@chromium.org</owner>
   <summary>
     Validation result when writing user policy to the policy store.
diff --git a/tools/metrics/histograms/histograms_xml/event/histograms.xml b/tools/metrics/histograms/histograms_xml/event/histograms.xml
index 35d18bc3..1fc651f2 100644
--- a/tools/metrics/histograms/histograms_xml/event/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/event/histograms.xml
@@ -281,7 +281,7 @@
 </histogram>
 
 <histogram name="Event.Latency.EndToEnd.KeyPress" units="microseconds"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>flackr@chromium.org</owner>
   <owner>input-dev@chromium.org</owner>
   <summary>
@@ -344,7 +344,7 @@
 </histogram>
 
 <histogram name="Event.Latency.HitTest" units="microseconds"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>schenney@chromium.org</owner>
   <owner>paint-dev@chromium.org</owner>
   <summary>
@@ -363,7 +363,7 @@
 </histogram>
 
 <histogram name="Event.Latency.HitTestRecursive" units="microseconds"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>schenney@chromium.org</owner>
   <owner>paint-dev@chromium.org</owner>
   <summary>
@@ -577,7 +577,7 @@
 </histogram>
 
 <histogram name="Event.Latency.ScrollBegin.TimeToScrollUpdateSwapBegin2"
-    units="microseconds" expires_after="2021-07-11">
+    units="microseconds" expires_after="2021-09-12">
   <owner>nzolghadr@chromium.org</owner>
   <summary>
     Time between initial creation of a wheel/touch event and start of the frame
@@ -1667,7 +1667,7 @@
 </histogram>
 
 <histogram base="true" name="EventLatency" units="microseconds"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>mohsen@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/extensions/histograms.xml b/tools/metrics/histograms/histograms_xml/extensions/histograms.xml
index d9e7df1..9a5d848 100644
--- a/tools/metrics/histograms/histograms_xml/extensions/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/extensions/histograms.xml
@@ -582,7 +582,7 @@
 </histogram>
 
 <histogram name="Extensions.DeclarativeNetRequest.CreateVerifiedMatcherTime"
-    units="ms" expires_after="2021-07-11">
+    units="ms" expires_after="2021-09-12">
   <owner>karandeepb@chromium.org</owner>
   <owner>extensions-core@chromium.org</owner>
   <summary>
@@ -633,7 +633,7 @@
 </histogram>
 
 <histogram name="Extensions.DeclarativeNetRequest.IsLargeRegexRule"
-    enum="RegexRuleStatus" expires_after="2021-05-30">
+    enum="RegexRuleStatus" expires_after="2021-09-12">
   <owner>karandeepb@chromium.org</owner>
   <owner>extensions-core@chromium.org</owner>
   <summary>
@@ -643,7 +643,7 @@
 </histogram>
 
 <histogram name="Extensions.DeclarativeNetRequest.LoadRulesetResult"
-    enum="LoadRulesetResult" expires_after="2021-07-11">
+    enum="LoadRulesetResult" expires_after="2021-09-12">
   <owner>karandeepb@chromium.org</owner>
   <owner>extensions-core@chromium.org</owner>
   <summary>
@@ -772,7 +772,7 @@
 </histogram>
 
 <histogram name="Extensions.DeclarativeNetRequest.UpdateDynamicRulesStatus"
-    enum="UpdateDynamicRulesStatus" expires_after="2021-06-01">
+    enum="UpdateDynamicRulesStatus" expires_after="2021-09-12">
   <owner>karandeepb@chromium.org</owner>
   <owner>rdevlin.cronin@chromium.org</owner>
   <summary>
@@ -1235,7 +1235,7 @@
 </histogram>
 
 <histogram name="Extensions.ExtensionUninstalled" units="units"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>rdevlin.cronin@chromium.org</owner>
   <owner>extensions-core@chromium.org</owner>
   <summary>An extension has been uninstalled.</summary>
@@ -3507,7 +3507,7 @@
 </histogram>
 
 <histogram name="Extensions.UsedMimeTypeHandler" enum="UsedMimeTypeHandler"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>apotapchuk@chromium.org</owner>
   <owner>anqing@chromium.org</owner>
   <summary>
@@ -3703,7 +3703,7 @@
 </histogram>
 
 <histogram name="Extensions.WebRequestBlockingCount" units="extensions"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>karandeepb@chromium.org</owner>
   <owner>extensions-core@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/gcm/histograms.xml b/tools/metrics/histograms/histograms_xml/gcm/histograms.xml
index 95d6304..a200977 100644
--- a/tools/metrics/histograms/histograms_xml/gcm/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/gcm/histograms.xml
@@ -306,7 +306,7 @@
 </histogram>
 
 <histogram name="GCM.RegistrationRequestStatus"
-    enum="GCMRegistrationRequestStatus" expires_after="2021-07-11">
+    enum="GCMRegistrationRequestStatus" expires_after="2021-09-12">
   <owner>peter@chromium.org</owner>
   <summary>
     Status code of the outcome of a GCM registration request. The Unknown error
diff --git a/tools/metrics/histograms/histograms_xml/gpu/histograms.xml b/tools/metrics/histograms/histograms_xml/gpu/histograms.xml
index 8b12040..8b118a4 100644
--- a/tools/metrics/histograms/histograms_xml/gpu/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/gpu/histograms.xml
@@ -773,7 +773,7 @@
 </histogram>
 
 <histogram name="GPU.GPUProcessLaunchTime" units="ms"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>vmiura@chromium.org</owner>
   <summary>
     Startup time of the GPU process as measured by the GPU process host.
diff --git a/tools/metrics/histograms/histograms_xml/input/histograms.xml b/tools/metrics/histograms/histograms_xml/input/histograms.xml
index 56c8a5d..1e80308 100644
--- a/tools/metrics/histograms/histograms_xml/input/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/input/histograms.xml
@@ -168,7 +168,7 @@
 </histogram>
 
 <histogram name="InputMethod.Assistive.TimeToAccept.Emoji" units="ms"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>myy@google.com</owner>
   <owner>essential-inputs-team@google.com</owner>
   <summary>
@@ -198,7 +198,7 @@
 </histogram>
 
 <histogram name="InputMethod.Assistive.TimeToDismiss.PersonalInfo" units="ms"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>jiwan@google.com</owner>
   <owner>essential-inputs-team@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/instant/histograms.xml b/tools/metrics/histograms/histograms_xml/instant/histograms.xml
index 3616df4b..74b09fd5 100644
--- a/tools/metrics/histograms/histograms_xml/instant/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/instant/histograms.xml
@@ -211,7 +211,7 @@
 </histogram>
 
 <histogram name="InstantTethering.HostScanResult"
-    enum="InstantTethering_HostScanResult" expires_after="2021-07-11">
+    enum="InstantTethering_HostScanResult" expires_after="2021-09-12">
   <owner>hansberry@chromium.org</owner>
   <owner>better-together-dev@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/ios/histograms.xml b/tools/metrics/histograms/histograms_xml/ios/histograms.xml
index 02dac47..2fc7f4e 100644
--- a/tools/metrics/histograms/histograms_xml/ios/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/ios/histograms.xml
@@ -379,7 +379,7 @@
   </summary>
 </histogram>
 
-<histogram name="IOS.Incognito.TimeSpent" units="ms" expires_after="2021-07-11">
+<histogram name="IOS.Incognito.TimeSpent" units="ms" expires_after="2021-09-12">
   <owner>olivierrobin@chromium.org</owner>
   <owner>thegreenfrog@chromium.org</owner>
   <summary>
@@ -471,7 +471,7 @@
 
 <histogram name="IOS.MainThreadFreezeDetection.NotRunningAfterReport"
     enum="IOSMainThreadFreezeDetectionNotRunningAfterReportBlock"
-    expires_after="2021-07-01">
+    expires_after="2021-09-12">
   <owner>justincohen@chromium.org</owner>
   <owner>olivierrobin@chromium.org</owner>
   <summary>
@@ -504,7 +504,7 @@
 </histogram>
 
 <histogram name="IOS.MetricKit.ApplicationResumeTime" units="ms"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>justincohen@chromium.org</owner>
   <owner>olivierrobin@chromium.org</owner>
   <summary>
@@ -524,7 +524,7 @@
 </histogram>
 
 <histogram name="IOS.MetricKit.BackgroundExitData" enum="MetricKitExitData"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>justincohen@chromium.org</owner>
   <owner>olivierrobin@chromium.org</owner>
   <summary>
@@ -619,7 +619,7 @@
 </histogram>
 
 <histogram name="IOS.NTP.Impression" enum="IOSNTPImpression"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>gambard@chromium.org</owner>
   <summary>
     The type of NTP impressions on iOS, split by type of suggestions shown
@@ -848,7 +848,7 @@
   </summary>
 </histogram>
 
-<histogram name="IOS.Snapshots.CacheSize" units="KB" expires_after="2021-07-11">
+<histogram name="IOS.Snapshots.CacheSize" units="KB" expires_after="2021-09-12">
   <owner>ajuma@chromium.org</owner>
   <owner>edchin@chromium.org</owner>
   <summary>
@@ -856,7 +856,7 @@
   </summary>
 </histogram>
 
-<histogram name="IOS.Snapshots.ImageSize" units="KB" expires_after="2021-07-11">
+<histogram name="IOS.Snapshots.ImageSize" units="KB" expires_after="2021-09-12">
   <owner>ajuma@chromium.org</owner>
   <owner>edchin@chromium.org</owner>
   <summary>
@@ -865,7 +865,7 @@
   </summary>
 </histogram>
 
-<histogram name="IOS.Snapshots.PDFSize" units="KB" expires_after="2021-07-11">
+<histogram name="IOS.Snapshots.PDFSize" units="KB" expires_after="2021-09-12">
   <owner>ajuma@chromium.org</owner>
   <owner>edchin@chromium.org</owner>
   <summary>
@@ -875,14 +875,14 @@
 </histogram>
 
 <histogram name="IOS.Spotlight.Action" enum="IOSSpotlightAction"
-    expires_after="2021-05-16">
+    expires_after="2021-09-12">
   <owner>olivierrobin@chromium.org</owner>
   <owner>rohitrao@chromium.org</owner>
   <summary>The Spotlight Action pressed by the user.</summary>
 </histogram>
 
 <histogram name="IOS.Spotlight.Availability" enum="IOSSpotlightAvailability"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>rohitrao@chromium.org</owner>
   <owner>olivierrobin@chromium.org</owner>
   <summary>
@@ -893,14 +893,14 @@
 </histogram>
 
 <histogram name="IOS.Spotlight.BookmarksIndexingDuration" units="ms"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>olivierrobin@chromium.org</owner>
   <owner>rohitrao@chromium.org</owner>
   <summary>Time spent in Spotlight initial indexation of bookmarks.</summary>
 </histogram>
 
 <histogram name="IOS.Spotlight.BookmarksInitialIndexSize" units="units"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>olivierrobin@chromium.org</owner>
   <owner>rohitrao@chromium.org</owner>
   <summary>Number of bookmarks indexed during initial indexation.</summary>
diff --git a/tools/metrics/histograms/histograms_xml/login/histograms.xml b/tools/metrics/histograms/histograms_xml/login/histograms.xml
index 2033d72..6d27adb 100644
--- a/tools/metrics/histograms/histograms_xml/login/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/login/histograms.xml
@@ -204,7 +204,7 @@
 </histogram>
 
 <histogram name="Login.PromptToCompleteLoginTime" units="ms"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>rsorokin@chromium.org</owner>
   <owner>achuith@chromium.org</owner>
   <owner>cros-oac@google.com</owner>
@@ -246,6 +246,19 @@
   <summary>Chrome OS login success reason.</summary>
 </histogram>
 
+<histogram name="Login.SwitchToFeatureFlagMappingStatus"
+    enum="LoginFeatureFlagMappingStatus" expires_after="2021-11-30">
+  <owner>mnissler@chromium.org</owner>
+  <owner>xiyuan@chromium.org</owner>
+  <summary>
+    Tracks whether switches were mapped to feature flags in session_manager for
+    compatibility. session_manager does this and emits UMA samples when
+    encountering old device settings files that still contain feature
+    configuration in command line switch representation. This data will inform
+    the decision when to remove this compatibility code.
+  </summary>
+</histogram>
+
 <histogram name="Login.TokenCheckResponseTime" units="ms"
     expires_after="2021-08-09">
   <owner>rsorokin@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/media/histograms.xml b/tools/metrics/histograms/histograms_xml/media/histograms.xml
index 8794c85a..f08962b 100644
--- a/tools/metrics/histograms/histograms_xml/media/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/media/histograms.xml
@@ -1488,7 +1488,7 @@
 </histogram>
 
 <histogram name="Media.EME.CdmFileIO.FileSizeKBOnFirstRead" units="KB"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>xhwang@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
   <summary>
@@ -1498,7 +1498,7 @@
 </histogram>
 
 <histogram base="true" name="Media.EME.CdmFileIO.TimeTo" units="ms"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>jrummell@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
   <summary>
@@ -1745,7 +1745,7 @@
 </histogram>
 
 <histogram name="Media.EME.OutputProtection" enum="MediaOutputProtectionStatus"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>xhwang@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
   <summary>
@@ -3361,7 +3361,7 @@
 </histogram>
 
 <histogram name="Media.RTCVideoDecoderInitializationLatencyMs" units="ms"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>kron@chromium.org</owner>
   <owner>webrtc-video@google.com</owner>
   <summary>
@@ -3886,7 +3886,7 @@
   </summary>
 </histogram>
 
-<histogram name="Media.Video.Roughness" units="ms" expires_after="2021-07-11">
+<histogram name="Media.Video.Roughness" units="ms" expires_after="2021-09-12">
   <owner>eugene@chromium.org</owner>
   <owner>videostack-eng@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/memory/histograms.xml b/tools/metrics/histograms/histograms_xml/memory/histograms.xml
index e24678f..20b2f98 100644
--- a/tools/metrics/histograms/histograms_xml/memory/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/memory/histograms.xml
@@ -297,7 +297,7 @@
 </histogram>
 
 <histogram name="Memory.Browser.MemoryFootprint.NumLiveOverscroll" units="tabs"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>ajuma@chromium.org</owner>
   <owner>rkgibson@google.com</owner>
   <summary>
@@ -312,7 +312,7 @@
 </histogram>
 
 <histogram name="Memory.Browser.MemoryFootprint.NumOpenTabs" units="tabs"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>ajuma@chromium.org</owner>
   <owner>rkgibson@google.com</owner>
   <summary>
@@ -437,7 +437,7 @@
 </histogram>
 
 <histogram name="Memory.Discardable.LargeAllocationFromFreelist"
-    enum="BooleanLargeAllocationFromFreelist" expires_after="2021-07-11">
+    enum="BooleanLargeAllocationFromFreelist" expires_after="2021-09-12">
   <owner>thiabaud@google.com</owner>
   <owner>lizeb@chromium.org</owner>
   <summary>
@@ -447,7 +447,7 @@
 </histogram>
 
 <histogram name="Memory.Discardable.LockingSuccess"
-    enum="BooleanLockingSuccess" expires_after="2021-07-11">
+    enum="BooleanLockingSuccess" expires_after="2021-09-12">
   <owner>thiabaud@google.com</owner>
   <owner>lizeb@chromium.org</owner>
   <summary>
@@ -1044,7 +1044,7 @@
 </histogram>
 
 <histogram name="Memory.Experimental.Renderer.HighestPrivateMemoryFootprint"
-    units="MB" expires_after="2021-07-11">
+    units="MB" expires_after="2021-09-12">
   <owner>tasak@google.com</owner>
   <owner>bartekn@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/multi_device/histograms.xml b/tools/metrics/histograms/histograms_xml/multi_device/histograms.xml
index c085bf0..39b4cae 100644
--- a/tools/metrics/histograms/histograms_xml/multi_device/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/multi_device/histograms.xml
@@ -86,7 +86,7 @@
 </histogram>
 
 <histogram name="MultiDevice.DeviceSyncService.SetSoftwareFeatureState.Result"
-    enum="BooleanSuccess" expires_after="2021-07-11">
+    enum="BooleanSuccess" expires_after="2021-09-12">
   <owner>vecore@google.com</owner>
   <owner>better-together-dev@google.com</owner>
   <summary>Result of enabling and disabling features for devices.</summary>
diff --git a/tools/metrics/histograms/histograms_xml/navigation/histograms.xml b/tools/metrics/histograms/histograms_xml/navigation/histograms.xml
index d1d7eb0..63a2f7b 100644
--- a/tools/metrics/histograms/histograms_xml/navigation/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/navigation/histograms.xml
@@ -750,7 +750,7 @@
 </histogram>
 
 <histogram name="Navigation.IsSameSiteInstance"
-    enum="NavigationIsSameSiteInstance" expires_after="2021-07-11">
+    enum="NavigationIsSameSiteInstance" expires_after="2021-09-12">
   <owner>arthursonzogni@chromium.org</owner>
   <owner>clamy@chromium.org</owner>
   <owner>nasko@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/net/histograms.xml b/tools/metrics/histograms/histograms_xml/net/histograms.xml
index 620d319..afeff08 100644
--- a/tools/metrics/histograms/histograms_xml/net/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/net/histograms.xml
@@ -21,6 +21,14 @@
 
 <histograms>
 
+<variants name="URLLoaderThrottleStages">
+  <variant name="BeforeWillProcessResponse"/>
+  <variant name="WillOnCompleteWithError"/>
+  <variant name="WillProcessResponse"/>
+  <variant name="WillRedirectRequest"/>
+  <variant name="WillStartRequest"/>
+</variants>
+
 <histogram name="Net.AlternateProtocolBrokenLocation"
     enum="BrokenAlternateProtocolLocation" expires_after="2021-07-27">
   <owner>dschinazi@chromium.org</owner>
@@ -31,7 +39,7 @@
 </histogram>
 
 <histogram name="Net.AlternateProtocolUsage" enum="AlternateProtocolUsage"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>
@@ -41,7 +49,7 @@
 </histogram>
 
 <histogram name="Net.AlternateProtocolUsageGoogle"
-    enum="AlternateProtocolUsage" expires_after="2021-07-11">
+    enum="AlternateProtocolUsage" expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>
@@ -363,7 +371,7 @@
 </histogram>
 
 <histogram name="Net.ConnectionInfo.MainFrame" enum="ConnectionInfo"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>
@@ -1093,7 +1101,7 @@
 </histogram>
 
 <histogram name="Net.DNS.ProbeSequence.ConfigChange.Success.AttemptTime"
-    units="ms" expires_after="2021-07-11">
+    units="ms" expires_after="2021-09-12">
   <owner>ericorth@chromium.org</owner>
   <owner>doh-core@google.com</owner>
   <summary>
@@ -1270,7 +1278,7 @@
 </histogram>
 
 <histogram name="Net.DNS.SecureDnsTask.DnsModeAutomatic.FailureTime" units="ms"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>ericorth@chromium.org</owner>
   <owner>doh-core@google.com</owner>
   <summary>
@@ -1318,7 +1326,7 @@
 </histogram>
 
 <histogram base="true" name="Net.DNS.UI.DropdownSelectionEvent"
-    enum="DohProviderId" expires_after="2021-07-11">
+    enum="DohProviderId" expires_after="2021-09-12">
 <!-- Name completed by histogram_suffixes
    name="DnsDropdownSelectionEvent" -->
 
@@ -2176,7 +2184,7 @@
 </histogram>
 
 <histogram name="Net.QuicActiveSessions" units="units"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -2234,7 +2242,7 @@
 </histogram>
 
 <histogram name="Net.QuicConnection.WritePacketStatus" enum="QuicWriteStatus"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>wub@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -2244,7 +2252,7 @@
 </histogram>
 
 <histogram name="Net.QuicConnectivityMonitor.NumActiveDegradingSessions"
-    units="sessions" expires_after="2021-07-11">
+    units="sessions" expires_after="2021-09-12">
   <owner>zhongyi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -2349,7 +2357,7 @@
 </histogram>
 
 <histogram name="Net.QuicConnectivityMonitor.PercentageActiveDegradingSessions"
-    units="%" expires_after="2021-07-11">
+    units="%" expires_after="2021-09-12">
   <owner>zhongyi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -2385,7 +2393,7 @@
 </histogram>
 
 <histogram name="Net.QuicConnectivityMonitor.SessionDegradedBeforeWriteError"
-    enum="BooleanDetected" expires_after="2021-07-11">
+    enum="BooleanDetected" expires_after="2021-09-12">
   <owner>zhongyi@chromium.org</owner>
   <owner>rockot@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
@@ -2551,7 +2559,7 @@
 </histogram>
 
 <histogram name="Net.QuicNumSentClientHellos" units="units"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>The number of client hello messages sent.</summary>
@@ -2585,6 +2593,30 @@
   </summary>
 </histogram>
 
+<histogram name="Net.QuicSession.AcceptChForOrigin" enum="Boolean"
+    expires_after="M99">
+  <owner>bnc@chromium.org</owner>
+  <owner>src/net/OWNERS</owner>
+  <summary>
+    Records whether the QUIC session receives an Accept-CH entry for the given
+    origin, which GetAcceptChViaAlps() returns. Logged every time
+    QuicHttpStream::GetAcceptChViaAlps() is called, typically once for each
+    request that is served over HTTP/3.
+  </summary>
+</histogram>
+
+<histogram name="Net.QuicSession.AcceptChFrameReceivedViaAlps"
+    enum="AcceptChEntries" expires_after="M99">
+  <owner>bnc@chromium.org</owner>
+  <owner>src/net/OWNERS</owner>
+  <summary>
+    Records both whether there are any valid origin fields and whether there are
+    any invalid ones in the ACCEPT_CH frame. Logged during the TLS handshake of
+    a QUIC connection if ALPS is negotiated, once for every ACCEPT_CH HTTP/3
+    frame received (possibly zero, typically not more than one).
+  </summary>
+</histogram>
+
 <histogram name="Net.QuicSession.ActiveStreamsOnGoAwayAfterPathDegrading"
     units="Streams" expires_after="2021-05-11">
   <owner>renjietang@chromium.org</owner>
@@ -2810,7 +2842,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.ConnectionCloseErrorCodeClient"
-    enum="QuicErrorCodes" expires_after="2021-07-11">
+    enum="QuicErrorCodes" expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -2820,7 +2852,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.ConnectionCloseErrorCodeClientGoogle"
-    enum="QuicErrorCodes" expires_after="2021-07-11">
+    enum="QuicErrorCodes" expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -2830,7 +2862,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.ConnectionCloseErrorCodeServer"
-    enum="QuicErrorCodes" expires_after="2021-07-11">
+    enum="QuicErrorCodes" expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -2840,7 +2872,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.ConnectionCloseErrorCodeServerGoogle"
-    enum="QuicErrorCodes" expires_after="2021-07-11">
+    enum="QuicErrorCodes" expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3010,7 +3042,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.ConnectionTypeFromPeer" enum="AddressFamily"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3048,7 +3080,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.CryptoRetransmitCount.HandshakeConfirmed"
-    units="count" expires_after="2021-07-11">
+    units="count" expires_after="2021-09-12">
   <owner>fayang@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3057,7 +3089,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.CryptoRetransmitCount.HandshakeNotConfirmed"
-    units="count" expires_after="2021-07-11">
+    units="count" expires_after="2021-09-12">
   <owner>fayang@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3106,7 +3138,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.FinchConfigIsValid" enum="Boolean"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3159,7 +3191,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.HandshakeConfirmedTime" units="Milliseconds"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3256,7 +3288,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.InitialRttEsitmateSource"
-    enum="InitialRttEstimateSource" expires_after="2021-07-11">
+    enum="InitialRttEstimateSource" expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3280,7 +3312,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.KeyUpdate.PerConnection2" units="count"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>mattm@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3291,7 +3323,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.KeyUpdate.PotentialPeerKeyUpdateAttemptCount"
-    units="count" expires_after="2021-07-11">
+    units="count" expires_after="2021-09-12">
   <owner>mattm@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3327,7 +3359,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.KeyUpdate.Supported"
-    enum="QuicKeyUpdateSupported" expires_after="2021-07-11">
+    enum="QuicKeyUpdateSupported" expires_after="2021-09-12">
   <owner>mattm@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3397,7 +3429,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.MaxReorderingTimeLongRtt" units="%"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3416,7 +3448,7 @@
   </summary>
 </histogram>
 
-<histogram name="Net.QuicSession.MinRTT" units="ms" expires_after="2021-07-11">
+<histogram name="Net.QuicSession.MinRTT" units="ms" expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3435,7 +3467,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.NumActiveStreamsOnIdleTimeout" units="streams"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>renjietang@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3471,7 +3503,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.NumPendingStreamRequests"
-    units="stream requests" expires_after="2021-07-11">
+    units="stream requests" expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3491,7 +3523,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.NumStreamsWaitingToWriteOnIdleTimeout"
-    units="streams" expires_after="2021-07-11">
+    units="streams" expires_after="2021-09-12">
   <owner>renjietang@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3554,7 +3586,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.PacketGapReceivedNearPing" units="count"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>zhongyi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3575,7 +3607,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.PacketLossRate" units="1/10th Percent"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3585,7 +3617,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.PacketRetransmitsPerMille" units="permille"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3635,7 +3667,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.PortMigration"
-    enum="QuicConnectionMigrationStatus" expires_after="2021-07-11">
+    enum="QuicConnectionMigrationStatus" expires_after="2021-09-12">
   <owner>zhongyi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>The result of a QUIC port migration attempt.</summary>
@@ -3683,7 +3715,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.Pushed" units="count"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3692,7 +3724,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.PushedAndClaimed" units="count"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3701,7 +3733,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.PushedAndUnclaimedBytes" units="count"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>zhongyi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3710,7 +3742,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.PushedBytes" units="count"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>zhongyi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3762,14 +3794,14 @@
 </histogram>
 
 <histogram name="Net.QuicSession.QuicVersion" units="units"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>Version of the QUIC protocol used for this connection.</summary>
 </histogram>
 
 <histogram name="Net.QuicSession.ReadError" enum="NetErrorCodes"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3779,7 +3811,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.ReadError.CurrentNetwork.HandshakeConfirmed"
-    enum="NetErrorCodes" expires_after="2021-07-11">
+    enum="NetErrorCodes" expires_after="2021-09-12">
   <owner>zhongyi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3934,7 +3966,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.SmoothedRTT" units="ms"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -4015,7 +4047,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.StreamCloseErrorCodeServer.HandshakeConfirmed"
-    enum="QuicErrorCodes" expires_after="2021-07-11">
+    enum="QuicErrorCodes" expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -4097,7 +4129,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.TimedOutWithOpenStreams.HasUnackedPackets"
-    units="units" expires_after="2021-07-11">
+    units="units" expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -4157,7 +4189,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.UndecryptablePacketsReceivedWithDecrypter"
-    units="units" expires_after="2021-07-11">
+    units="units" expires_after="2021-09-12">
   <owner>mattm@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -4222,7 +4254,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.VerifyProofTime" units="ms"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -4233,7 +4265,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.WriteError" enum="NetErrorCodes"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -4243,7 +4275,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.WriteError.HandshakeConfirmed"
-    enum="NetErrorCodes" expires_after="2021-07-11">
+    enum="NetErrorCodes" expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -4273,7 +4305,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.ZeroRttReason"
-    enum="SSLHandshakeEarlyDataReason" expires_after="2021-07-11">
+    enum="SSLHandshakeEarlyDataReason" expires_after="2021-09-12">
   <owner>nharper@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -4283,7 +4315,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.ZeroRttReasonGoogle"
-    enum="SSLHandshakeEarlyDataReason" expires_after="2021-07-11">
+    enum="SSLHandshakeEarlyDataReason" expires_after="2021-09-12">
   <owner>renjietang@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -4294,7 +4326,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.ZeroRttReasonNonGoogle"
-    enum="SSLHandshakeEarlyDataReason" expires_after="2021-07-11">
+    enum="SSLHandshakeEarlyDataReason" expires_after="2021-09-12">
   <owner>renjietang@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -4305,7 +4337,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.ZeroRttState" enum="ZeroRttState"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>renjietang@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>Whether 0-RTT was successfully used in the connection.</summary>
@@ -4674,7 +4706,7 @@
 </histogram>
 
 <histogram name="Net.SpdyPushedStreamFate" enum="SpdyPushedStreamFate"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>
@@ -4695,7 +4727,7 @@
 </histogram>
 
 <histogram name="Net.SpdySession.ClosedOnError" enum="NetErrorCodes"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>Net error codes when SpdySession was closed.</summary>
@@ -4790,7 +4822,7 @@
 </histogram>
 
 <histogram name="Net.SpdyStreamsPushedAndClaimedPerSession" units="units"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>
@@ -4970,7 +5002,7 @@
 </histogram>
 
 <histogram name="Net.SSLVersionGoogle" enum="SSLOrQUICVersion"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>davidben@chromium.org</owner>
   <owner>rsleevi@chromium.org</owner>
   <summary>
@@ -5239,6 +5271,28 @@
   </summary>
 </histogram>
 
+<histogram name="Net.URLLoaderThrottleDeferTime.{Stage}" units="ms"
+    expires_after="2022-03-14">
+  <owner>cduvall@chromium.org</owner>
+  <owner>jam@chromium.org</owner>
+  <summary>
+    Measures time a URLLoaderThrottle was deferred when on {Stage}. Logged every
+    time a throttle defers a request.
+  </summary>
+  <token key="Stage" variants="URLLoaderThrottleStages"/>
+</histogram>
+
+<histogram name="Net.URLLoaderThrottleExecutionTime.{Stage}" units="ms"
+    expires_after="2022-03-14">
+  <owner>cduvall@chromium.org</owner>
+  <owner>jam@chromium.org</owner>
+  <summary>
+    Measures time a URLLoaderThrottle took to execute {Stage}. Logged every time
+    a throttle runs.
+  </summary>
+  <token key="Stage" variants="URLLoaderThrottleStages"/>
+</histogram>
+
 <histogram name="Net.URLRequest.ReferrerHasInformativePath"
     enum="BooleanPathIsInformative" expires_after="2021-09-05">
 <!-- Name completed by histogram_suffixes name="ReferrerPolicySameOrigin" -->
diff --git a/tools/metrics/histograms/histograms_xml/new_tab_page/histograms.xml b/tools/metrics/histograms/histograms_xml/new_tab_page/histograms.xml
index 099ba02..0a4bf624 100644
--- a/tools/metrics/histograms/histograms_xml/new_tab_page/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/new_tab_page/histograms.xml
@@ -629,7 +629,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Customized" enum="NTPCustomizedFeatures"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -806,7 +806,7 @@
 </histogram>
 
 <histogram name="NewTabPage.LogoShown" enum="NewTabPageLogoShown"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1067,7 +1067,7 @@
 </histogram>
 
 <histogram name="NewTabPage.NumberOfTiles" units="units"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1095,7 +1095,7 @@
 </histogram>
 
 <histogram name="NewTabPage.OneGoogleBar.ShownTime" units="ms"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1117,7 +1117,7 @@
 
 <histogram
     name="NewTabPage.Promo.EnhancedProtectionPromo.ImpressionUntilAction"
-    units="units" expires_after="2021-07-11">
+    units="units" expires_after="2021-09-12">
   <owner>bdea@chromium.org</owner>
   <owner>chrome-safebrowsing-core@google.com</owner>
   <summary>
@@ -1218,7 +1218,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Promos.ShownTime" units="ms"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1870,7 +1870,7 @@
 </histogram>
 
 <histogram name="NewTabPage.VoiceActions" enum="NewTabPageVoiceAction"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
diff --git a/tools/metrics/histograms/histograms_xml/offline/histograms.xml b/tools/metrics/histograms/histograms_xml/offline/histograms.xml
index 926fe5a..e34f6a8 100644
--- a/tools/metrics/histograms/histograms_xml/offline/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/offline/histograms.xml
@@ -58,7 +58,7 @@
 </histogram>
 
 <histogram name="OfflineIndicator.ConnectivityChanged.DeviceState.Offline"
-    enum="OfflineIndicatorSurfaceState" expires_after="2021-07-11">
+    enum="OfflineIndicatorSurfaceState" expires_after="2021-09-12">
   <owner>curranmax@chromium.org</owner>
   <owner>tbansal@chromium.org</owner>
   <owner>sinansahin@google.com</owner>
diff --git a/tools/metrics/histograms/histograms_xml/others/histograms.xml b/tools/metrics/histograms/histograms_xml/others/histograms.xml
index 4db6811..a7c33687 100644
--- a/tools/metrics/histograms/histograms_xml/others/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/others/histograms.xml
@@ -574,7 +574,7 @@
 </histogram>
 
 <histogram name="AppBanners.DisplayEvent" enum="AppBannersDisplayEvent"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>pjmclachlan@google.com</owner>
   <owner>pcovell@google.com</owner>
   <summary>
@@ -599,7 +599,7 @@
 </histogram>
 
 <histogram name="AppBanners.InstallEvent" enum="AppBannersInstallEvent"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>pjmclachlan@google.com</owner>
   <owner>pcovell@google.com</owner>
   <summary>
@@ -623,7 +623,7 @@
 </histogram>
 
 <histogram name="AppBanners.UserResponse" enum="AppBannersUserResponse"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>dominickn@chromium.org</owner>
   <owner>pjmclachlan@google.com</owner>
   <summary>
@@ -1004,7 +1004,7 @@
 </histogram>
 
 <histogram name="Aura.WebContentsWindowUnOccludedTime" units="ms"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>alemate@chromium.org</owner>
   <owner>oshima@chromium.org</owner>
   <summary>
@@ -2711,7 +2711,7 @@
 </histogram>
 
 <histogram name="Clipboard.Read" enum="ClipboardFormatRead"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>huangdarwin@chromium.org</owner>
   <owner>src/ui/base/clipboard/OWNERS</owner>
   <summary>
@@ -2736,7 +2736,7 @@
 </histogram>
 
 <histogram name="Clipboard.Write" enum="ClipboardFormatWrite"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>huangdarwin@chromium.org</owner>
   <owner>src/ui/base/clipboard/OWNERS</owner>
   <summary>
@@ -2802,7 +2802,7 @@
 </histogram>
 
 <histogram base="true" name="CompositorLatency" units="microseconds"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>sadrul@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
   <summary>
@@ -4356,7 +4356,7 @@
 </histogram>
 
 <histogram name="Display.ParseEdidFailure" enum="ParseEdidFailure"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>sashamcintosh@chromium.org</owner>
   <owner>chromeos-gfx@google.com</owner>
   <summary>
@@ -5608,7 +5608,7 @@
 </histogram>
 
 <histogram name="FamilyUser.SessionEngagement.Weekday" units="Hour of day"
-    expires_after="2021-07-14">
+    expires_after="2021-09-12">
   <owner>agawronska@chromium.org</owner>
   <owner>tobyhuang@chromium.org</owner>
   <owner>xiqiruan@chromium.org</owner>
@@ -5621,7 +5621,7 @@
 </histogram>
 
 <histogram name="FamilyUser.SessionEngagement.Weekend" units="Hour of day"
-    expires_after="2021-07-14">
+    expires_after="2021-09-12">
   <owner>agawronska@chromium.org</owner>
   <owner>tobyhuang@chromium.org</owner>
   <owner>xiqiruan@chromium.org</owner>
@@ -6427,7 +6427,7 @@
 </histogram>
 
 <histogram name="Graphics.Smoothness.Checkerboarding" units="%"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>sadrul@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
   <summary>
@@ -7248,13 +7248,13 @@
   </summary>
 </histogram>
 
-<histogram name="Hyphenation.Open" units="ms" expires_after="2021-07-11">
+<histogram name="Hyphenation.Open" units="ms" expires_after="2021-09-12">
   <owner>kojii@chromium.org</owner>
   <owner>layout-dev@chromium.org</owner>
   <summary>The time it takes to open a hyphenation dictionary.</summary>
 </histogram>
 
-<histogram name="Hyphenation.Open.File" units="ms" expires_after="2021-07-11">
+<histogram name="Hyphenation.Open.File" units="ms" expires_after="2021-09-12">
   <owner>kojii@chromium.org</owner>
   <owner>layout-dev@chromium.org</owner>
   <summary>The time it takes to open a hyphenation dictionary file.</summary>
@@ -7328,7 +7328,7 @@
 </histogram>
 
 <histogram name="ImportantFile.FileCreateError" enum="PlatformFileError"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>grt@chromium.org</owner>
   <owner>xaerox@yandex-team.ru</owner>
   <summary>
@@ -9994,7 +9994,7 @@
 </histogram>
 
 <histogram name="NCN.NetworkOperatorMCCMNC" units="units"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>tbansal@chromium.org</owner>
   <owner>bengr@google.com</owner>
   <summary>
@@ -10188,7 +10188,7 @@
 </histogram>
 
 <histogram name="NQE.RTT.OnECTComputation" units="ms"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>bengr@chromium.org</owner>
   <owner>tbansal@chromium.org</owner>
   <summary>
@@ -10809,7 +10809,7 @@
 </histogram>
 
 <histogram name="PDF.LoadStatus" enum="ChromePDFViewerLoadStatus"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>kmoon@chromium.org</owner>
   <owner>thestig@chromium.org</owner>
   <summary>
@@ -10819,7 +10819,7 @@
   </summary>
 </histogram>
 
-<histogram name="PDF.PageCount" units="pages" expires_after="2021-07-11">
+<histogram name="PDF.PageCount" units="pages" expires_after="2021-09-12">
   <owner>hnakashima@chromium.org</owner>
   <owner>thestig@chromium.org</owner>
   <summary>
@@ -13085,7 +13085,7 @@
 </histogram>
 
 <histogram name="SB2.RemoteCall.CanCheckUrl" enum="BooleanCanCheckUrl"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>vakh@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
@@ -13188,7 +13188,7 @@
 </histogram>
 
 <histogram name="SB2.ResourceTypes2" enum="ContentResourceType2"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>vakh@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
@@ -13719,7 +13719,7 @@
 </histogram>
 
 <histogram name="SharedHighlights.LinkGenerated.Error"
-    enum="LinkGenerationError" expires_after="2021-07-11">
+    enum="LinkGenerationError" expires_after="2021-09-12">
   <owner>gayane@chromium.org</owner>
   <owner>chrome-shared-highlighting@google.com</owner>
   <summary>
@@ -13730,7 +13730,7 @@
 </histogram>
 
 <histogram name="SharedHighlights.LinkGenerated.Error.Iterations"
-    units="iterations" expires_after="2021-07-11">
+    units="iterations" expires_after="2021-09-12">
   <owner>gayane@chromium.org</owner>
   <owner>chrome-shared-highlighting@google.com</owner>
   <summary>
@@ -13750,7 +13750,7 @@
 </histogram>
 
 <histogram name="SharedHighlights.LinkGenerated.Error.TimeToGenerate"
-    units="ms" expires_after="2021-07-11">
+    units="ms" expires_after="2021-09-12">
   <owner>gayane@chromium.org</owner>
   <owner>chrome-shared-highlighting@google.com</owner>
   <summary>
@@ -13760,7 +13760,7 @@
 </histogram>
 
 <histogram name="SharedHighlights.LinkGenerated.Iterations" units="iterations"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>gayane@chromium.org</owner>
   <owner>chrome-shared-highlighting@google.com</owner>
   <summary>
@@ -13770,7 +13770,7 @@
 </histogram>
 
 <histogram name="SharedHighlights.LinkGenerated.ParamLength" units="characters"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>gayane@chromium.org</owner>
   <owner>chrome-shared-highlighting@google.com</owner>
   <summary>
@@ -13782,7 +13782,7 @@
 </histogram>
 
 <histogram name="SharedHighlights.LinkGenerated.SelectionLength"
-    units="characters" expires_after="2021-07-11">
+    units="characters" expires_after="2021-09-12">
   <owner>gayane@chromium.org</owner>
   <owner>chrome-shared-highlighting@google.com</owner>
   <summary>
@@ -13792,7 +13792,7 @@
 </histogram>
 
 <histogram name="SharedHighlights.LinkGenerated.SelectorParameters"
-    enum="TextFragmentAnchorParameters" expires_after="2021-07-11">
+    enum="TextFragmentAnchorParameters" expires_after="2021-09-12">
   <owner>gayane@chromium.org</owner>
   <owner>chrome-shared-highlighting@google.com</owner>
   <summary>
@@ -13802,7 +13802,7 @@
 </histogram>
 
 <histogram name="SharedHighlights.LinkGenerated.TimeToGenerate" units="ms"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>gayane@chromium.org</owner>
   <owner>chrome-shared-highlighting@google.com</owner>
   <summary>
@@ -14151,7 +14151,7 @@
 </histogram>
 
 <histogram name="SiteEngagementService.EngagementScore" units="units"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>calamity@chromium.org</owner>
   <owner>dominickn@chromium.org</owner>
   <summary>
@@ -14173,7 +14173,7 @@
 </histogram>
 
 <histogram name="SiteEngagementService.EngagementType"
-    enum="SiteEngagementServiceEngagementType" expires_after="2021-07-11">
+    enum="SiteEngagementServiceEngagementType" expires_after="2021-09-12">
   <owner>calamity@chromium.org</owner>
   <owner>dominickn@chromium.org</owner>
   <summary>
@@ -14194,7 +14194,7 @@
 </histogram>
 
 <histogram name="SiteEngagementService.MedianEngagement" units="units"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>calamity@chromium.org</owner>
   <owner>dominickn@chromium.org</owner>
   <summary>
@@ -14242,7 +14242,7 @@
 </histogram>
 
 <histogram name="SiteEngagementService.TotalEngagement" units="units"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>calamity@chromium.org</owner>
   <owner>dominickn@chromium.org</owner>
   <summary>
@@ -14253,7 +14253,7 @@
 </histogram>
 
 <histogram name="SiteIsolatedCodeCache.JS.Behaviour"
-    enum="SiteIsolatedCodeCacheJSBehaviour" expires_after="2021-07-11">
+    enum="SiteIsolatedCodeCacheJSBehaviour" expires_after="2021-09-12">
   <owner>mythria@chromium.org</owner>
   <owner>v8-team@google.com</owner>
   <summary>
@@ -14710,7 +14710,7 @@
 </histogram>
 
 <histogram name="SpellCheck.SpellingService.RequestDuration" units="ms"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>yyushkina@google.com</owner>
   <owner>gujen@google.com</owner>
   <owner>chrome-language@google.com</owner>
@@ -15263,7 +15263,7 @@
 </histogram>
 
 <histogram name="SupervisedUsers.ExtensionsMayRequestPermissions"
-    enum="BooleanEnabled" expires_after="2021-07-13">
+    enum="BooleanEnabled" expires_after="2021-09-12">
   <owner>tobyhuang@chromium.org</owner>
   <owner>cros-families@google.com</owner>
   <summary>
@@ -15350,7 +15350,7 @@
 </histogram>
 
 <histogram name="SupervisedUsers.PerAppTimeLimits.BlockedAppsCount"
-    units="Apps" expires_after="2021-07-11">
+    units="Apps" expires_after="2021-09-12">
   <owner>agawronska@chromium.org</owner>
   <owner>yilkal@chromium.org</owner>
   <owner>cros-families@google.com</owner>
@@ -15607,7 +15607,7 @@
 </histogram>
 
 <histogram name="TextFragmentAnchor.LinkOpenSource"
-    enum="TextFragmentLinkOpenSource" expires_after="2021-07-11">
+    enum="TextFragmentLinkOpenSource" expires_after="2021-09-12">
   <owner>gayane@chromium.org</owner>
   <owner>chrome-shared-highlighting@google.com</owner>
   <summary>
@@ -16815,7 +16815,7 @@
 </histogram>
 
 <histogram name="UsageStats.Events" enum="UsageStatsEvents"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>pnoland@chromium.org</owner>
   <owner>fgorski@chromium.org</owner>
   <summary>
@@ -17424,7 +17424,7 @@
   </summary>
 </histogram>
 
-<histogram name="VRSessionVideoCount" units="units" expires_after="2021-07-11">
+<histogram name="VRSessionVideoCount" units="units" expires_after="2021-09-12">
   <owner>alcooper@chromium.org</owner>
   <owner>xr-dev@chromium.org</owner>
   <summary>
@@ -17433,7 +17433,7 @@
   </summary>
 </histogram>
 
-<histogram name="VRSessionVideoTime" units="ms" expires_after="2021-07-11">
+<histogram name="VRSessionVideoTime" units="ms" expires_after="2021-09-12">
   <owner>alcooper@chromium.org</owner>
   <owner>xr-dev@chromium.org</owner>
   <summary>
@@ -17510,7 +17510,7 @@
 </histogram>
 
 <histogram base="true" name="WebApp.Engagement"
-    enum="SiteEngagementServiceEngagementType" expires_after="2021-07-11">
+    enum="SiteEngagementServiceEngagementType" expires_after="2021-09-12">
   <owner>calamity@chromium.org</owner>
   <owner>mgiuca@chromium.org</owner>
   <owner>loyso@chromium.org</owner>
@@ -17585,7 +17585,7 @@
 </histogram>
 
 <histogram name="Webapp.Install.InstallEvent" enum="WebappInstallSource"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>dominickn@chromium.org</owner>
   <owner>loyso@chromium.org</owner>
   <owner>calamity@chromium.org</owner>
@@ -17618,7 +17618,7 @@
 </histogram>
 
 <histogram name="Webapp.InstallResult" enum="WebAppInstallResultCode"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
 <!-- Name completed by histogram_suffixes name="WebAppType" -->
 
   <owner>calamity@chromium.org</owner>
@@ -17789,7 +17789,7 @@
 </histogram>
 
 <histogram name="Webapp.SystemApps.FreshInstallDuration" units="ms"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>calamity@chromium.org</owner>
   <owner>ortuno@chromium.org</owner>
   <summary>
@@ -17823,7 +17823,7 @@
 </histogram>
 
 <histogram name="Webapp.UninstallDialogAction"
-    enum="WebappUninstallDialogAction" expires_after="2021-07-11">
+    enum="WebappUninstallDialogAction" expires_after="2021-09-12">
   <owner>benwells@chromium.org</owner>
   <owner>dominickn@chromium.org</owner>
   <owner>loyso@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/page/histograms.xml b/tools/metrics/histograms/histograms_xml/page/histograms.xml
index b85815cc..f36fce2 100644
--- a/tools/metrics/histograms/histograms_xml/page/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/page/histograms.xml
@@ -762,7 +762,7 @@
 </histogram>
 
 <histogram name="PageLoad.Clients.ThirdParty.Origins.SessionStorageAccess2"
-    units="Count" expires_after="2021-07-11">
+    units="Count" expires_after="2021-09-12">
   <owner>yaoxia@chromium.org</owner>
   <owner>jkarlin@chromium.org</owner>
   <summary>
@@ -1253,7 +1253,7 @@
 
 <histogram
     name="PageLoad.Experimental.NavigationTiming.NavigationStartToFirstRequestStart"
-    units="ms" expires_after="2021-07-11">
+    units="ms" expires_after="2021-09-12">
   <owner>nhiroki@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
@@ -1275,7 +1275,7 @@
 
 <histogram
     name="PageLoad.Experimental.NavigationTiming.NavigationStartToNavigationCommitSent"
-    units="ms" expires_after="2021-07-11">
+    units="ms" expires_after="2021-09-12">
   <owner>nhiroki@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/password/histograms.xml b/tools/metrics/histograms/histograms_xml/password/histograms.xml
index dba07df..af6721ba 100644
--- a/tools/metrics/histograms/histograms_xml/password/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/password/histograms.xml
@@ -22,7 +22,7 @@
 <histograms>
 
 <histogram name="PasswordBubble.CompromisedBubble.CheckClicked"
-    enum="BooleanClicked" expires_after="2021-07-11">
+    enum="BooleanClicked" expires_after="2021-09-12">
   <owner>vasilii@chromium.org</owner>
   <owner>jdoerrie@chromium.org</owner>
   <summary>
@@ -32,7 +32,7 @@
 </histogram>
 
 <histogram name="PasswordBubble.CompromisedBubble.Type"
-    enum="PasswordBubbleFollowupType" expires_after="2021-07-11">
+    enum="PasswordBubbleFollowupType" expires_after="2021-09-12">
   <owner>vasilii@chromium.org</owner>
   <owner>jdoerrie@chromium.org</owner>
   <summary>
@@ -67,7 +67,7 @@
 </histogram>
 
 <histogram name="PasswordGeneration.GeneratedPasswordWasEdited"
-    enum="BooleanGeneratedPasswordWasEdited" expires_after="2021-07-11">
+    enum="BooleanGeneratedPasswordWasEdited" expires_after="2021-09-12">
   <owner>kolos@chromium.org</owner>
   <summary>
     Measures the frequency of user editing of generated passwords. Uploaded once
@@ -105,7 +105,7 @@
 </histogram>
 
 <histogram name="PasswordGeneration.SubmissionEvent"
-    enum="PasswordSubmissionEvent" expires_after="2021-07-11">
+    enum="PasswordSubmissionEvent" expires_after="2021-09-12">
   <owner>jdoerrie@chromium.org</owner>
   <owner>kolos@chromium.org</owner>
   <summary>
@@ -2002,7 +2002,7 @@
 </histogram>
 
 <histogram name="PasswordManager.SavedGaiaPasswordHashCount" units="count"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>vakh@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
@@ -2431,7 +2431,7 @@
 </histogram>
 
 <histogram name="PasswordProtection.ModalWarningDialogLifetime" units="ms"
-    expires_after="2021-07-04">
+    expires_after="2021-09-12">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/platform/histograms.xml b/tools/metrics/histograms/histograms_xml/platform/histograms.xml
index 1de02ece..a4e46a33 100644
--- a/tools/metrics/histograms/histograms_xml/platform/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/platform/histograms.xml
@@ -352,7 +352,7 @@
 </histogram>
 
 <histogram name="Platform.DetachableBase.ROUpdateResult"
-    enum="DetachableBaseROUpdateResult" expires_after="2021-06-02">
+    enum="DetachableBaseROUpdateResult" expires_after="2021-09-12">
   <owner>drinkcat@chromium.org</owner>
   <owner>fshao@chromium.org</owner>
   <owner>chromeos-kukui@google.com</owner>
@@ -474,7 +474,7 @@
 </histogram>
 
 <histogram name="Platform.IntelMaxMicroArchitecture"
-    enum="IntelMaxMicroArchitecture" expires_after="2021-07-13">
+    enum="IntelMaxMicroArchitecture" expires_after="2021-09-12">
   <owner>fbarchard@chromium.org</owner>
   <owner>pwnall@chromium.org</owner>
   <summary>
@@ -583,7 +583,7 @@
   </summary>
 </histogram>
 
-<histogram name="Platform.Meminfo" units="KB" expires_after="2021-09-05">
+<histogram name="Platform.Meminfo" units="KB" expires_after="2021-09-12">
   <owner>hajimehoshi@chromium.org</owner>
   <owner>kouhei@chromium.org</owner>
   <owner>sonnyrao@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/plugin/histograms.xml b/tools/metrics/histograms/histograms_xml/plugin/histograms.xml
index 9b8ec6b..a6da5e9 100644
--- a/tools/metrics/histograms/histograms_xml/plugin/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/plugin/histograms.xml
@@ -125,7 +125,7 @@
 </histogram>
 
 <histogram name="PluginVm.DlcUseResult" enum="PluginVmDlcUseResult"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>kimjae@google.com</owner>
   <owner>timloh@google.com</owner>
   <summary>Recorded at each time PluginVM DLC is installed.</summary>
diff --git a/tools/metrics/histograms/histograms_xml/print/histograms.xml b/tools/metrics/histograms/histograms_xml/print/histograms.xml
index a960038..e82fe01b 100644
--- a/tools/metrics/histograms/histograms_xml/print/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/print/histograms.xml
@@ -129,7 +129,7 @@
 </histogram>
 
 <histogram name="PrintPreview.PrintSettings" enum="PrintSettings"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>thestig@chromium.org</owner>
   <owner>awscreen@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/profile/histograms.xml b/tools/metrics/histograms/histograms_xml/profile/histograms.xml
index 9dec95c4..da9a95a 100644
--- a/tools/metrics/histograms/histograms_xml/profile/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/profile/histograms.xml
@@ -97,7 +97,7 @@
 </histogram>
 
 <histogram name="Profile.BrowserActive.PerProfile" enum="Profile"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>msarda@chromium.org</owner>
   <owner>tangltom@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml b/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml
index 39f0876..db56a08c 100644
--- a/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml
@@ -1045,7 +1045,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.RT.CanCheckDatabase" enum="BooleanEnabled"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
@@ -1091,7 +1091,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.RT.GetToken.Time" units="ms"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
@@ -1102,7 +1102,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.RT.HasTokenFromFetcher" enum="BooleanHasToken"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
@@ -1113,7 +1113,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.RT.HasTokenInRequest" enum="BooleanHasToken"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
@@ -1135,7 +1135,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.RT.IsLookupServiceAvailable"
-    enum="BooleanAvailable" expires_after="2021-07-11">
+    enum="BooleanAvailable" expires_after="2021-09-12">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
@@ -1147,7 +1147,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.RT.IsLookupSuccessful" enum="BooleanSuccess"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
@@ -1200,7 +1200,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.RT.Request.UserPopulation"
-    enum="SafeBrowsingUserPopulation" expires_after="2021-07-11">
+    enum="SafeBrowsingUserPopulation" expires_after="2021-09-12">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/sb_client/histograms.xml b/tools/metrics/histograms/histograms_xml/sb_client/histograms.xml
index 26fa3fc..18feed7b 100644
--- a/tools/metrics/histograms/histograms_xml/sb_client/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/sb_client/histograms.xml
@@ -107,7 +107,7 @@
 </histogram>
 
 <histogram name="SBClientDownload.DownloadRequestNetError" enum="NetErrorCodes"
-    expires_after="2021-07-10">
+    expires_after="2021-09-12">
   <owner>drubery@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <owner>mattm@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/session/histograms.xml b/tools/metrics/histograms/histograms_xml/session/histograms.xml
index bc17c1d..69e6f7d 100644
--- a/tools/metrics/histograms/histograms_xml/session/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/session/histograms.xml
@@ -303,7 +303,7 @@
 </histogram>
 
 <histogram name="Session.TotalDuration.TouchMode" units="times"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>collinbaker@chromium.org</owner>
   <owner>chrome-desktop-ui-sea@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/settings/histograms.xml b/tools/metrics/histograms/histograms_xml/settings/histograms.xml
index 525da23..6493096e 100644
--- a/tools/metrics/histograms/histograms_xml/settings/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/settings/histograms.xml
@@ -376,7 +376,7 @@
 </histogram>
 
 <histogram name="Settings.StartupPageLoadSettings" enum="SessionStartupPref"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>mpearson@chromium.org</owner>
   <owner>ramyan@chromium.org</owner>
   <owner>tiborg@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/signin/histograms.xml b/tools/metrics/histograms/histograms_xml/signin/histograms.xml
index d6b9aa2..760919e9 100644
--- a/tools/metrics/histograms/histograms_xml/signin/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/signin/histograms.xml
@@ -585,7 +585,7 @@
 </histogram>
 
 <histogram name="Signin.IOSLoginMethodAndSyncState"
-    enum="SigninIOSLoginMethodAndSyncState" expires_after="2021-07-04">
+    enum="SigninIOSLoginMethodAndSyncState" expires_after="2021-09-12">
   <owner>jebel@chromium.org</owner>
   <owner>fernandex@chromium.org</owner>
   <owner>msarda@chromium.org</owner>
@@ -717,7 +717,7 @@
 </histogram>
 
 <histogram name="Signin.OAuth2MintToken.ApiCallResult"
-    enum="OAuth2MintTokenApiCallResult" expires_after="M92">
+    enum="OAuth2MintTokenApiCallResult" expires_after="2021-09-12">
   <owner>alexilin@chromium.org</owner>
   <owner>droger@chromium.org</owner>
   <summary>
@@ -1088,7 +1088,7 @@
 
 <histogram
     name="Signin.SSOIdentityListRequest.FetchIdentitiesWithCallback.Duration"
-    units="ms" expires_after="2021-07-11">
+    units="ms" expires_after="2021-09-12">
   <owner>jlebel@chromium.org</owner>
   <owner>fernandex@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
diff --git a/tools/metrics/histograms/histograms_xml/stability/histograms.xml b/tools/metrics/histograms/histograms_xml/stability/histograms.xml
index bfd07f3..f5ecd5e 100644
--- a/tools/metrics/histograms/histograms_xml/stability/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/stability/histograms.xml
@@ -145,7 +145,7 @@
 </histogram>
 
 <histogram name="Stability.BadMessageTerminated.Content"
-    enum="BadMessageReasonContent" expires_after="2021-07-11">
+    enum="BadMessageReasonContent" expires_after="2021-09-12">
   <owner>jam@chromium.org</owner>
   <owner>jamescook@chromium.org</owner>
   <summary>
@@ -312,7 +312,7 @@
 </histogram>
 
 <histogram name="Stability.Experimental.PageLoads" enum="StabilityPageLoadType"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>fdoray@chromium.org</owner>
   <owner>chrome-catan@google.com</owner>
   <summary>
@@ -527,7 +527,7 @@
 </histogram>
 
 <histogram name="Stability.iOS.UTE.MobileSessionAppWillTerminateWasReceived"
-    enum="AppWillTerminateReceived" expires_after="2021-07-11">
+    enum="AppWillTerminateReceived" expires_after="2021-09-12">
   <owner>eugenebut@google.com</owner>
   <owner>olivierrobin@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/startup/histograms.xml b/tools/metrics/histograms/histograms_xml/startup/histograms.xml
index 88bfe259..e480a831 100644
--- a/tools/metrics/histograms/histograms_xml/startup/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/startup/histograms.xml
@@ -56,7 +56,7 @@
 </histogram>
 
 <histogram base="true" name="Startup.Android.Cold.TimeToFirstContentfulPaint"
-    units="ms" expires_after="2021-07-11">
+    units="ms" expires_after="2021-09-12">
   <owner>pasko@chromium.org</owner>
   <owner>alexilin@chromium.org</owner>
   <summary>
@@ -69,7 +69,7 @@
 </histogram>
 
 <histogram base="true" name="Startup.Android.Cold.TimeToFirstNavigationCommit"
-    units="ms" expires_after="2021-07-11">
+    units="ms" expires_after="2021-09-12">
   <owner>pasko@chromium.org</owner>
   <owner>alexilin@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/subresource/histograms.xml b/tools/metrics/histograms/histograms_xml/subresource/histograms.xml
index 0b49e6d..8dfb616 100644
--- a/tools/metrics/histograms/histograms_xml/subresource/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/subresource/histograms.xml
@@ -421,7 +421,7 @@
 </histogram>
 
 <histogram name="SubresourceFilter.PageLoad.ActivationList"
-    enum="ActivationList" expires_after="2021-07-11">
+    enum="ActivationList" expires_after="2021-09-12">
   <owner>alexmt@chromium.org</owner>
   <owner>chrome-ads-histograms@google.com</owner>
   <summary>
@@ -431,7 +431,7 @@
 </histogram>
 
 <histogram name="SubresourceFilter.PageLoad.ActivationState"
-    enum="SubresourceFilterActivationState" expires_after="2021-07-11">
+    enum="SubresourceFilterActivationState" expires_after="2021-09-12">
   <owner>alexmt@chromium.org</owner>
   <owner>chrome-ads-histograms@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/sync/histograms.xml b/tools/metrics/histograms/histograms_xml/sync/histograms.xml
index 0b96c199..25cdd38 100644
--- a/tools/metrics/histograms/histograms_xml/sync/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/sync/histograms.xml
@@ -74,7 +74,7 @@
 </histogram>
 
 <histogram name="Sync.BookmarkGUIDSource2" enum="BookmarkGUIDSource"
-    expires_after="2021-07-13">
+    expires_after="2021-09-12">
   <owner>rushans@google.com</owner>
   <owner>mastiz@chromium.org</owner>
   <summary>
@@ -163,7 +163,7 @@
 </histogram>
 
 <histogram name="Sync.ConfigureDataTypeManagerOption"
-    enum="SyncFeatureOrTransport" expires_after="2021-07-11">
+    enum="SyncFeatureOrTransport" expires_after="2021-09-12">
   <owner>treib@chromium.org</owner>
   <summary>
     Whether the full Sync feature or only the Sync transport layer is being
@@ -916,7 +916,7 @@
 </histogram>
 
 <histogram name="Sync.PostedDataTypeCommitRequest" enum="SyncModelTypes"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>mastiz@chromium.org</owner>
   <owner>jkrcal@chromium.org</owner>
   <summary>
@@ -929,7 +929,7 @@
 </histogram>
 
 <histogram name="Sync.PostedDataTypeGetUpdatesRequest" enum="SyncModelTypes"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>mastiz@chromium.org</owner>
   <owner>jkrcal@chromium.org</owner>
   <summary>
@@ -1108,7 +1108,7 @@
 </histogram>
 
 <histogram name="Sync.StopSource" enum="SyncStopSource"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>treib@chromium.org</owner>
   <owner>mastiz@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/tab/histograms.xml b/tools/metrics/histograms/histograms_xml/tab/histograms.xml
index 583d841..d753f26 100644
--- a/tools/metrics/histograms/histograms_xml/tab/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/tab/histograms.xml
@@ -598,7 +598,7 @@
 </histogram>
 
 <histogram name="TabGroups.CollapsedGroupCountPerLoad" units="groups"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>cyan@chromium.org</owner>
   <owner>chrome-desktop-ui-sea@google.com</owner>
   <summary>
@@ -620,7 +620,7 @@
 </histogram>
 
 <histogram name="TabGroups.TimeSpentCollapsed" units="ms"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>cyan@chromium.org</owner>
   <owner>chrome-desktop-ui-sea@google.com</owner>
   <summary>
@@ -630,7 +630,7 @@
 </histogram>
 
 <histogram name="TabGroups.TimeSpentExpanded" units="ms"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>cyan@chromium.org</owner>
   <owner>chrome-desktop-ui-sea@google.com</owner>
   <summary>
@@ -640,7 +640,7 @@
 </histogram>
 
 <histogram name="TabGroups.UserCustomizedGroupCountPerLoad" units="groups"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>connily@chromium.org</owner>
   <owner>cyan@chromium.org</owner>
   <owner>chrome-desktop-ui-sea@google.com</owner>
@@ -661,7 +661,7 @@
 </histogram>
 
 <histogram name="TabGroups.UserGroupCountPerLoad" units="groups"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>connily@chromium.org</owner>
   <owner>cyan@chromium.org</owner>
   <owner>chrome-desktop-ui-sea@google.com</owner>
@@ -1188,7 +1188,7 @@
 </histogram>
 
 <histogram name="TabManager.TimeSinceTabClosedUntilRestored" units="ms"
-    expires_after="2021-07-13">
+    expires_after="2021-09-12">
   <owner>aebacanu@chromium.org</owner>
   <owner>carlscab@chromium.org</owner>
   <owner>sreejakshetty@chromium.org</owner>
@@ -2640,7 +2640,7 @@
   </summary>
 </histogram>
 
-<histogram name="TabStrip.TimeToSwitch" units="ms" expires_after="2021-07-11">
+<histogram name="TabStrip.TimeToSwitch" units="ms" expires_after="2021-09-12">
   <owner>connily@chromium.org</owner>
   <owner>cyan@chromium.org</owner>
   <owner>chrome-desktop-ui-sea@google.com</owner>
diff --git a/tools/metrics/histograms/histograms_xml/translate/histograms.xml b/tools/metrics/histograms/histograms_xml/translate/histograms.xml
index 5ba769a4..3d5f53e 100644
--- a/tools/metrics/histograms/histograms_xml/translate/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/translate/histograms.xml
@@ -248,7 +248,7 @@
 </histogram>
 
 <histogram name="Translate.HrefHint.PrefsFilterStatus"
-    enum="HrefTranslatePrefsFilterStatus" expires_after="2021-06-23">
+    enum="HrefTranslatePrefsFilterStatus" expires_after="2021-09-12">
   <owner>sclittle@google.com</owner>
   <owner>megjablon@google.com</owner>
   <owner>chrome-language@google.com</owner>
@@ -263,7 +263,7 @@
 </histogram>
 
 <histogram name="Translate.HrefHint.Status" enum="HrefTranslateStatus"
-    expires_after="2021-06-27">
+    expires_after="2021-09-12">
   <owner>megjablon@google.com</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/ukm/histograms.xml b/tools/metrics/histograms/histograms_xml/ukm/histograms.xml
index fc85db5c..f64c038 100644
--- a/tools/metrics/histograms/histograms_xml/ukm/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/ukm/histograms.xml
@@ -80,7 +80,7 @@
 </histogram>
 
 <histogram name="UKM.Entries.Dropped.ByEntryHash" enum="UkmEventNameHash"
-    expires_after="2021-07-04">
+    expires_after="2021-09-12">
   <owner>jwd@chromium.org</owner>
   <owner>ukm-team@google.com</owner>
   <summary>
@@ -135,7 +135,7 @@
 </histogram>
 
 <histogram name="UKM.IOSLog.OnSuccess" units="records"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>rkaplow@chromium.org</owner>
   <summary>
     Number of times when UKM.LogSize.OnSuccess was recorded on iOS. Recorded
diff --git a/tools/metrics/histograms/histograms_xml/uma/histograms.xml b/tools/metrics/histograms/histograms_xml/uma/histograms.xml
index 3feea2cf..4bb8e02 100644
--- a/tools/metrics/histograms/histograms_xml/uma/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/uma/histograms.xml
@@ -172,7 +172,7 @@
 </histogram>
 
 <histogram name="UMA.IsClonedInstall" enum="BooleanCloned"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>asvitkine@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <summary>
@@ -265,7 +265,7 @@
 </histogram>
 
 <histogram name="UMA.LogUpload.Canceled.CellularConstraint"
-    enum="BooleanCanceled" expires_after="2021-07-11">
+    enum="BooleanCanceled" expires_after="2021-09-12">
   <owner>holte@chromium.org</owner>
   <owner>asvitkine@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
@@ -589,7 +589,7 @@
 </histogram>
 
 <histogram name="UMA.TruncatedEvents.UserAction" units="events"
-    expires_after="2021-09-05">
+    expires_after="2021-09-12">
   <owner>rkaplow@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/update_engine/histograms.xml b/tools/metrics/histograms/histograms_xml/update_engine/histograms.xml
index 56d35e6..4dd4448 100644
--- a/tools/metrics/histograms/histograms_xml/update_engine/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/update_engine/histograms.xml
@@ -597,7 +597,7 @@
 
 <histogram
     name="UpdateEngine.SuccessfulUpdate.DurationFromSeenDays.NoTimeRestriction"
-    units="days" expires_after="2021-07-11">
+    units="days" expires_after="2021-09-12">
   <owner>snijhara@google.com</owner>
   <owner>managed-platforms@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/v8/histograms.xml b/tools/metrics/histograms/histograms_xml/v8/histograms.xml
index 6b49711..efe26b5 100644
--- a/tools/metrics/histograms/histograms_xml/v8/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/v8/histograms.xml
@@ -355,7 +355,7 @@
   </summary>
 </histogram>
 
-<histogram name="V8.Execute" units="ms" expires_after="2021-07-11">
+<histogram name="V8.Execute" units="ms" expires_after="2021-09-12">
   <owner>rmcilroy@chromium.org</owner>
   <summary>
     Time spent in JavaScript Execution, including runtime calls, callbacks, and
@@ -807,7 +807,7 @@
 </histogram>
 
 <histogram name="V8.MemoryHeapSampleTotalUsed" units="KB"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>hpayer@chromium.org</owner>
   <summary>
     The total size of live memory used by V8 after each GC in KB.
@@ -882,7 +882,7 @@
 </histogram>
 
 <histogram name="V8.TurboFanOptimizeExecute" units="microseconds"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>neis@chromium.org</owner>
   <owner>mvstanton@chromium.org</owner>
   <summary>
@@ -894,7 +894,7 @@
 </histogram>
 
 <histogram name="V8.TurboFanOptimizeFinalize" units="microseconds"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>neis@chromium.org</owner>
   <owner>mvstanton@chromium.org</owner>
   <summary>
@@ -906,7 +906,7 @@
 </histogram>
 
 <histogram name="V8.TurboFanOptimizeForOnStackReplacementExecute"
-    units="microseconds" expires_after="2021-07-11">
+    units="microseconds" expires_after="2021-09-12">
   <owner>neis@chromium.org</owner>
   <owner>mvstanton@chromium.org</owner>
   <summary>
@@ -919,7 +919,7 @@
 </histogram>
 
 <histogram name="V8.TurboFanOptimizeForOnStackReplacementFinalize"
-    units="microseconds" expires_after="2021-07-11">
+    units="microseconds" expires_after="2021-09-12">
   <owner>neis@chromium.org</owner>
   <owner>mvstanton@chromium.org</owner>
   <summary>
@@ -932,7 +932,7 @@
 </histogram>
 
 <histogram name="V8.TurboFanOptimizeForOnStackReplacementPrepare"
-    units="microseconds" expires_after="2021-07-11">
+    units="microseconds" expires_after="2021-09-12">
   <owner>neis@chromium.org</owner>
   <owner>mvstanton@chromium.org</owner>
   <summary>
@@ -945,7 +945,7 @@
 </histogram>
 
 <histogram name="V8.TurboFanOptimizeForOnStackReplacementTotalTime"
-    units="microseconds" expires_after="2021-07-11">
+    units="microseconds" expires_after="2021-09-12">
   <owner>neis@chromium.org</owner>
   <owner>mvstanton@chromium.org</owner>
   <summary>
@@ -971,7 +971,7 @@
 </histogram>
 
 <histogram name="V8.TurboFanOptimizePrepare" units="microseconds"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>neis@chromium.org</owner>
   <owner>mvstanton@chromium.org</owner>
   <summary>
@@ -983,7 +983,7 @@
 </histogram>
 
 <histogram name="V8.TurboFanOptimizeTotalBackground" units="microseconds"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>neis@chromium.org</owner>
   <owner>mvstanton@chromium.org</owner>
   <summary>
@@ -995,7 +995,7 @@
 </histogram>
 
 <histogram name="V8.TurboFanOptimizeTotalForeground" units="microseconds"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>neis@chromium.org</owner>
   <owner>mvstanton@chromium.org</owner>
   <summary>
@@ -1007,7 +1007,7 @@
 </histogram>
 
 <histogram name="V8.TurboFanOptimizeTotalTime" units="microseconds"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>neis@chromium.org</owner>
   <owner>mvstanton@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/video_tutorials/histograms.xml b/tools/metrics/histograms/histograms_xml/video_tutorials/histograms.xml
index fa9906a..42267b7 100644
--- a/tools/metrics/histograms/histograms_xml/video_tutorials/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/video_tutorials/histograms.xml
@@ -53,7 +53,7 @@
 </histogram>
 
 <histogram name="VideoTutorials.Player.LoadTimeLatency" units="ms"
-    expires_after="2021-07-04">
+    expires_after="2021-09-12">
   <owner>shaktisahu@chromium.org</owner>
   <owner>chrome-upboarding-eng@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/web_apk/histograms.xml b/tools/metrics/histograms/histograms_xml/web_apk/histograms.xml
index a517346..879a44d 100644
--- a/tools/metrics/histograms/histograms_xml/web_apk/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/web_apk/histograms.xml
@@ -70,7 +70,7 @@
 </histogram>
 
 <histogram name="WebApk.Install.GooglePlayInstallResult"
-    enum="WebApkGooglePlayInstallResult" expires_after="2021-07-11">
+    enum="WebApkGooglePlayInstallResult" expires_after="2021-09-12">
   <owner>hartmanng@chromium.org</owner>
   <owner>
     src/chrome/android/java/src/org/chromium/chrome/browser/webapps/OWNERS
diff --git a/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml b/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml
index 0988177..1b911203 100644
--- a/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml
@@ -406,7 +406,7 @@
 </histogram>
 
 <histogram name="WebRTC.Audio.DelayedPacketOutageEventMs" units="ms"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>hlundin@chromium.org</owner>
   <summary>
     Measures the duration of each packet loss concealment (a.k.a. expand) event
@@ -730,7 +730,7 @@
 </histogram>
 
 <histogram name="WebRTC.Audio.ExpandRatePercent" units="%"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>hlundin@chromium.org</owner>
   <summary>
     Measures the expand rate for an incoming WebRTC audio stream. The expand
@@ -934,7 +934,7 @@
 </histogram>
 
 <histogram name="WebRTC.BWE.Probing.TimePerProbeCluster" units="ms"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>jonasolsson@chromium.org</owner>
   <owner>crodbro@chromium.org</owner>
   <summary>
@@ -954,7 +954,7 @@
 </histogram>
 
 <histogram name="WebRTC.BWE.Probing.TotalProbeClustersRequested" units="units"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>jonasolsson@chromium.org</owner>
   <owner>crodbro@chromium.org</owner>
   <summary>
@@ -3585,7 +3585,7 @@
 </histogram>
 
 <histogram name="WebRTC.webkitApiCount" enum="RTCAPIName"
-    expires_after="2021-07-11">
+    expires_after="2021-09-12">
   <owner>guidou@chromium.org</owner>
   <owner>hbos@chromium.org</owner>
   <owner>mcasas@chromium.org</owner>
@@ -3635,7 +3635,7 @@
 </histogram>
 
 <histogram name="WebRtcEventLogging.Upload" enum="WebRtcEventLoggingUploadEnum"
-    expires_after="2021-07-07">
+    expires_after="2021-09-12">
   <owner>eladalon@chromium.org</owner>
   <owner>saeedj@google.com</owner>
   <owner>manj@google.com</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 0704046..5aacacc 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -1,16 +1,16 @@
 {
     "trace_processor_shell": {
         "win": {
-            "hash": "6acd2fb9651bcbb5cb59963637b5d47848fc1476",
-            "remote_path": "perfetto_binaries/trace_processor_shell/win/4973272defb4081572496c831ca3e55c6d12c99a/trace_processor_shell.exe"
+            "hash": "c490b300106dbf909633a65af57bb3ab0e41befb",
+            "remote_path": "perfetto_binaries/trace_processor_shell/win/b0d9de4c263359c154e3ca31af9d40055f9840ad/trace_processor_shell.exe"
         },
         "mac": {
-            "hash": "0a851874f1a85eddc033b36017a0945bd0ca2627",
-            "remote_path": "perfetto_binaries/trace_processor_shell/mac/4973272defb4081572496c831ca3e55c6d12c99a/trace_processor_shell"
+            "hash": "682dc60bd132e8a5f26c37231cb3f221caf20e57",
+            "remote_path": "perfetto_binaries/trace_processor_shell/mac/b0d9de4c263359c154e3ca31af9d40055f9840ad/trace_processor_shell"
         },
         "linux": {
-            "hash": "9f560ce138859ba0808168b69a9376a91bc5bdeb",
-            "remote_path": "perfetto_binaries/trace_processor_shell/linux/0f1ec9f510ae0cc8f800d08e8205017b6a8b8f3b/trace_processor_shell"
+            "hash": "36eed8cb39578770709ab41a3a76444f5c1ec727",
+            "remote_path": "perfetto_binaries/trace_processor_shell/linux/3243c529bd7e2e1f3a0163ccedb680f4e3cdf335/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index 47b2f31..0c3aa96 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -248,6 +248,7 @@
 crbug.com/1150490 [ android-nexus-5x android-webview ] rendering.mobile/microgame_fps [ Skip ]
 crbug.com/1153607 [ android-pixel-2 ] rendering.mobile/many_images [ Skip ]
 crbug.com/1178690 [ android-webview ] rendering.mobile/wsj_mobile_2018 [ Skip ]
+crbug.com/1188586 [ android-pixel-4 android-webview ] rendering.mobile/text_hover_10000_pixels_per_second [ Skip ]
 
 # Benchmark: rasterize_and_record_micro.top_25
 crbug.com/764543 rasterize_and_record_micro.top_25/file://static_top_25/wikipedia.html [ Skip ]
@@ -265,6 +266,9 @@
 crbug.com/948789 [ android-nexus-5x ] startup.mobile/maps_pwa:with_http_cache [ Skip ]
 crbug.com/1030735 [ android-weblayer ] startup.mobile/maps_pwa:with_http_cache [ Skip ]
 crbug.com/1059717 [ android-pixel-2 ] startup.mobile/maps_pwa:with_http_cache [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] startup.mobile/cct:coldish:bbc [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] startup.mobile/intent:coldish:bbc [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] startup.mobile/intent:warm:bbc [ Skip ]
 
 # Benchmark: system_health.common_desktop
 crbug.com/903417 [ mac ] system_health.common_desktop/long_running:tools:gmail-foreground [ Skip ]
@@ -310,6 +314,18 @@
 crbug.com/1185355 [ android-nexus-5x ] system_health.common_mobile/browse:social:pinterest_infinite_scroll:2021 [ Skip ]
 crbug.com/1185355 [ android-go ] system_health.common_mobile/browse:social:pinterest_infinite_scroll:2021 [ Skip ]
 crbug.com/1185355 [ android-go android-webview ] system_health.common_mobile/browse:social:pinterest_infinite_scroll:2021 [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] system_health.common_mobile/background:social:facebook:2019 [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] system_health.common_mobile/background:tools:gmail:2019 [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] system_health.common_mobile/browse:news:cnn:2021 [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] system_health.common_mobile/browse:news:reddit:2019 [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] system_health.common_mobile/browse:social:pinterest_infinite_scroll:2021 [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] system_health.common_mobile/browse:social:tumblr_infinite_scroll:2018 [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] system_health.common_mobile/browse:social:twitter:2019 [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] system_health.common_mobile/browse:tools:maps:2019 [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] system_health.common_mobile/load:media:youtube:2018 [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] system_health.common_mobile/load:news:cnn:2020 [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] system_health.common_mobile/load:tools:gmail:2019 [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] system_health.common_mobile/load:tools:weather:2019 [ Skip ]
 
 # Benchmark: system_health.memory_desktop
 crbug.com/649392 system_health.memory_desktop/play:media:google_play_music [ Skip ]
@@ -401,11 +417,26 @@
 crbug.com/1185355 [ android-nexus-5x ] system_health.common_mobile/browse:social:pinterest_infinite_scroll:2021 [ Skip ]
 crbug.com/1185355 [ android-go ] system_health.common_mobile/browse:social:pinterest_infinite_scroll:2021 [ Skip ]
 crbug.com/1185355 [ android-go android-webview ] system_health.common_mobile/browse:social:pinterest_infinite_scroll:2021 [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] system_health.memory_mobile/background:social:facebook:2019 [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] system_health.memory_mobile/background:tools:gmail:2019 [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] system_health.memory_mobile/browse:news:cnn:2021 [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] system_health.memory_mobile/browse:news:reddit:2019 [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] system_health.memory_mobile/browse:social:pinterest_infinite_scroll:2021 [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] system_health.memory_mobile/browse:social:tumblr_infinite_scroll:2018 [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] system_health.memory_mobile/browse:social:twitter:2019 [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] system_health.memory_mobile/browse:tools:maps:2019 [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] system_health.memory_mobile/load:media:youtube:2018 [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] system_health.memory_mobile/load:news:cnn:2020 [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] system_health.memory_mobile/load:tools:gmail:2019 [ Skip ]
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] system_health.memory_mobile/load:tools:weather:2019 [ Skip ]
 
 # Benchmark: system_health.pcscan
 crbug.com/v8/11180 [ android ] system_health.pcscan/browse:news:cnn:2021 [ Skip ]
 crbug.com/v8/11180 [ desktop ] system_health.pcscan/browse:news:cnn:2021 [ Skip ]
 
+# Benchmark: system_health.weblayer_startup
+crbug.com/1188602 [ android-pixel-4 android-weblayer ] system_health.weblayer_startup/load:chrome:blank [ Skip ]
+
 # Benchmark: tab_switching.typical_25
 crbug.com/747026 [ mac ] tab_switching.typical_25/multitab:misc:typical24 [ Skip ]
 crbug.com/883731 [ win ] tab_switching.typical_25/multitab:misc:typical24 [ Skip ]
diff --git a/ui/base/clipboard/clipboard_test_template.h b/ui/base/clipboard/clipboard_test_template.h
index e18cfa8a..3d9b783 100644
--- a/ui/base/clipboard/clipboard_test_template.h
+++ b/ui/base/clipboard/clipboard_test_template.h
@@ -585,9 +585,7 @@
 
 // Only kN32_SkColorType bitmaps are allowed in the clipboard to prevent
 // surprising buffer overflows due to bits-per-pixel assumptions.
-// TODO(https://crbug.com/1181697): test disabled as it times out on certain
-// bots.
-TYPED_TEST(ClipboardTest, DISABLED_Bitmap_F16_Premul) {
+TYPED_TEST(ClipboardTest, Bitmap_F16_Premul) {
   constexpr F16x4 kRGBAF16Premul = {0x30c5, 0x2d86, 0x2606, 0x3464};
   constexpr U8x4 kRGBAPremul = {0x26, 0x16, 0x06, 0x46};
   EXPECT_DEATH(TestBitmapWrite(&this->clipboard(),
diff --git a/ui/base/ime/composition_text.cc b/ui/base/ime/composition_text.cc
index ab2136e9..1544a3ef 100644
--- a/ui/base/ime/composition_text.cc
+++ b/ui/base/ime/composition_text.cc
@@ -6,12 +6,19 @@
 
 namespace ui {
 
-CompositionText::CompositionText() {
-}
+CompositionText::CompositionText() = default;
 
 CompositionText::CompositionText(const CompositionText& other) = default;
 
-CompositionText::~CompositionText() {
+CompositionText::~CompositionText() = default;
+
+bool CompositionText::operator==(const CompositionText& other) const {
+  return text == other.text && ime_text_spans == other.ime_text_spans &&
+         selection == other.selection;
+}
+
+bool CompositionText::operator!=(const CompositionText& other) const {
+  return !(*this == other);
 }
 
 }  // namespace ui
diff --git a/ui/base/ime/composition_text.h b/ui/base/ime/composition_text.h
index 2bc75f1b..ee047ed 100644
--- a/ui/base/ime/composition_text.h
+++ b/ui/base/ime/composition_text.h
@@ -21,20 +21,8 @@
   CompositionText(const CompositionText& other);
   ~CompositionText();
 
-  bool operator==(const CompositionText& rhs) const {
-    if ((this->text != rhs.text) || (this->selection != rhs.selection) ||
-        (this->ime_text_spans.size() != rhs.ime_text_spans.size()))
-      return false;
-    for (size_t i = 0; i < this->ime_text_spans.size(); ++i) {
-      if (this->ime_text_spans[i] != rhs.ime_text_spans[i])
-        return false;
-    }
-    return true;
-  }
-
-  bool operator!=(const CompositionText& rhs) const {
-    return !(*this == rhs);
-  }
+  bool operator==(const CompositionText& other) const;
+  bool operator!=(const CompositionText& other) const;
 
   // Content of the composition text.
   std::u16string text;
diff --git a/ui/file_manager/file_manager/foreground/js/ui/banners.js b/ui/file_manager/file_manager/foreground/js/ui/banners.js
index 1dddbd4..b46da3b 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/banners.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/banners.js
@@ -297,9 +297,9 @@
    */
   setPhotosWelcomeCounter_(value) {
     this.photosWelcomeCounter_ = value;
-    chrome.storage.local.set({
-      PHOTOS_WELCOME_COUNTER_KEY: value,
-    });
+    const values = {};
+    values[PHOTOS_WELCOME_COUNTER_KEY] = value;
+    chrome.storage.local.set(values);
   }
 
   /**
diff --git a/ui/gl/swap_chain_presenter.cc b/ui/gl/swap_chain_presenter.cc
index bc8f30d0..88cd60c 100644
--- a/ui/gl/swap_chain_presenter.cc
+++ b/ui/gl/swap_chain_presenter.cc
@@ -212,12 +212,12 @@
       is_on_battery_power_(true) {
   if (base::PowerMonitor::IsInitialized()) {
     is_on_battery_power_ = base::PowerMonitor::IsOnBatteryPower();
-    base::PowerMonitor::AddObserver(this);
+    base::PowerMonitor::AddPowerStateObserver(this);
   }
 }
 
 SwapChainPresenter::~SwapChainPresenter() {
-  base::PowerMonitor::RemoveObserver(this);
+  base::PowerMonitor::RemovePowerStateObserver(this);
 }
 
 DXGI_FORMAT SwapChainPresenter::GetSwapChainFormat(
diff --git a/ui/gl/swap_chain_presenter.h b/ui/gl/swap_chain_presenter.h
index 6ecd03e..c93bbca 100644
--- a/ui/gl/swap_chain_presenter.h
+++ b/ui/gl/swap_chain_presenter.h
@@ -24,7 +24,7 @@
 // SwapChainPresenter holds a swap chain, direct composition visuals, and other
 // associated resources for a single overlay layer.  It is updated by calling
 // PresentToSwapChain(), and can update or recreate resources as necessary.
-class SwapChainPresenter : public base::PowerObserver {
+class SwapChainPresenter : public base::PowerStateObserver {
  public:
   SwapChainPresenter(DCLayerTree* layer_tree,
                      HWND window,
@@ -176,7 +176,7 @@
   // decode swap chain.
   void RecordPresentationStatistics();
 
-  // base::PowerObserver
+  // base::PowerStateObserver
   void OnPowerStateChange(bool on_battery_power) override;
 
   // If connected with a power source, let the Intel video processor to do
diff --git a/ui/views/controls/message_box_view.cc b/ui/views/controls/message_box_view.cc
index e2c6095d..644de75a 100644
--- a/ui/views/controls/message_box_view.cc
+++ b/ui/views/controls/message_box_view.cc
@@ -183,10 +183,6 @@
   ResetLayoutManager();
 }
 
-void MessageBoxView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
-  node_data->role = ax::mojom::Role::kAlertDialog;
-}
-
 void MessageBoxView::SetInterRowVerticalSpacing(int spacing) {
   if (inter_row_vertical_spacing_ == spacing)
     return;
@@ -220,8 +216,6 @@
   if (details.child == this && details.is_add) {
     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 b577ebc4..7575fdee 100644
--- a/ui/views/controls/message_box_view.h
+++ b/ui/views/controls/message_box_view.h
@@ -71,9 +71,6 @@
   // Sets the text and the callback of the link. |text| must be non-empty.
   void SetLink(const std::u16string& text, Link::ClickedCallback callback);
 
-  // View:
-  void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
-
   void SetInterRowVerticalSpacing(int spacing);
   void SetMessageWidth(int width);
 
diff --git a/ui/views/corewm/tooltip_aura.cc b/ui/views/corewm/tooltip_aura.cc
index eb9cd6a..542f520 100644
--- a/ui/views/corewm/tooltip_aura.cc
+++ b/ui/views/corewm/tooltip_aura.cc
@@ -267,23 +267,19 @@
 void TooltipAura::Update(aura::Window* window,
                          const std::u16string& tooltip_text,
                          const TooltipPosition& position) {
+  // Hide() must be called before showing the next tooltip.  See also the
+  // comment in Hide().
+  DCHECK(!widget_);
+
   tooltip_window_ = window;
 
-  if (!widget_) {
-    auto new_tooltip_view = std::make_unique<TooltipView>();
-    new_tooltip_view->SetMaxWidth(GetMaxWidth(position.anchor_point));
-    new_tooltip_view->SetText(tooltip_text);
-    CreateTooltipWidget(
-        GetTooltipBounds(new_tooltip_view->GetPreferredSize(), position));
-    widget_->SetTooltipView(std::move(new_tooltip_view));
-    widget_->AddObserver(this);
-  } else {
-    TooltipView* old_tooltip_view = widget_->GetTooltipView();
-    old_tooltip_view->SetMaxWidth(GetMaxWidth(position.anchor_point));
-    old_tooltip_view->SetText(tooltip_text);
-    widget_->SetBounds(
-        GetTooltipBounds(old_tooltip_view->GetPreferredSize(), position));
-  }
+  auto new_tooltip_view = std::make_unique<TooltipView>();
+  new_tooltip_view->SetMaxWidth(GetMaxWidth(position.anchor_point));
+  new_tooltip_view->SetText(tooltip_text);
+  CreateTooltipWidget(
+      GetTooltipBounds(new_tooltip_view->GetPreferredSize(), position));
+  widget_->SetTooltipView(std::move(new_tooltip_view));
+  widget_->AddObserver(this);
 
   ui::NativeTheme* native_theme = widget_->GetNativeTheme();
   auto background_color =
diff --git a/ui/views/test/widget_test.cc b/ui/views/test/widget_test.cc
index 1c42693..c82718ea 100644
--- a/ui/views/test/widget_test.cc
+++ b/ui/views/test/widget_test.cc
@@ -243,16 +243,22 @@
     run_loop_.Quit();
 }
 
-WidgetDestroyedWaiter::WidgetDestroyedWaiter(Widget* widget) {
+WidgetDestroyedWaiter::WidgetDestroyedWaiter(Widget* widget) : widget_(widget) {
   widget->AddObserver(this);
 }
 
+WidgetDestroyedWaiter::~WidgetDestroyedWaiter() {
+  if (widget_)
+    widget_->RemoveObserver(this);
+}
+
 void WidgetDestroyedWaiter::Wait() {
   run_loop_.Run();
 }
 
 void WidgetDestroyedWaiter::OnWidgetDestroyed(Widget* widget) {
   widget->RemoveObserver(this);
+  widget_ = nullptr;
   run_loop_.Quit();
 }
 
diff --git a/ui/views/test/widget_test.h b/ui/views/test/widget_test.h
index 9743c69..f7c4aab1 100644
--- a/ui/views/test/widget_test.h
+++ b/ui/views/test/widget_test.h
@@ -273,6 +273,7 @@
 class WidgetDestroyedWaiter : public WidgetObserver {
  public:
   explicit WidgetDestroyedWaiter(Widget* widget);
+  ~WidgetDestroyedWaiter() override;
 
   // Wait for the widget to be destroyed, or return immediately if it was
   // already destroyed since this object was created.
@@ -282,6 +283,7 @@
   // views::WidgetObserver
   void OnWidgetDestroyed(Widget* widget) override;
 
+  Widget* widget_;
   base::RunLoop run_loop_;
 
   DISALLOW_COPY_AND_ASSIGN(WidgetDestroyedWaiter);
diff --git a/ui/views/widget/widget_delegate.cc b/ui/views/widget/widget_delegate.cc
index d696d3a..0c1be5b 100644
--- a/ui/views/widget/widget_delegate.cc
+++ b/ui/views/widget/widget_delegate.cc
@@ -55,8 +55,13 @@
       non_client_frame_view_factory_(
           base::BindRepeating(&CreateDefaultNonClientFrameView)),
       overlay_view_factory_(base::BindOnce(&CreateDefaultOverlayView)) {}
+
 WidgetDelegate::~WidgetDelegate() {
   CHECK(can_delete_this_) << "A WidgetDelegate must outlive its Widget";
+  if (destructor_ran_) {
+    DCHECK(!*destructor_ran_);
+    *destructor_ran_ = true;
+  }
 }
 
 void WidgetDelegate::SetCanActivate(bool can_activate) {
@@ -220,10 +225,27 @@
 }
 
 void WidgetDelegate::DeleteDelegate() {
-  for (auto&& callback : delete_delegate_callbacks_)
+  bool owned_by_widget = params_.owned_by_widget;
+  ClosureVector delete_callbacks;
+  delete_callbacks.swap(delete_delegate_callbacks_);
+
+  bool destructor_ran = false;
+  destructor_ran_ = &destructor_ran;
+  for (auto&& callback : delete_callbacks)
     std::move(callback).Run();
-  if (params_.owned_by_widget)
+
+  // If the WidgetDelegate is owned by the Widget, it is illegal for the
+  // DeleteDelegate callbacks to destruct it; if it is not owned by the Widget,
+  // the DeleteDelete callbacks are allowed but not required to destroy it.
+  if (owned_by_widget) {
+    DCHECK(!destructor_ran);
     delete this;
+  } else {
+    // If the destructor didn't get run, reset destructor_ran_ so that when it
+    // does run it doesn't try to scribble over where our stack was.
+    if (!destructor_ran)
+      destructor_ran_ = nullptr;
+  }
 }
 
 Widget* WidgetDelegate::GetWidget() {
diff --git a/ui/views/widget/widget_delegate.h b/ui/views/widget/widget_delegate.h
index 77983195..eba8040 100644
--- a/ui/views/widget/widget_delegate.h
+++ b/ui/views/widget/widget_delegate.h
@@ -419,6 +419,10 @@
   // Managed by Widget. Ensures |this| outlives its Widget.
   bool can_delete_this_ = true;
 
+  // Used to ensure that a client Delete callback doesn't actually destruct the
+  // WidgetDelegate if the client has given ownership to the Widget.
+  bool* destructor_ran_ = nullptr;
+
   // The first two are stored as unique_ptrs to make it easier to check in the
   // registration methods whether a callback is being registered too late in the
   // WidgetDelegate's lifecycle.
diff --git a/ui/views_content_client/views_content_client_main_parts.cc b/ui/views_content_client/views_content_client_main_parts.cc
index 68e02f8..2b646d5 100644
--- a/ui/views_content_client/views_content_client_main_parts.cc
+++ b/ui/views_content_client/views_content_client_main_parts.cc
@@ -8,6 +8,7 @@
 
 #include "base/run_loop.h"
 #include "build/build_config.h"
+#include "content/public/common/result_codes.h"
 #include "content/shell/browser/shell_browser_context.h"
 #include "ui/base/ime/init/input_method_initializer.h"
 #include "ui/views/test/desktop_test_views_delegate.h"
@@ -28,13 +29,14 @@
 void ViewsContentClientMainParts::PreCreateMainMessageLoop() {}
 #endif
 
-void ViewsContentClientMainParts::PreMainMessageLoopRun() {
+int ViewsContentClientMainParts::PreMainMessageLoopRun() {
   ui::InitializeInputMethodForTesting();
   browser_context_ = std::make_unique<content::ShellBrowserContext>(false);
 
   views_delegate_ = std::make_unique<views::DesktopTestViewsDelegate>();
   run_loop_ = std::make_unique<base::RunLoop>();
   views_content_client()->set_quit_closure(run_loop_->QuitClosure());
+  return content::RESULT_CODE_NORMAL_EXIT;
 }
 
 void ViewsContentClientMainParts::PostMainMessageLoopRun() {
@@ -42,9 +44,4 @@
   views_delegate_.reset();
 }
 
-bool ViewsContentClientMainParts::MainMessageLoopRun(int* result_code) {
-  run_loop_->Run();
-  return true;
-}
-
 }  // namespace ui
diff --git a/ui/views_content_client/views_content_client_main_parts.h b/ui/views_content_client/views_content_client_main_parts.h
index 749d1d9..69f8e7b 100644
--- a/ui/views_content_client/views_content_client_main_parts.h
+++ b/ui/views_content_client/views_content_client_main_parts.h
@@ -41,8 +41,7 @@
   ~ViewsContentClientMainParts() override;
 
   // content::BrowserMainParts:
-  void PreMainMessageLoopRun() override;
-  bool MainMessageLoopRun(int* result_code) override;
+  int PreMainMessageLoopRun() override;
   void PostMainMessageLoopRun() override;
 
   content::ShellBrowserContext* browser_context() {
diff --git a/ui/views_content_client/views_content_client_main_parts_chromeos.cc b/ui/views_content_client/views_content_client_main_parts_chromeos.cc
index 5c74f13..68eca2f 100644
--- a/ui/views_content_client/views_content_client_main_parts_chromeos.cc
+++ b/ui/views_content_client/views_content_client_main_parts_chromeos.cc
@@ -4,6 +4,7 @@
 
 #include "base/macros.h"
 #include "content/public/browser/context_factory.h"
+#include "content/public/common/result_codes.h"
 #include "content/shell/browser/shell_browser_context.h"
 #include "ui/aura/window.h"
 #include "ui/views_content_client/views_content_client.h"
@@ -23,7 +24,7 @@
   ~ViewsContentClientMainPartsChromeOS() override {}
 
   // content::BrowserMainParts:
-  void PreMainMessageLoopRun() override;
+  int PreMainMessageLoopRun() override;
   void PostMainMessageLoopRun() override;
 
  private:
@@ -39,7 +40,7 @@
     : ViewsContentClientMainPartsAura(content_params, views_content_client) {
 }
 
-void ViewsContentClientMainPartsChromeOS::PreMainMessageLoopRun() {
+int ViewsContentClientMainPartsChromeOS::PreMainMessageLoopRun() {
   ViewsContentClientMainPartsAura::PreMainMessageLoopRun();
 
   // Set up basic pieces of views::corewm.
@@ -51,6 +52,8 @@
   aura::Window* root_window = wm_test_helper_->host()->window();
   views_content_client()->OnPreMainMessageLoopRun(browser_context(),
                                                   root_window);
+
+  return content::RESULT_CODE_NORMAL_EXIT;
 }
 
 void ViewsContentClientMainPartsChromeOS::PostMainMessageLoopRun() {
diff --git a/ui/views_content_client/views_content_client_main_parts_desktop_aura.cc b/ui/views_content_client/views_content_client_main_parts_desktop_aura.cc
index c5d990a4..c5eb0a5 100644
--- a/ui/views_content_client/views_content_client_main_parts_desktop_aura.cc
+++ b/ui/views_content_client/views_content_client_main_parts_desktop_aura.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "content/public/common/result_codes.h"
 #include "content/shell/browser/shell_browser_context.h"
 #include "ui/display/screen.h"
 #include "ui/views/widget/desktop_aura/desktop_screen.h"
@@ -25,7 +26,7 @@
   ~ViewsContentClientMainPartsDesktopAura() override = default;
 
   // ViewsContentClientMainPartsAura:
-  void PreMainMessageLoopRun() override;
+  int PreMainMessageLoopRun() override;
 };
 
 ViewsContentClientMainPartsDesktopAura::ViewsContentClientMainPartsDesktopAura(
@@ -34,12 +35,14 @@
     : ViewsContentClientMainPartsAura(content_params, views_content_client) {
 }
 
-void ViewsContentClientMainPartsDesktopAura::PreMainMessageLoopRun() {
+int ViewsContentClientMainPartsDesktopAura::PreMainMessageLoopRun() {
   ViewsContentClientMainPartsAura::PreMainMessageLoopRun();
 
   views::CreateDesktopScreen();
 
   views_content_client()->OnPreMainMessageLoopRun(browser_context(), nullptr);
+
+  return content::RESULT_CODE_NORMAL_EXIT;
 }
 
 }  // namespace
diff --git a/ui/views_content_client/views_content_client_main_parts_mac.mm b/ui/views_content_client/views_content_client_main_parts_mac.mm
index 20a36c6..ec2cfe6 100644
--- a/ui/views_content_client/views_content_client_main_parts_mac.mm
+++ b/ui/views_content_client/views_content_client_main_parts_mac.mm
@@ -15,6 +15,7 @@
 #include "content/public/browser/context_factory.h"
 #include "content/public/browser/plugin_service.h"
 #include "content/public/common/content_paths.h"
+#include "content/public/common/result_codes.h"
 #include "content/shell/browser/shell_application_mac.h"
 #include "content/shell/browser/shell_browser_context.h"
 #include "ui/views/test/test_views_delegate.h"
@@ -45,7 +46,7 @@
   ~ViewsContentClientMainPartsMac() override;
 
   // content::BrowserMainParts:
-  void PreMainMessageLoopRun() override;
+  int PreMainMessageLoopRun() override;
 
  private:
   base::scoped_nsobject<ViewsContentClientAppController> app_controller_;
@@ -65,7 +66,7 @@
   [[NSApplication sharedApplication] setDelegate:app_controller_];
 }
 
-void ViewsContentClientMainPartsMac::PreMainMessageLoopRun() {
+int ViewsContentClientMainPartsMac::PreMainMessageLoopRun() {
   ViewsContentClientMainParts::PreMainMessageLoopRun();
 
   views_delegate()->set_context_factory(content::GetContextFactory());
@@ -80,6 +81,8 @@
                          base::Unretained(views_content_client()),
                          base::Unretained(browser_context()),
                          base::Unretained(window_context))];
+
+  return content::RESULT_CODE_NORMAL_EXIT;
 }
 
 ViewsContentClientMainPartsMac::~ViewsContentClientMainPartsMac() {
diff --git a/weblayer/browser/browser_main_parts_impl.cc b/weblayer/browser/browser_main_parts_impl.cc
index 1107b74..80d0b1d 100644
--- a/weblayer/browser/browser_main_parts_impl.cc
+++ b/weblayer/browser/browser_main_parts_impl.cc
@@ -217,7 +217,7 @@
           performance_manager::Decorators::kMinimal, base::DoNothing());
 }
 
-void BrowserMainPartsImpl::PreMainMessageLoopRun() {
+int BrowserMainPartsImpl::PreMainMessageLoopRun() {
   FeatureListCreator::GetInstance()->PerformPreMainMessageLoopStartup();
 
   // It's necessary to have a complete dependency graph of
@@ -278,18 +278,20 @@
   Java_MojoInterfaceRegistrar_registerMojoInterfaces(
       base::android::AttachCurrentThread());
 #endif
+
+  return content::RESULT_CODE_NORMAL_EXIT;
 }
 
-bool BrowserMainPartsImpl::MainMessageLoopRun(int* result_code) {
-  return !run_message_loop_;
-}
-
-void BrowserMainPartsImpl::PreDefaultMainMessageLoopRun(
-    base::OnceClosure quit_closure) {
-  // Wrap the method that stops the message loop so we can do other shutdown
-  // cleanup inside content.
-  params_->delegate->SetMainMessageLoopQuitClosure(
-      base::BindOnce(StopMessageLoop, std::move(quit_closure)));
+void BrowserMainPartsImpl::WillRunMainMessageLoop(
+    std::unique_ptr<base::RunLoop>& run_loop) {
+  if (run_message_loop_) {
+    // Wrap the method that stops the message loop so we can do other shutdown
+    // cleanup inside content.
+    params_->delegate->SetMainMessageLoopQuitClosure(
+        base::BindOnce(StopMessageLoop, run_loop->QuitClosure()));
+  } else {
+    run_loop.reset();
+  }
 }
 
 void BrowserMainPartsImpl::PostMainMessageLoopRun() {
@@ -298,4 +300,5 @@
 
   performance_manager_lifetime_.reset();
 }
+
 }  // namespace weblayer
diff --git a/weblayer/browser/browser_main_parts_impl.h b/weblayer/browser/browser_main_parts_impl.h
index 4ed8f99..fa512236 100644
--- a/weblayer/browser/browser_main_parts_impl.h
+++ b/weblayer/browser/browser_main_parts_impl.h
@@ -36,10 +36,10 @@
   int PreEarlyInitialization() override;
   void PreMainMessageLoopStart() override;
   void PostCreateThreads() override;
-  void PreMainMessageLoopRun() override;
+  int PreMainMessageLoopRun() override;
+  void WillRunMainMessageLoop(
+      std::unique_ptr<base::RunLoop>& run_loop) override;
   void PostMainMessageLoopRun() override;
-  bool MainMessageLoopRun(int* result_code) override;
-  void PreDefaultMainMessageLoopRun(base::OnceClosure quit_closure) override;
 
  private:
   MainParams* params_;
diff --git a/weblayer/browser/webrtc/media_stream_manager.cc b/weblayer/browser/webrtc/media_stream_manager.cc
index 99990c5..c468f87 100644
--- a/weblayer/browser/webrtc/media_stream_manager.cc
+++ b/weblayer/browser/webrtc/media_stream_manager.cc
@@ -4,6 +4,8 @@
 
 #include "weblayer/browser/webrtc/media_stream_manager.h"
 
+#include <utility>
+
 #include "base/supports_user_data.h"
 #include "components/webrtc/media_stream_devices_controller.h"
 #include "content/public/browser/media_stream_request.h"
@@ -115,8 +117,7 @@
   webrtc::MediaStreamDevicesController::RequestPermissions(
       request, nullptr,
       base::BindOnce(&MediaStreamManager::OnMediaAccessPermissionResult,
-                     weak_factory_.GetWeakPtr(),
-                     base::Passed(std::move(callback))));
+                     weak_factory_.GetWeakPtr(), std::move(callback)));
 }
 
 void MediaStreamManager::OnClientReadyToStream(JNIEnv* env,