diff --git a/DEPS b/DEPS
index ac5f881a..ff04f26 100644
--- a/DEPS
+++ b/DEPS
@@ -300,7 +300,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'b838c9b66d3bf5c89b971000b0df1fedfad68efa',
+  'skia_revision': 'ca89d2781f782c36ed021e9bc9e1dd80b6550b52',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -308,7 +308,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': '2f9d0810ecb7d6e3549a4ca1fe6866f849a5af8a',
+  'angle_revision': 'c6ad305ccfc2cdea77d8e05e2fe5c5f40febb5e0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -371,7 +371,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '638d30eac631145d3d1bfcfb95aa96a9b4a5450f',
+  'catapult_revision': '94fe26f9d5ab1009c0cc716314d3d92a4f56e056',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -415,7 +415,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.
-  'dawn_revision': '1862e83510aef598b427af3d3a5c18fbf17ac590',
+  'dawn_revision': '426b47e4816542659fdce29b3c689045d288e199',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -443,7 +443,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling nearby
   # and whatever else without interference from each other.
-  'nearby_revision': '408900e702103c8ed39af851aae3095da03c076f',
+  'nearby_revision': '525283a166274480d842fb6104074337c6ec8727',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling securemessage
   # and whatever else without interference from each other.
@@ -479,7 +479,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ffmpeg
   # and whatever else without interference from each other.
-  'ffmpeg_revision': 'b71ecd02b47939e530e620d9d0d101463db0f688',
+  'ffmpeg_revision': '64d7d8d0e5035087ebe24a65845b36f78e7fad92',
 
   # If you change this, also update the libc++ revision in
   # //buildtools/deps_revisions.gni.
@@ -776,7 +776,7 @@
     Var('chromium_git') + '/external/github.com/toji/webvr.info.git' + '@' + 'c58ae99b9ff9e2aa4c524633519570bf33536248',
 
   'src/docs/website': {
-    'url': Var('chromium_git') + '/website.git' + '@' + 'b6f13823c75384e11b1f8d591c0b94f36bf99189',
+    'url': Var('chromium_git') + '/website.git' + '@' + '8ef190c15ff4982a54a22466f41c8fcaa30def58',
   },
 
   'src/ios/third_party/earl_grey2/src': {
@@ -955,7 +955,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': '7LibE0MLJMFS99X0RgfGxaihptFBes7DCeHNQU_qJGMC',
+          'version': 'vqYWBuNeaF85CGvaKzQtC7wXNdb5Yy-R-KFqxDNbyBkC',
       },
     ],
     'condition': 'checkout_android',
@@ -1198,7 +1198,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'b0fb8d570df94ed4e457adaa827d1ce9b51ade00',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '5084800dc3cea44a6e135ccee721034ec7951fa7',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1575,7 +1575,7 @@
     Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + 'fac04ceb3e966f613ed17e98178e9d690280bba6',
 
   'src/third_party/openscreen/src':
-    Var('chromium_git') + '/openscreen' + '@' + 'c1804995a222b75fdf336f768249f6dfe416a2f8',
+    Var('chromium_git') + '/openscreen' + '@' + '3f47ffddac61e2c28887cd2a80f93d5078091a5e',
 
   'src/third_party/openxr/src': {
     'url': Var('chromium_git') + '/external/github.com/KhronosGroup/OpenXR-SDK' + '@' + 'bf21ccb1007bb531b45d9978919a56ea5059c245',
@@ -1723,7 +1723,7 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@3747e941a17126e1ade593593b86e012b139b894',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@1d36249fb716315181169b0aa95307584c338bf2',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907',
@@ -1762,7 +1762,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '39f597ad35bd5e88af9c388c65582673922df63c',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '73e677817aa93129f0b75233e376f070f82e758b',
+    Var('webrtc_git') + '/src.git' + '@' + '4c77c5462325cc8b73c7e13777438d6dd387ac06',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1835,7 +1835,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@8f603931a7410aab801f12f89647d200cf092239',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@e52d1f44e259791bec1662e75298a62f29371ab4',
     'condition': 'checkout_src_internal',
   },
 
@@ -3577,17 +3577,6 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_robolectric_shadows_multidex': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/org_robolectric_shadows_multidex',
-              'version': 'version:2@4.8.1.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
   'src/third_party/android_deps/libs/org_robolectric_shadows_playservices': {
       'packages': [
           {
diff --git a/ash/accelerators/accelerator_controller_impl.cc b/ash/accelerators/accelerator_controller_impl.cc
index 1e310e2..4b7fe34 100644
--- a/ash/accelerators/accelerator_controller_impl.cc
+++ b/ash/accelerators/accelerator_controller_impl.cc
@@ -1854,6 +1854,7 @@
     case DEBUG_PRINT_VIEW_HIERARCHY:
     case DEBUG_PRINT_WINDOW_HIERARCHY:
     case DEBUG_SHOW_TOAST:
+    case DEBUG_TOGGLE_DARK_MODE:
     case DEBUG_TOGGLE_GLANCEABLES:
     case DEBUG_TOGGLE_SHOW_DEBUG_BORDERS:
     case DEBUG_TOGGLE_SHOW_FPS_COUNTER:
@@ -2099,6 +2100,7 @@
     case DEBUG_PRINT_VIEW_HIERARCHY:
     case DEBUG_PRINT_WINDOW_HIERARCHY:
     case DEBUG_SHOW_TOAST:
+    case DEBUG_TOGGLE_DARK_MODE:
     case DEBUG_TOGGLE_GLANCEABLES:
       debug::PerformDebugActionIfEnabled(action);
       break;
diff --git a/ash/accelerators/accelerator_table.cc b/ash/accelerators/accelerator_table.cc
index d04cc8b..062c7f33 100644
--- a/ash/accelerators/accelerator_table.cc
+++ b/ash/accelerators/accelerator_table.cc
@@ -83,6 +83,7 @@
     {true, ui::VKEY_P, kDebugModifier, DEBUG_TOGGLE_SHOW_PAINT_RECTS},
     {true, ui::VKEY_K, kDebugModifier, DEBUG_TRIGGER_CRASH},
     {true, ui::VKEY_G, kDebugModifier, DEBUG_TOGGLE_HUD_DISPLAY},
+    {true, ui::VKEY_D, kDebugModifier, DEBUG_TOGGLE_DARK_MODE},
 };
 
 const size_t kDebugAcceleratorDataLength = std::size(kDebugAcceleratorData);
diff --git a/ash/accelerators/debug_commands.cc b/ash/accelerators/debug_commands.cc
index 2cf21ec..32f2c12 100644
--- a/ash/accelerators/debug_commands.cc
+++ b/ash/accelerators/debug_commands.cc
@@ -16,7 +16,9 @@
 #include "ash/public/cpp/accelerators.h"
 #include "ash/public/cpp/debug_utils.h"
 #include "ash/public/cpp/system/toast_data.h"
+#include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
+#include "ash/style/dark_light_mode_controller_impl.h"
 #include "ash/system/toast/toast_manager_impl.h"
 #include "ash/touch/touch_devices_controller.h"
 #include "ash/wallpaper/wallpaper_controller_impl.h"
@@ -107,6 +109,18 @@
   accelerators::DumpCalendarModel();
 }
 
+void HandleToggleDarkMode() {
+  // Toggling dark mode requires that the active user session has started
+  // since the feature is backed by user preferences.
+  if (auto* controller = Shell::Get()->session_controller();
+      !(controller && controller->IsActiveUserSessionStarted())) {
+    return;
+  }
+
+  if (auto* controller = DarkLightModeControllerImpl::Get())
+    controller->ToggleColorMode();
+}
+
 void HandleToggleGlanceables() {
   if (!features::AreGlanceablesEnabled())
     return;
@@ -207,6 +221,9 @@
           /*visible_on_lock_screen=*/false, /*has_dismiss_button=*/true,
           /*custom_dismiss_text=*/u"Dismiss"));
       break;
+    case DEBUG_TOGGLE_DARK_MODE:
+      HandleToggleDarkMode();
+      break;
     case DEBUG_TOGGLE_GLANCEABLES:
       HandleToggleGlanceables();
       break;
diff --git a/ash/app_list/views/app_list_view.cc b/ash/app_list/views/app_list_view.cc
index 50a99772..935f6c1e 100644
--- a/ash/app_list/views/app_list_view.cc
+++ b/ash/app_list/views/app_list_view.cc
@@ -1096,6 +1096,8 @@
 
 AppListStateTransitionSource AppListView::GetAppListStateTransitionSource(
     AppListViewState target_state) const {
+  // TODO(https://crbug.com/1356661): Remove peeking and half launcher
+  // transitions.
   switch (app_list_state_) {
     case AppListViewState::kClosed:
       // CLOSED->X transitions are not useful for UMA.
@@ -1113,8 +1115,6 @@
           // failed state transition. Not useful for UMA.
           return kMaxAppListStateTransition;
         case AppListViewState::kFullscreenSearch:
-          // PEEKING->FULLSCREEN_SEARCH is not a valid transition.
-          NOTREACHED();
           return kMaxAppListStateTransition;
       }
     case AppListViewState::kHalf:
diff --git a/ash/app_list/views/assistant/assistant_page_view.cc b/ash/app_list/views/assistant/assistant_page_view.cc
index f034008d..fd46b42 100644
--- a/ash/app_list/views/assistant/assistant_page_view.cc
+++ b/ash/app_list/views/assistant/assistant_page_view.cc
@@ -485,12 +485,12 @@
 
   // Update app list view state for |assistant_page_view_|.
   // Embedded Assistant Ui only has two sizes. The only state change is from
-  // |kPeeking| to |kHalf| state.
+  // |kPeeking| to |kFullscreenAllApps| state.
   if (app_list_view->app_list_state() != AppListViewState::kPeeking)
     return;
 
   if (child_height > GetPreferredHeightForAppListState(app_list_view))
-    app_list_view->SetState(AppListViewState::kHalf);
+    app_list_view->SetState(AppListViewState::kFullscreenSearch);
 }
 
 BEGIN_METADATA(AssistantPageView, views::View)
diff --git a/ash/app_list/views/assistant/assistant_page_view_unittest.cc b/ash/app_list/views/assistant/assistant_page_view_unittest.cc
index 65edc40..4f82b48 100644
--- a/ash/app_list/views/assistant/assistant_page_view_unittest.cc
+++ b/ash/app_list/views/assistant/assistant_page_view_unittest.cc
@@ -260,14 +260,6 @@
   EXPECT_EQ(AppListViewState::kPeeking, app_list_view()->app_list_state());
 }
 
-TEST_F(AssistantPageNonBubbleTest, ShouldStartInHalfState) {
-  SetOnboardingMode(AssistantOnboardingMode::kEducation);
-
-  ShowAssistantUi();
-
-  EXPECT_EQ(AppListViewState::kHalf, app_list_view()->app_list_state());
-}
-
 TEST_F(AssistantPageNonBubbleTest, ShouldStartAtMinimumHeight) {
   DoNotShowOnboardingViews();
 
diff --git a/ash/components/arc/compat_mode/OWNERS b/ash/components/arc/compat_mode/OWNERS
new file mode 100644
index 0000000..6d135a65
--- /dev/null
+++ b/ash/components/arc/compat_mode/OWNERS
@@ -0,0 +1,2 @@
+takise@chromium.org
+toshikikikuchi@chromium.org
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index c188f60c..6efb8de 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -331,10 +331,6 @@
 const base::Feature kCellularCustomAPNProfiles{
     "CellularCustomAPNProfiles", base::FEATURE_DISABLED_BY_DEFAULT};
 
-// If enabled, send the LTE attach APN configuration to the modem.
-const base::Feature kCellularUseAttachApn{"CellularUseAttachApn",
-                                          base::FEATURE_ENABLED_BY_DEFAULT};
-
 // If enabled, use second the Euicc that is exposed by Hermes in Cellular Setup
 // and Settings.
 const base::Feature kCellularUseSecondEuicc{"CellularUseSecondEuicc",
@@ -1594,6 +1590,10 @@
 const base::Feature kTerminalTmuxIntegration{"TerminalTmuxIntegration",
                                              base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Enable or disable new touch text editing features on ChromeOS.
+const base::Feature kTouchTextEditingRedesign{
+    "TouchTextEditingRedesign", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables the TrafficCountersHandler class to auto-reset traffic counters
 // and shows Data Usage in the Celluar Settings UI.
 const base::Feature kTrafficCountersEnabled{"TrafficCountersEnabled",
@@ -1663,6 +1663,11 @@
 const base::Feature kVirtualKeyboardRoundCorners{
     "VirtualKeyboardRoundCorners", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Enables a per-boot host GPU cache generation for VMs. On default, the cache
+// is generated per OS version.
+const base::Feature kVmPerBootShaderCache{"VmPerBootShaderCache",
+                                          base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Controls whether to allow enabling wake on WiFi features in shill.
 const base::Feature kWakeOnWifiAllowed{"WakeOnWifiAllowed",
                                        base::FEATURE_DISABLED_BY_DEFAULT};
@@ -2584,10 +2589,6 @@
   return base::FeatureList::IsEnabled(kShowPlayInDemoMode);
 }
 
-bool ShouldUseAttachApn() {
-  return base::FeatureList::IsEnabled(kCellularUseAttachApn);
-}
-
 bool ShouldUseV1DeviceSync() {
   return !ShouldUseV2DeviceSync() ||
          !base::FeatureList::IsEnabled(kDisableCryptAuthV1DeviceSync);
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 5fc8c07..d89bca2 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -147,8 +147,6 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kCellularCustomAPNProfiles;
 COMPONENT_EXPORT(ASH_CONSTANTS)
-extern const base::Feature kCellularUseAttachApn;
-COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kCellularUseSecondEuicc;
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kCheckPasswordsAgainstCryptohomeHelper;
@@ -646,6 +644,8 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kTerminalTmuxIntegration;
 COMPONENT_EXPORT(ASH_CONSTANTS)
+extern const base::Feature kTouchTextEditingRedesign;
+COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kTrafficCountersEnabled;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kTrilinearFiltering;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kUploadOfficeToCloud;
@@ -674,6 +674,8 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kVirtualKeyboardRoundCorners;
 COMPONENT_EXPORT(ASH_CONSTANTS)
+extern const base::Feature kVmPerBootShaderCache;
+COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kWakeOnWifiAllowed;
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kWallpaperFastRefresh;
@@ -924,7 +926,6 @@
 bool ShouldArcAndGuestOsFileTasksUseAppService();
 // TODO(michaelpg): Remove after M71 branch to re-enable Play Store by default.
 COMPONENT_EXPORT(ASH_CONSTANTS) bool ShouldShowPlayStoreInDemoMode();
-COMPONENT_EXPORT(ASH_CONSTANTS) bool ShouldUseAttachApn();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool ShouldUseV1DeviceSync();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool ShouldUseV2DeviceSync();
 
diff --git a/ash/public/cpp/accelerators.h b/ash/public/cpp/accelerators.h
index eed04236..8dcbfa44 100644
--- a/ash/public/cpp/accelerators.h
+++ b/ash/public/cpp/accelerators.h
@@ -152,6 +152,7 @@
   DEBUG_PRINT_VIEW_HIERARCHY,
   DEBUG_PRINT_WINDOW_HIERARCHY,
   DEBUG_SHOW_TOAST,
+  DEBUG_TOGGLE_DARK_MODE,
   DEBUG_TOGGLE_GLANCEABLES,
   DEBUG_TOGGLE_SHOW_DEBUG_BORDERS,
   DEBUG_TOGGLE_SHOW_FPS_COUNTER,
diff --git a/ash/quick_pair/repository/fast_pair_repository_impl.cc b/ash/quick_pair/repository/fast_pair_repository_impl.cc
index 6c4a4f6..a213f835 100644
--- a/ash/quick_pair/repository/fast_pair_repository_impl.cc
+++ b/ash/quick_pair/repository/fast_pair_repository_impl.cc
@@ -34,6 +34,7 @@
 namespace {
 
 constexpr base::TimeDelta kOfflineRetryTimeout = base::Minutes(1);
+constexpr base::TimeDelta kCacheInvalidationTime = base::Minutes(30);
 
 // Checks if the mac address of a FastPairDevice is the same as the given
 // |mac_address| by checking if the SHA256 from the given |device| equals to
@@ -213,14 +214,25 @@
     const AccountKeyFilter& account_key_filter,
     CheckAccountKeysCallback callback) {
   CheckAccountKeysImpl(account_key_filter, std::move(callback),
-                       /*refresh_cache_on_miss=*/true);
+                       /*allow_cache_refresh=*/true);
 }
 
 void FastPairRepositoryImpl::CheckAccountKeysImpl(
     const AccountKeyFilter& account_key_filter,
     CheckAccountKeysCallback callback,
-    bool refresh_cache_on_miss) {
+    bool allow_cache_refresh) {
   QP_LOG(INFO) << __func__;
+  if (allow_cache_refresh &&
+      (base::Time::Now() - footprints_last_updated_) > kCacheInvalidationTime) {
+    // If it has been >30 minutes since the cache was updated, try to get
+    // user devices from the server before proceeding.
+    footprints_fetcher_->GetUserDevices(base::BindOnce(
+        &FastPairRepositoryImpl::UpdateCacheAndRetryCheckAccountKeys,
+        weak_ptr_factory_.GetWeakPtr(), account_key_filter,
+        std::move(callback)));
+    return;
+  }
+
   for (const auto& info : user_devices_cache_.fast_pair_info()) {
     if (info.has_device()) {
       const std::string& string_key = info.device().account_key();
@@ -242,7 +254,9 @@
     }
   }
 
-  if (refresh_cache_on_miss &&
+  // On cache miss, query the server to make sure the device isn't saved to the
+  // account unless we've already queried the server in the past minute.
+  if (allow_cache_refresh &&
       (base::Time::Now() - footprints_last_updated_) > base::Minutes(1)) {
     footprints_fetcher_->GetUserDevices(
         base::BindOnce(&FastPairRepositoryImpl::RetryCheckAccountKeys,
@@ -266,7 +280,22 @@
 
   UpdateUserDevicesCache(user_devices);
   CheckAccountKeysImpl(account_key_filter, std::move(callback),
-                       /*refresh_cache_on_miss=*/false);
+                       /*allow_cache_refresh=*/false);
+}
+
+void FastPairRepositoryImpl::UpdateCacheAndRetryCheckAccountKeys(
+    const AccountKeyFilter& account_key_filter,
+    CheckAccountKeysCallback callback,
+    absl::optional<nearby::fastpair::UserReadDevicesResponse> user_devices) {
+  QP_LOG(INFO) << __func__;
+  if (!user_devices) {
+    QP_LOG(INFO) << __func__
+                 << "Failed to update user devices cache. Using stale cache";
+  } else {
+    UpdateUserDevicesCache(user_devices);
+  }
+  CheckAccountKeysImpl(account_key_filter, std::move(callback),
+                       /*allow_cache_refresh=*/false);
 }
 
 void FastPairRepositoryImpl::CompleteAccountKeyLookup(
diff --git a/ash/quick_pair/repository/fast_pair_repository_impl.h b/ash/quick_pair/repository/fast_pair_repository_impl.h
index 34773c5..74101b19 100644
--- a/ash/quick_pair/repository/fast_pair_repository_impl.h
+++ b/ash/quick_pair/repository/fast_pair_repository_impl.h
@@ -95,7 +95,7 @@
  private:
   void CheckAccountKeysImpl(const AccountKeyFilter& account_key_filter,
                             CheckAccountKeysCallback callback,
-                            bool refresh_cache_on_miss);
+                            bool allow_cache_refresh);
   void OnMetadataFetched(
       const std::string& normalized_model_id,
       DeviceMetadataCallback callback,
@@ -109,6 +109,10 @@
       const AccountKeyFilter& account_key_filter,
       CheckAccountKeysCallback callback,
       absl::optional<nearby::fastpair::UserReadDevicesResponse> user_devices);
+  void UpdateCacheAndRetryCheckAccountKeys(
+      const AccountKeyFilter& account_key_filter,
+      CheckAccountKeysCallback callback,
+      absl::optional<nearby::fastpair::UserReadDevicesResponse> user_devices);
   void UpdateUserDevicesCache(
       absl::optional<nearby::fastpair::UserReadDevicesResponse> user_devices);
   void CompleteAccountKeyLookup(CheckAccountKeysCallback callback,
diff --git a/ash/quick_pair/repository/fast_pair_repository_impl_unittest.cc b/ash/quick_pair/repository/fast_pair_repository_impl_unittest.cc
index b50f12a..b71a44f 100644
--- a/ash/quick_pair/repository/fast_pair_repository_impl_unittest.cc
+++ b/ash/quick_pair/repository/fast_pair_repository_impl_unittest.cc
@@ -327,6 +327,92 @@
   run_loop->Run();
 }
 
+TEST_F(FastPairRepositoryImplTest, UpdateStaleUserDeviceCache) {
+  AccountKeyFilter filter(kFilterBytes1, {salt});
+  nearby::fastpair::GetObservedDeviceResponse response;
+  DeviceMetadata metadata(response, gfx::Image());
+
+  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestBLEAddress,
+                                             Protocol::kFastPairInitial);
+  device->set_classic_address(kTestClassicAddress1);
+  fast_pair_repository_->AssociateAccountKey(device, kAccountKey1);
+  base::RunLoop().RunUntilIdle();
+  ASSERT_TRUE(footprints_fetcher_->ContainsKey(kAccountKey1));
+  ASSERT_TRUE(
+      saved_device_registry_->IsAccountKeySavedToRegistry(kAccountKey1));
+
+  auto run_loop = std::make_unique<base::RunLoop>();
+
+  // Check for the device, this will also load the device into the cache
+  fast_pair_repository_->CheckAccountKeys(
+      filter, base::BindOnce(&FastPairRepositoryImplTest::VerifyAccountKeyCheck,
+                             base::Unretained(this), run_loop->QuitClosure(),
+                             /*expected_result=*/true));
+  base::RunLoop().RunUntilIdle();
+
+  // Remove the device directly from footprints. This is equivalent to the
+  // device being removed on an Android phone or another Chromebook
+  footprints_fetcher_->DeleteUserDevice(base::HexEncode(kAccountKey1),
+                                        base::DoNothing());
+
+  // 29 minutes later, device is still in the cache
+  task_environment()->FastForwardBy(base::Minutes(29));
+  fast_pair_repository_->CheckAccountKeys(
+      filter, base::BindOnce(&FastPairRepositoryImplTest::VerifyAccountKeyCheck,
+                             base::Unretained(this), run_loop->QuitClosure(),
+                             /*expected_result=*/true));
+  base::RunLoop().RunUntilIdle();
+
+  // After >30 minutes, cache will have gone stale so device will be removed
+  task_environment()->FastForwardBy(base::Seconds(61));
+  fast_pair_repository_->CheckAccountKeys(
+      filter, base::BindOnce(&FastPairRepositoryImplTest::VerifyAccountKeyCheck,
+                             base::Unretained(this), run_loop->QuitClosure(),
+                             /*expected_result=*/false));
+  run_loop->Run();
+}
+
+TEST_F(FastPairRepositoryImplTest, UseStaleCache) {
+  AccountKeyFilter filter(kFilterBytes1, {salt});
+  nearby::fastpair::GetObservedDeviceResponse response;
+  DeviceMetadata metadata(response, gfx::Image());
+
+  auto device = base::MakeRefCounted<Device>(kValidModelId, kTestBLEAddress,
+                                             Protocol::kFastPairInitial);
+  device->set_classic_address(kTestClassicAddress1);
+  fast_pair_repository_->AssociateAccountKey(device, kAccountKey1);
+  base::RunLoop().RunUntilIdle();
+  ASSERT_TRUE(footprints_fetcher_->ContainsKey(kAccountKey1));
+  ASSERT_TRUE(
+      saved_device_registry_->IsAccountKeySavedToRegistry(kAccountKey1));
+
+  auto run_loop = std::make_unique<base::RunLoop>();
+
+  // Check for the device, this will also load the device into the cache
+  fast_pair_repository_->CheckAccountKeys(
+      filter, base::BindOnce(&FastPairRepositoryImplTest::VerifyAccountKeyCheck,
+                             base::Unretained(this), run_loop->QuitClosure(),
+                             /*expected_result=*/true));
+  base::RunLoop().RunUntilIdle();
+
+  // Remove the device directly from footprints. This is equivalent to the
+  // device being removed on an Android phone or another Chromebook
+  footprints_fetcher_->DeleteUserDevice(base::HexEncode(kAccountKey1),
+                                        base::DoNothing());
+
+  // Set the response to replicate an error getting devices from the server
+  footprints_fetcher_->SetGetUserDevicesResponse(absl::nullopt);
+
+  // After >30 minutes, cache is stale but we will fail to get devices from
+  // the server so we use the stale cache with the device still present
+  task_environment()->FastForwardBy(base::Minutes(31));
+  fast_pair_repository_->CheckAccountKeys(
+      filter, base::BindOnce(&FastPairRepositoryImplTest::VerifyAccountKeyCheck,
+                             base::Unretained(this), run_loop->QuitClosure(),
+                             /*expected_result=*/true));
+  run_loop->Run();
+}
+
 TEST_F(FastPairRepositoryImplTest, AssociateAccountKey_InvalidId) {
   auto device = base::MakeRefCounted<Device>(kInvalidModelId, kTestBLEAddress,
                                              Protocol::kFastPairInitial);
diff --git a/ash/system/human_presence/snooping_protection_notification_blocker_unittest.cc b/ash/system/human_presence/snooping_protection_notification_blocker_unittest.cc
index 7d899f7c..3f1bbe0 100644
--- a/ash/system/human_presence/snooping_protection_notification_blocker_unittest.cc
+++ b/ash/system/human_presence/snooping_protection_notification_blocker_unittest.cc
@@ -182,8 +182,18 @@
  public:
   SnoopingProtectionNotificationBlockerTest()
       : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {
-    scoped_feature_list_.InitWithFeatures({ash::features::kSnoopingProtection},
-                                          {ash::features::kQuickDim});
+    scoped_feature_list_.InitWithFeaturesAndParameters(
+        {{ash::features::kSnoopingProtection,
+          {
+              {"SnoopingProtection_pos_window_ms", "4000"},
+              {"SnoopingProtection_filter_config_case", "2"},
+              {"SnoopingProtection_positive_count_threshold", "1"},
+              {"SnoopingProtection_negative_count_threshold", "1"},
+              {"SnoopingProtection_uncertain_count_threshold", "1"},
+              {"SnoopingProtection_positive_score_threshold", "0"},
+              {"SnoopingProtection_negative_score_threshold", "0"},
+          }}},
+        {ash::features::kQuickDim});
     scoped_command_line_.GetProcessCommandLine()->AppendSwitch(
         switches::kHasHps);
   }
diff --git a/ash/webui/shimless_rma/resources/onboarding_enter_rsu_wp_disable_code_page.html b/ash/webui/shimless_rma/resources/onboarding_enter_rsu_wp_disable_code_page.html
index 86d9af8..521166f2 100644
--- a/ash/webui/shimless_rma/resources/onboarding_enter_rsu_wp_disable_code_page.html
+++ b/ash/webui/shimless_rma/resources/onboarding_enter_rsu_wp_disable_code_page.html
@@ -29,6 +29,11 @@
     width: 320px;
   }
 
+  #rsuCodeDialogLink {
+    color: var(--cros-link-color);
+    text-decoration: none;
+  }
+
   #qrCodeCanvas {
       border: 1px solid;
       border-color: var(--google-grey-200);
@@ -50,9 +55,7 @@
   <div slot="left-pane">
     <h1>[[i18n('rsuCodePageTitleText')]]</h1>
     <div class="instructions">
-      <localized-link id="rsuCodeDialogLink"
-          localized-string="[[rsuInstructionsText_]]">
-      </localized-link>
+      <span inner-h-t-m-l="[[rsuInstructionsText_]]"></span>
     </div>
     <div id="inputContainer">
       <cr-input
diff --git a/ash/webui/shimless_rma/resources/onboarding_enter_rsu_wp_disable_code_page.js b/ash/webui/shimless_rma/resources/onboarding_enter_rsu_wp_disable_code_page.js
index 991fe19..ef3c2a2 100644
--- a/ash/webui/shimless_rma/resources/onboarding_enter_rsu_wp_disable_code_page.js
+++ b/ash/webui/shimless_rma/resources/onboarding_enter_rsu_wp_disable_code_page.js
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'chrome://resources/cr_components/localized_link/localized_link.js';
 import './shimless_rma_fonts_css.js';
 import './shimless_rma_shared_css.js';
 import './base_page.js';
@@ -233,9 +232,9 @@
 
   /** @private */
   setRsuInstructionsText_() {
-    this.rsuInstructionsText_ = this.i18nAdvanced('rsuCodeInstructionsText');
-    const linkElement = this.shadowRoot.querySelector('#rsuCodeDialogLink')
-                            .shadowRoot.querySelector('a');
+    this.rsuInstructionsText_ =
+        this.i18nAdvanced('rsuCodeInstructionsText', {attrs: ['id']});
+    const linkElement = this.shadowRoot.querySelector('#rsuCodeDialogLink');
     linkElement.setAttribute('href', '#');
     linkElement.addEventListener('click', () => {
       if (this.allButtonsDisabled) {
diff --git a/ash/webui/shimless_rma/resources/reimaging_device_information_page.html b/ash/webui/shimless_rma/resources/reimaging_device_information_page.html
index 163d591..3c0fa374 100644
--- a/ash/webui/shimless_rma/resources/reimaging_device_information_page.html
+++ b/ash/webui/shimless_rma/resources/reimaging_device_information_page.html
@@ -73,14 +73,15 @@
   <div slot="right-pane">
     <div class="input-wrapper">
       <div class="input-row">
-        <div class="input-holder" aria-labelledby="serialNumberLabel">
+        <div class="input-holder">
           <cr-input id="serialNumber" value="{{serialNumber_}}" 
               label="[[i18n('confirmDeviceInfoSerialNumberLabel')]]"
               disabled="[[allButtonsDisabled]]">
           </cr-input>
           <cr-button id="resetSerialNumber"
               on-click="onResetSerialNumberButtonClicked_"
-              disabled="[[disableResetSerialNumber_]]">
+              disabled="[[disableResetSerialNumber_]]"
+              aria-description="[[i18n('confirmDeviceInfoSerialNumberLabel')]]">
             [[i18n('confirmDeviceInfoResetButtonLabel')]]
           </cr-button>
         </div>
@@ -93,7 +94,8 @@
           </cr-input>
           <cr-button id="resetDramPartNumber"
               on-click="onResetDramPartNumberButtonClicked_"
-              disabled="[[disableResetDramPartNumber_]]">
+              disabled="[[disableResetDramPartNumber_]]"
+              aria-description="[[i18n('confirmDeviceInfoDramPartNumberLabel')]]">
             [[i18n('confirmDeviceInfoResetButtonLabel')]]
           </cr-button>
         </div>
@@ -113,7 +115,8 @@
             </template>
           </select>
           <cr-button id="resetRegion" on-click="onResetRegionButtonClicked_"
-              disabled="[[disableResetRegion_]]">
+              disabled="[[disableResetRegion_]]"
+              aria-describedby="regionLabel">
             [[i18n('confirmDeviceInfoResetButtonLabel')]]
           </cr-button>
         </div>
@@ -135,7 +138,8 @@
           </select>
           <cr-button id="resetWhiteLabel"
               on-click="onResetWhiteLabelButtonClicked_"
-              disabled="[[disableResetWhiteLabel_]]">
+              disabled="[[disableResetWhiteLabel_]]"
+              aria-describedby="whiteLabelLabel">
             [[i18n('confirmDeviceInfoResetButtonLabel')]]
           </cr-button>
         </div>
@@ -162,7 +166,8 @@
           </template>
         </select>
         <cr-button id="resetSku" on-click="onResetSkuButtonClicked_"
-            disabled="[[disableResetSku_]]">
+            disabled="[[disableResetSku_]]"
+            aria-describedby="skuLabel">
           [[i18n('confirmDeviceInfoResetButtonLabel')]]
         </cr-button>
       </div>
diff --git a/ash/webui/shortcut_customization_ui/resources/accelerator_edit_view.ts b/ash/webui/shortcut_customization_ui/resources/accelerator_edit_view.ts
index f16c106..9293fa3 100644
--- a/ash/webui/shortcut_customization_ui/resources/accelerator_edit_view.ts
+++ b/ash/webui/shortcut_customization_ui/resources/accelerator_edit_view.ts
@@ -155,5 +155,11 @@
   }
 }
 
+declare global {
+  interface HTMLElementTagNameMap {
+    'accelerator-edit-view': AcceleratorEditViewElement;
+  }
+}
+
 customElements.define(
     AcceleratorEditViewElement.is, AcceleratorEditViewElement);
diff --git a/ash/webui/shortcut_customization_ui/resources/accelerator_row.ts b/ash/webui/shortcut_customization_ui/resources/accelerator_row.ts
index 82da2f5a..3511ba1 100644
--- a/ash/webui/shortcut_customization_ui/resources/accelerator_row.ts
+++ b/ash/webui/shortcut_customization_ui/resources/accelerator_row.ts
@@ -113,4 +113,10 @@
   }
 }
 
+declare global {
+  interface HTMLElementTagNameMap {
+    'accelerator-row': AcceleratorRowElement;
+  }
+}
+
 customElements.define(AcceleratorRowElement.is, AcceleratorRowElement);
\ No newline at end of file
diff --git a/ash/webui/shortcut_customization_ui/resources/accelerator_view.ts b/ash/webui/shortcut_customization_ui/resources/accelerator_view.ts
index c45d088..8a57887 100644
--- a/ash/webui/shortcut_customization_ui/resources/accelerator_view.ts
+++ b/ash/webui/shortcut_customization_ui/resources/accelerator_view.ts
@@ -472,4 +472,10 @@
   }
 }
 
+declare global {
+  interface HTMLElementTagNameMap {
+    'accelerator-view': AcceleratorViewElement;
+  }
+}
+
 customElements.define(AcceleratorViewElement.is, AcceleratorViewElement);
diff --git a/ash/webui/shortcut_customization_ui/resources/shortcut_customization_app.ts b/ash/webui/shortcut_customization_ui/resources/shortcut_customization_app.ts
index b2b0c17..69a62e8 100644
--- a/ash/webui/shortcut_customization_ui/resources/shortcut_customization_app.ts
+++ b/ash/webui/shortcut_customization_ui/resources/shortcut_customization_app.ts
@@ -200,5 +200,11 @@
   }
 }
 
+declare global {
+  interface HTMLElementTagNameMap {
+    'shortcut-customization-app': ShortcutCustomizationAppElement;
+  }
+}
+
 customElements.define(
     ShortcutCustomizationAppElement.is, ShortcutCustomizationAppElement);
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/PayloadCallbackHelper.java b/base/test/android/javatests/src/org/chromium/base/test/util/PayloadCallbackHelper.java
index 1ea531b..27b700b4 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/util/PayloadCallbackHelper.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/PayloadCallbackHelper.java
@@ -11,6 +11,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
 /**
@@ -74,7 +75,23 @@
      */
     @Nullable
     public T getPayloadByIndexBlocking(int index) {
-        waitForCallback(1 + index);
+        return getPayloadByIndexBlocking(
+                index, CallbackHelper.WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+    }
+
+    /**
+     * Blocks until the requested payload is provided, and then returns it.
+     * @param index Index into a conceptual array of payloads provided by sequential callbacks.
+     * @param timeout timeout value for all callbacks to occur.
+     * @param unit timeout unit.
+     * @return The nth payload provided to notify. Null is a valid return value if the callback was
+     *         invoked with null.
+     * @throws IndexOutOfBoundsException If notify is not called at least the specified number of
+     *         times.
+     */
+    @Nullable
+    public T getPayloadByIndexBlocking(int index, long timeout, TimeUnit unit) {
+        waitForCallback(1 + index, timeout, unit);
         return mPayloadList.get(index);
     }
 
@@ -87,7 +104,7 @@
      */
     @Nullable
     public T getOnlyPayloadBlocking() {
-        waitForCallback(1);
+        waitForCallback(1, CallbackHelper.WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
         // While this lock likely isn't necessary for tests to call this method correctly, it allows
         // this method to truly fulfil the contact promised by the method's name that there's only
         // one payload. Other threads may be waiting to notify while this lock is held. Note this
@@ -108,17 +125,19 @@
     /**
      * Blocks until notify has been called the specified number of times.
      * @param expectedCallCount The number of times notify should be called.
+     * @param timeout timeout value for all callbacks to occur.
+     * @param unit timeout unit.
      * @throws IndexOutOfBoundsException If notify is not called at least the specified number of
      *         times.
      */
-    private void waitForCallback(int expectedCallCount) {
+    private void waitForCallback(int expectedCallCount, long timeout, TimeUnit unit) {
         int currentCallCount = mDelegate.getCallCount();
         int numberOfCallsToWaitFor = expectedCallCount - currentCallCount;
         if (numberOfCallsToWaitFor <= 0) {
             return;
         }
         try {
-            mDelegate.waitForCallback(currentCallCount, numberOfCallsToWaitFor);
+            mDelegate.waitForCallback(currentCallCount, numberOfCallsToWaitFor, timeout, unit);
         } catch (TimeoutException te) {
             throw new IllegalStateException(te);
         }
diff --git a/base/values.cc b/base/values.cc
index c174f447..b7c214e 100644
--- a/base/values.cc
+++ b/base/values.cc
@@ -1071,20 +1071,6 @@
   GetList().Append(std::move(value));
 }
 
-bool Value::EraseListIter(CheckedContiguousConstIterator<Value> iter) {
-  const auto offset = iter - ListView(list()).begin();
-  auto list_iter = list().begin() + offset;
-  if (list_iter == list().end())
-    return false;
-
-  list().erase(list_iter);
-  return true;
-}
-
-size_t Value::EraseListValue(const Value& val) {
-  return GetList().EraseValue(val);
-}
-
 void Value::ClearList() {
   GetList().clear();
 }
diff --git a/base/values.h b/base/values.h
index 657d0d1..4725ead1 100644
--- a/base/values.h
+++ b/base/values.h
@@ -729,27 +729,6 @@
   // DEPRECATED: prefer `Value::List::Append()`.
   void Append(std::string&& value);
 
-  // Erases the Value pointed to by `iter`. Returns false if `iter` is out of
-  // bounds.
-  //
-  // DEPRECATED: prefer `Value::List::erase(iter)`.
-  bool EraseListIter(CheckedContiguousConstIterator<Value> iter);
-
-  // Erases all Values that compare equal to `val`. Returns the number of
-  // deleted Values.
-  //
-  // DEPRECATED: prefer `Value::List::EraseValue(val)`.
-  size_t EraseListValue(const Value& val);
-
-  // Erases all Values for which `pred` returns true. Returns the number of
-  // deleted Values.
-  //
-  // DEPRECATED: prefer `Value::List::EraseIf(pred)`.
-  template <typename Predicate>
-  size_t EraseListValueIf(Predicate pred) {
-    return base::EraseIf(list(), pred);
-  }
-
   // Erases all Values from the list.
   //
   // DEPRECATED: prefer `Value::List::clear()`.
diff --git a/base/values_unittest.cc b/base/values_unittest.cc
index de93a76..a06fa29 100644
--- a/base/values_unittest.cc
+++ b/base/values_unittest.cc
@@ -735,65 +735,43 @@
   EXPECT_EQ(next_it, list.end());
 }
 
-TEST(ValuesTest, EraseListIter) {
-  ListValue value;
-  value.Append(1);
-  value.Append(2);
-  value.Append(3);
+TEST(ValuesTest, ListEraseValue) {
+  Value::List list;
+  list.Append(1);
+  list.Append(2);
+  list.Append(2);
+  list.Append(3);
 
-  EXPECT_TRUE(value.EraseListIter(value.GetListDeprecated().begin() + 1));
-  EXPECT_EQ(2u, value.GetListDeprecated().size());
-  EXPECT_EQ(1, value.GetListDeprecated()[0].GetInt());
-  EXPECT_EQ(3, value.GetListDeprecated()[1].GetInt());
+  EXPECT_EQ(2u, list.EraseValue(Value(2)));
+  EXPECT_EQ(2u, list.size());
+  EXPECT_EQ(1, list[0]);
+  EXPECT_EQ(3, list[1]);
 
-  EXPECT_TRUE(value.EraseListIter(value.GetListDeprecated().begin()));
-  EXPECT_EQ(1u, value.GetListDeprecated().size());
-  EXPECT_EQ(3, value.GetListDeprecated()[0].GetInt());
+  EXPECT_EQ(1u, list.EraseValue(Value(1)));
+  EXPECT_EQ(1u, list.size());
+  EXPECT_EQ(3, list[0]);
 
-  EXPECT_TRUE(value.EraseListIter(value.GetListDeprecated().begin()));
-  EXPECT_TRUE(value.GetListDeprecated().empty());
+  EXPECT_EQ(1u, list.EraseValue(Value(3)));
+  EXPECT_TRUE(list.empty());
 
-  EXPECT_FALSE(value.EraseListIter(value.GetListDeprecated().begin()));
+  EXPECT_EQ(0u, list.EraseValue(Value(3)));
 }
 
-TEST(ValuesTest, EraseListValue) {
-  ListValue value;
-  value.Append(1);
-  value.Append(2);
-  value.Append(2);
-  value.Append(3);
+TEST(ValuesTest, ListEraseIf) {
+  Value::List list;
+  list.Append(1);
+  list.Append(2);
+  list.Append(2);
+  list.Append(3);
 
-  EXPECT_EQ(2u, value.EraseListValue(Value(2)));
-  EXPECT_EQ(2u, value.GetListDeprecated().size());
-  EXPECT_EQ(1, value.GetListDeprecated()[0].GetInt());
-  EXPECT_EQ(3, value.GetListDeprecated()[1].GetInt());
+  EXPECT_EQ(3u, list.EraseIf([](const auto& val) { return val >= Value(2); }));
+  EXPECT_EQ(1u, list.size());
+  EXPECT_EQ(1, list[0]);
 
-  EXPECT_EQ(1u, value.EraseListValue(Value(1)));
-  EXPECT_EQ(1u, value.GetListDeprecated().size());
-  EXPECT_EQ(3, value.GetListDeprecated()[0].GetInt());
+  EXPECT_EQ(1u, list.EraseIf([](const auto& val) { return true; }));
+  EXPECT_TRUE(list.empty());
 
-  EXPECT_EQ(1u, value.EraseListValue(Value(3)));
-  EXPECT_TRUE(value.GetListDeprecated().empty());
-
-  EXPECT_EQ(0u, value.EraseListValue(Value(3)));
-}
-
-TEST(ValuesTest, EraseListValueIf) {
-  ListValue value;
-  value.Append(1);
-  value.Append(2);
-  value.Append(2);
-  value.Append(3);
-
-  EXPECT_EQ(3u, value.EraseListValueIf(
-                    [](const auto& val) { return val >= Value(2); }));
-  EXPECT_EQ(1u, value.GetListDeprecated().size());
-  EXPECT_EQ(1, value.GetListDeprecated()[0].GetInt());
-
-  EXPECT_EQ(1u, value.EraseListValueIf([](const auto& val) { return true; }));
-  EXPECT_TRUE(value.GetListDeprecated().empty());
-
-  EXPECT_EQ(0u, value.EraseListValueIf([](const auto& val) { return true; }));
+  EXPECT_EQ(0u, list.EraseIf([](const auto& val) { return true; }));
 }
 
 TEST(ValuesTest, ClearList) {
diff --git a/build/config/c++/BUILD.gn b/build/config/c++/BUILD.gn
index 1478437e..f8bfa01 100644
--- a/build/config/c++/BUILD.gn
+++ b/build/config/c++/BUILD.gn
@@ -31,12 +31,6 @@
 
   include_dirs += [ "//buildtools/third_party/libc++" ]
 
-  # Work around a symbol conflict between GRPC and the Fuchsia SDK.
-  # TODO(crbug.com/1166970): Remove this when resolved.
-  if (is_fuchsia) {
-    defines += [ "_LIBCPP_NO_NATIVE_SEMAPHORES" ]
-  }
-
   # The Windows component build fails to link with libc++'s debug mode. See
   # https://crbug.com/923166#c33, https://crbug.com/923166#c44, and
   # https://llvm.org/PR41018.
diff --git a/build/config/fuchsia/size_optimized_cast_receiver_args_internal.gn b/build/config/fuchsia/size_optimized_cast_receiver_args_internal.gn
new file mode 100644
index 0000000..7a836a0
--- /dev/null
+++ b/build/config/fuchsia/size_optimized_cast_receiver_args_internal.gn
@@ -0,0 +1,17 @@
+# Copyright 2022 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.
+
+# This is a version of size_optimized_cast_receiver_args.gn that is intended for
+# internal builds and requires src-internal.
+#
+# To use it do one of the following:
+# * Add the following to your `gn args`:
+#   import("build/config/fuchsia/size_optimized_cast_receiver_args_internal.gn")
+# * Add the following to `gn_args` in a bot recipe:
+#   'args_file': '//build/config/fuchsia/size_optimized_cast_receiver_args_internal.gn'
+
+import("//build/config/fuchsia/size_optimized_cast_receiver_args.gn")
+
+use_internal_isolated_origins = true
+use_official_google_api_keys = false
diff --git a/chrome/VERSION b/chrome/VERSION
index e1a736a..f14e0099 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=107
 MINOR=0
-BUILD=5274
+BUILD=5275
 PATCH=0
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
index 22e73ed..44055dd 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
@@ -893,10 +893,9 @@
         assert mStartSurfaceState == StartSurfaceState.SHOWN_HOMEPAGE;
 
         if (mSecondaryTasksSurfacePropertyModel == null) {
-            mSecondaryTasksSurfaceController = mSecondaryTasksSurfaceInitializer.initialize();
+            TabSwitcher.Controller controller = mSecondaryTasksSurfaceInitializer.initialize();
             assert mSecondaryTasksSurfacePropertyModel != null;
-            mSecondaryTasksSurfaceController.isDialogVisibleSupplier().addObserver(
-                    (x) -> notifyBackPressStateChanged());
+            setSecondaryTasksSurfaceController(controller);
         }
 
         RecordUserAction.record("StartSurface.SinglePane.MoreTabs");
@@ -930,6 +929,8 @@
         mSecondaryTasksSurfaceController = secondaryTasksSurfaceController;
         mSecondaryTasksSurfaceController.isDialogVisibleSupplier().addObserver(
                 (v) -> notifyBackPressStateChanged());
+        mSecondaryTasksSurfaceController.getHandleBackPressChangedSupplier().addObserver(
+                (v) -> notifyBackPressStateChanged());
     }
 
     void setFeedPlaceholderHasShown() {
@@ -1004,7 +1005,6 @@
         // StartSurface is being supplied with OneShotSupplier, notification sends after
         // StartSurface is available to avoid missing events. More detail see:
         // https://crrev.com/c/2427428.
-        notifyBackPressStateChanged();
         mController.onHomepageChanged(mStartSurfaceState == StartSurfaceState.SHOWN_HOMEPAGE);
         if (mSecondaryTasksSurfaceController != null) {
             mSecondaryTasksSurfaceController.onHomepageChanged(
@@ -1015,6 +1015,7 @@
                 observer.onStateChanged(mStartSurfaceState, shouldShowTabSwitcherToolbar());
             }
         });
+        notifyBackPressStateChanged();
     }
 
     private boolean hasFakeSearchBox() {
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/SingleTabSwitcherMediator.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/SingleTabSwitcherMediator.java
index b345814..2fefb329 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/SingleTabSwitcherMediator.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/tasks/SingleTabSwitcherMediator.java
@@ -44,6 +44,8 @@
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.url.GURL;
 
+import java.util.List;
+
 /** Mediator of the single tab tab switcher. */
 public class SingleTabSwitcherMediator implements TabSwitcher.Controller {
     @VisibleForTesting
@@ -104,6 +106,21 @@
                 }
                 mTabSelectingListener.onTabSelecting(LayoutManagerImpl.time(), tab.getId());
             }
+
+            @Override
+            public void tabPendingClosure(Tab tab) {
+                mBackPressChangedSupplier.set(shouldInterceptBackPress());
+            }
+
+            @Override
+            public void multipleTabsPendingClosure(List<Tab> tabs, boolean isAllTabs) {
+                mBackPressChangedSupplier.set(shouldInterceptBackPress());
+            }
+
+            @Override
+            public void tabClosureUndone(Tab tab) {
+                mBackPressChangedSupplier.set(shouldInterceptBackPress());
+            }
         };
         mTabModelSelectorObserver = new TabModelSelectorObserver() {
             @Override
diff --git a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/tasks/SingleTabSwitcherMediatorUnitTest.java b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/tasks/SingleTabSwitcherMediatorUnitTest.java
index 4037b21..aefdb563 100644
--- a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/tasks/SingleTabSwitcherMediatorUnitTest.java
+++ b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/tasks/SingleTabSwitcherMediatorUnitTest.java
@@ -268,11 +268,16 @@
         assertTrue(mMediator.onBackPressed(false));
         verify(mOnTabSelectingListener).onTabSelecting(anyLong(), eq(mTabId));
 
+        mMediator.hideTabSwitcherView(true);
+        assertEquals(Boolean.FALSE, mMediator.getHandleBackPressChangedSupplier().get());
         doReturn(TabList.INVALID_TAB_INDEX).when(mTabModelSelector).getCurrentTabId();
+        mMediator.showTabSwitcherView(true);
+        assertEquals(Boolean.FALSE, mMediator.getHandleBackPressChangedSupplier().get());
         assertFalse(mMediator.onBackPressed(false));
 
         doReturn(mTabId).when(mTabModelSelector).getCurrentTabId();
         doReturn(true).when(mTabModelSelector).isIncognitoSelected();
+        assertEquals(Boolean.FALSE, mMediator.getHandleBackPressChangedSupplier().get());
         assertFalse(mMediator.onBackPressed(false));
     }
 }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherBackPressHandler.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherBackPressHandler.java
deleted file mode 100644
index 6544a50..0000000
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherBackPressHandler.java
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.tasks.tab_management;
-
-import org.chromium.base.lifetime.Destroyable;
-import org.chromium.base.supplier.ObservableSupplier;
-import org.chromium.base.supplier.ObservableSupplierImpl;
-import org.chromium.base.supplier.OneshotSupplier;
-import org.chromium.chrome.browser.layouts.LayoutStateProvider;
-import org.chromium.chrome.browser.layouts.LayoutStateProvider.LayoutStateObserver;
-import org.chromium.chrome.browser.layouts.LayoutType;
-import org.chromium.chrome.features.start_surface.StartSurface;
-import org.chromium.chrome.features.start_surface.StartSurfaceState;
-import org.chromium.components.browser_ui.widget.gesture.BackPressHandler;
-
-/**
- * A {@link BackPressHandler} intercepting back press to show {@link LayoutType#BROWSING} when
- * the tab switcher is showing.
- */
-public class TabSwitcherBackPressHandler
-        implements BackPressHandler, StartSurface.StateObserver, LayoutStateObserver, Destroyable {
-    private final OneshotSupplier<LayoutStateProvider> mLayoutStateProviderSupplier;
-    private final OneshotSupplier<StartSurface> mStartSurfaceSupplier;
-    private final Runnable mShowBrowsing;
-    private final boolean mIsStartSurfaceRefactorEnabled;
-    private final ObservableSupplierImpl<Boolean> mBackPressChangedSupplier =
-            new ObservableSupplierImpl<>();
-    public TabSwitcherBackPressHandler(
-            OneshotSupplier<LayoutStateProvider> layoutStateProviderSupplier,
-            OneshotSupplier<StartSurface> startSurfaceSupplier, Runnable showBrowsing,
-            boolean isStartSurfaceRefactorEnabled) {
-        layoutStateProviderSupplier.onAvailable(this::onLayoutStateProviderAvailable);
-        startSurfaceSupplier.onAvailable(this::onStartSurfaceAvailable);
-        mLayoutStateProviderSupplier = layoutStateProviderSupplier;
-        mStartSurfaceSupplier = startSurfaceSupplier;
-        mShowBrowsing = showBrowsing;
-        mIsStartSurfaceRefactorEnabled = isStartSurfaceRefactorEnabled;
-        onBackPressChanged();
-    }
-
-    @Override
-    public void onStateChanged(int startSurfaceState, boolean shouldShowTabSwitcherToolbar) {
-        onBackPressChanged();
-    }
-
-    @Override
-    public void onStartedShowing(int layoutType, boolean showToolbar) {
-        onBackPressChanged();
-    }
-
-    @Override
-    public void handleBackPress() {
-        mShowBrowsing.run();
-    }
-
-    @Override
-    public ObservableSupplier<Boolean> getHandleBackPressChangedSupplier() {
-        return mBackPressChangedSupplier;
-    }
-
-    @Override
-    public void destroy() {
-        if (mLayoutStateProviderSupplier.hasValue()) {
-            mLayoutStateProviderSupplier.get().removeObserver(this);
-        }
-        if (mStartSurfaceSupplier.hasValue()) {
-            mStartSurfaceSupplier.get().removeStateChangeObserver(this);
-        }
-    }
-
-    private void onLayoutStateProviderAvailable(LayoutStateProvider provider) {
-        provider.addObserver(this);
-        onBackPressChanged();
-    }
-
-    private void onStartSurfaceAvailable(StartSurface startSurface) {
-        if (mIsStartSurfaceRefactorEnabled) return;
-        // TODO(crbug.com/1315679): Remove |mStartSurfaceSupplier| and
-        // StartSurfaceStateChangeObserver when refactor flag is enabled by default.
-        startSurface.addStateChangeObserver(this);
-        onBackPressChanged();
-    }
-
-    private void onBackPressChanged() {
-        LayoutStateProvider provider = mLayoutStateProviderSupplier.get();
-        boolean isOverviewVisible = provider != null
-                && (provider.isLayoutVisible(LayoutType.TAB_SWITCHER)
-                        || provider.isLayoutVisible(LayoutType.START_SURFACE));
-        if (!isOverviewVisible) {
-            mBackPressChangedSupplier.set(false);
-            return;
-        }
-        StartSurface startSurface = mStartSurfaceSupplier.get();
-        boolean isStartSurfaceShownTabSwitcher = mIsStartSurfaceRefactorEnabled
-                ? provider.isLayoutVisible(LayoutType.TAB_SWITCHER)
-                : startSurface == null
-                        || startSurface.getStartSurfaceState()
-                                == StartSurfaceState.SHOWN_TABSWITCHER;
-        mBackPressChangedSupplier.set(isStartSurfaceShownTabSwitcher);
-    }
-}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java
index 01d1402d..be8991c 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java
@@ -371,6 +371,17 @@
                         && mPriceMessageService.getBindingTabId() == tab.getId()) {
                     priceWelcomeMessageController.restorePriceWelcomeMessage();
                 }
+                notifyBackPressStateChangedInternal();
+            }
+
+            @Override
+            public void tabPendingClosure(Tab tab) {
+                notifyBackPressStateChangedInternal();
+            }
+
+            @Override
+            public void multipleTabsPendingClosure(List<Tab> tabs, boolean isAllTabs) {
+                notifyBackPressStateChangedInternal();
             }
 
             @Override
diff --git a/chrome/android/features/tab_ui/tab_management_java_sources.gni b/chrome/android/features/tab_ui/tab_management_java_sources.gni
index d4e3940..0316b28d 100644
--- a/chrome/android/features/tab_ui/tab_management_java_sources.gni
+++ b/chrome/android/features/tab_ui/tab_management_java_sources.gni
@@ -13,7 +13,6 @@
   "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegate.java",
   "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementModuleProvider.java",
   "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcher.java",
-  "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherBackPressHandler.java",
   "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayout.java",
   "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiFeatureUtilities.java",
   "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java",
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 31f1535..415da484 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -178,7 +178,6 @@
 import org.chromium.chrome.browser.tasks.tab_management.TabGroupUi;
 import org.chromium.chrome.browser.tasks.tab_management.TabManagementModuleProvider;
 import org.chromium.chrome.browser.tasks.tab_management.TabSwitcher;
-import org.chromium.chrome.browser.tasks.tab_management.TabSwitcherBackPressHandler;
 import org.chromium.chrome.browser.tasks.tab_management.TabUiFeatureUtilities;
 import org.chromium.chrome.browser.toolbar.ToolbarButtonInProductHelpController;
 import org.chromium.chrome.browser.toolbar.ToolbarIntentMetadata;
@@ -388,7 +387,6 @@
 
     private ReturnToChromeBackPressHandler mReturnToChromeBackPressHandler;
     private ReadingListBackPressHandler mReadingListBackPressHandler;
-    private TabSwitcherBackPressHandler mTabSwitcherBackPressHandler;
     private MinimizeAppAndCloseTabBackPressHandler mMinimizeAppAndCloseTabBackPressHandler;
 
     // ID assigned to each ChromeTabbedActivity instance in Android S+ where multi-instance feature
@@ -2274,17 +2272,6 @@
             return true;
         }
 
-        // If we are in the tab switcher mode (not in the Start surface homepage) and not a tablet,
-        // then leave tab switcher mode on back.
-        if (isInOverviewMode() && !isTablet()
-                && (mStartSurfaceSupplier.get() == null
-                        || mStartSurfaceSupplier.get().getStartSurfaceState()
-                                == StartSurfaceState.SHOWN_TABSWITCHER)) {
-            mLayoutManager.showLayout(LayoutType.BROWSING, true);
-            BackPressManager.record(BackPressHandler.Type.TAB_SWITCHER_TO_BROWSING);
-            return true;
-        }
-
         final WebContents webContents = currentTab.getWebContents();
         if (webContents != null) {
             RenderFrameHost focusedFrame = webContents.getFocusedFrame();
@@ -2367,15 +2354,6 @@
             mBackPressManager.addHandler(
                     mReadingListBackPressHandler, BackPressHandler.Type.SHOW_READING_LIST);
         }
-        if (mTabSwitcherBackPressHandler == null && !isTablet()) {
-            mTabSwitcherBackPressHandler = new TabSwitcherBackPressHandler(
-                    mLayoutStateProviderSupplier, mStartSurfaceSupplier,
-                    ()
-                            -> mLayoutManager.showLayout(LayoutType.BROWSING, true),
-                    ReturnToChromeUtil.isTabSwitcherOnlyRefactorEnabled(this));
-            mBackPressManager.addHandler(
-                    mTabSwitcherBackPressHandler, BackPressHandler.Type.TAB_SWITCHER_TO_BROWSING);
-        }
         if (mMinimizeAppAndCloseTabBackPressHandler == null) {
             mMinimizeAppAndCloseTabBackPressHandler =
                     new MinimizeAppAndCloseTabBackPressHandler(getTabModelSelectorSupplier(),
@@ -2642,10 +2620,6 @@
             mReadingListBackPressHandler.destroy();
             mReadingListBackPressHandler = null;
         }
-        if (mTabSwitcherBackPressHandler != null) {
-            mTabSwitcherBackPressHandler.destroy();
-            mTabSwitcherBackPressHandler = null;
-        }
         if (mMinimizeAppAndCloseTabBackPressHandler != null) {
             mMinimizeAppAndCloseTabBackPressHandler.destroy();
             mMinimizeAppAndCloseTabBackPressHandler = null;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/feed/FeedActionDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/app/feed/FeedActionDelegateImpl.java
index 9bc1f93..a8654488 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/feed/FeedActionDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/feed/FeedActionDelegateImpl.java
@@ -104,8 +104,17 @@
 
     @Override
     public void openCrow(String url) {
-        mCrowButtonDelegate.launchCustomTab(
-                mActivityContext, new GURL(url), GURL.emptyGURL(), /*isFollowing=*/true);
+        if (ChromeFeatureList.isInitialized()
+                && ChromeFeatureList.isEnabled(ChromeFeatureList.SHARE_CROW_BUTTON_LAUNCH_TAB)) {
+            String tabUrl = mCrowButtonDelegate.getUrlForWebFlow(
+                    new GURL(url), GURL.emptyGURL(), /*isFollowing=*/true);
+            mNavigationDelegate.openUrl(
+                    WindowOpenDisposition.NEW_FOREGROUND_TAB, new LoadUrlParams(tabUrl));
+        } else {
+            mCrowButtonDelegate.launchCustomTab(
+                    /*tab=*/null, mActivityContext, new GURL(url), GURL.emptyGURL(),
+                    /*isFollowing=*/true);
+        }
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java
index 555bef94..e58e7b4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java
@@ -50,6 +50,7 @@
 import org.chromium.base.MathUtils;
 import org.chromium.base.SysUtils;
 import org.chromium.base.ThreadUtils;
+import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.customtabs.features.CustomTabNavigationBarController;
 import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbar;
@@ -150,6 +151,19 @@
     // but using height for the close animation.
     private Consumer<Integer> mTabAnimator = this::updateWindowPos;
 
+    // These values are persisted to logs. Entries should not be renumbered and
+    // numeric values should never be reused.
+    // This should be kept in sync with the definition |CustomTabsResizeType|
+    // in tools/metrics/histograms/enums.xml.
+    @IntDef({ResizeType.EXPANSION, ResizeType.MINIMIZATION, ResizeType.COUNT})
+    @Retention(RetentionPolicy.SOURCE)
+    @VisibleForTesting
+    @interface ResizeType {
+        int EXPANSION = 0;
+        int MINIMIZATION = 1;
+        int COUNT = 2;
+    }
+
     /** A callback to be called once the Custom Tab has been resized. */
     interface OnResizedCallback {
         /** The Custom Tab has been resized. */
@@ -743,6 +757,14 @@
             mFinishRunnable.run();
             return;
         }
+
+        int draggingEndY = mActivity.getWindow().getAttributes().y;
+        if (mDraggingStartY >= 0 && mDraggingStartY != draggingEndY) {
+            RecordHistogram.recordEnumeratedHistogram("CustomTabs.ResizeType",
+                    mDraggingStartY < draggingEndY ? ResizeType.MINIMIZATION : ResizeType.EXPANSION,
+                    ResizeType.COUNT);
+        }
+
         hideSpinnerView();
         if (mWindowAboveNavbar) {
             Window window = mActivity.getWindow();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegateImpl.java
index b105962..970638d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegateImpl.java
@@ -18,8 +18,11 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.signin.services.UnifiedConsentServiceBridge;
 import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tab.TabLaunchType;
+import org.chromium.chrome.browser.tabmodel.document.TabDelegate;
 import org.chromium.components.optimization_guide.OptimizationGuideDecision;
 import org.chromium.components.optimization_guide.proto.HintsProto;
+import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.ui.util.ColorUtils;
 import org.chromium.url.GURL;
 
@@ -91,19 +94,28 @@
 
     @Override
     public void launchCustomTab(
-            Context currentContext, GURL pageUrl, GURL canonicalUrl, boolean isFollowing) {
-        String customTabUrl = buildServerUrl(new GURL(getServerUrl()), pageUrl, canonicalUrl,
-                getPublicationId(pageUrl), areMetricsEnabled(), isFollowing);
+            Tab tab, Context currentContext, GURL pageUrl, GURL canonicalUrl, boolean isFollowing) {
+        String customTabUrl = getUrlForWebFlow(pageUrl, canonicalUrl, isFollowing);
 
-        CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
-        builder.setShowTitle(true);
-        builder.setColorScheme(ColorUtils.inNightMode(currentContext)
-                        ? CustomTabsIntent.COLOR_SCHEME_DARK
-                        : CustomTabsIntent.COLOR_SCHEME_LIGHT);
-        builder.setShareState(CustomTabsIntent.SHARE_STATE_OFF);
-        CustomTabsIntent customTabsIntent = builder.build();
-        customTabsIntent.intent.setClassName(currentContext, CustomTabActivity.class.getName());
-        customTabsIntent.launchUrl(currentContext, Uri.parse(customTabUrl));
+        // Experiment flag: open in standard new tab.
+        if (ChromeFeatureList.isInitialized()
+                && ChromeFeatureList.isEnabled(ChromeFeatureList.SHARE_CROW_BUTTON_LAUNCH_TAB)) {
+            // TabLaunchType.FROM_LINK will allow back to navigate back to the
+            // current tab.
+            LoadUrlParams loadUrlParams = new LoadUrlParams(customTabUrl);
+            new TabDelegate(false).createNewTab(loadUrlParams, TabLaunchType.FROM_LINK, tab);
+        } else {
+            // Default to custom tab.
+            CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
+            builder.setShowTitle(true);
+            builder.setColorScheme(ColorUtils.inNightMode(currentContext)
+                            ? CustomTabsIntent.COLOR_SCHEME_DARK
+                            : CustomTabsIntent.COLOR_SCHEME_LIGHT);
+            builder.setShareState(CustomTabsIntent.SHARE_STATE_OFF);
+            CustomTabsIntent customTabsIntent = builder.build();
+            customTabsIntent.intent.setClassName(currentContext, CustomTabActivity.class.getName());
+            customTabsIntent.launchUrl(currentContext, Uri.parse(customTabUrl));
+        }
     }
 
     public boolean isCrowEnabled() {
@@ -187,8 +199,14 @@
                         Profile.getLastUsedRegularProfile()));
     }
 
+    @Override
+    public String getUrlForWebFlow(GURL pageUrl, GURL canonicalPageUrl, boolean isFollowing) {
+        return buildServerUrlInternal(new GURL(getServerUrl()), pageUrl, canonicalPageUrl,
+                getPublicationId(pageUrl), areMetricsEnabled(), isFollowing);
+    }
+
     @VisibleForTesting
-    public String buildServerUrl(GURL serverUrl, GURL pageUrl, GURL canonicalPageUrl,
+    public String buildServerUrlInternal(GURL serverUrl, GURL pageUrl, GURL canonicalPageUrl,
             String publicationId, boolean allowMetrics, boolean isFollowing) {
         String serverSpec = serverUrl.getSpec();
         if (serverSpec.isEmpty()) return "";
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegateImplTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegateImplTest.java
index 54943fe..a9147d0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegateImplTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegateImplTest.java
@@ -43,39 +43,39 @@
         boolean isFollowing = false;
 
         assertEquals("",
-                delegate.buildServerUrl(
+                delegate.buildServerUrlInternal(
                         GURL.emptyGURL(), shareUrl1, shareUrl1, "", allowMetrics, isFollowing));
 
         // Baseline/common case.
         assertEquals(
                 "https://www.foo.com/v1/api?q=hi&pageUrl=https%3A%2F%2Ftestsitewearesharing.com%2Fblog%2Fentry&entry=menu&relCanonUrl=https%3A%2F%2Ftestsitewearesharing.com%2Fblog%2Fentry&publicationId=pubId1&metrics=true",
-                delegate.buildServerUrl(
+                delegate.buildServerUrlInternal(
                         serverUrl, shareUrl1, shareUrl1, "pubId1", allowMetrics, isFollowing));
 
         // Sending a URL with urlparams of its own.
         assertEquals(
                 "https://www.foo.com/v1/api?q=hi&pageUrl=https%3A%2F%2Ftestsitewearesharing.com%2F%3Fblog%3D1%26entry%3D2&entry=menu&relCanonUrl=https%3A%2F%2Ftestsitewearesharing.com%2F%3Fblog%3D1%26entry%3D2&publicationId=pubId2&metrics=true",
-                delegate.buildServerUrl(
+                delegate.buildServerUrlInternal(
                         serverUrl, shareUrl2, shareUrl2, "pubId2", allowMetrics, isFollowing));
 
         // Empty canonical URL is ok, passes as empty param.
         assertEquals(
                 "https://www.foo.com/v1/api?q=hi&pageUrl=https%3A%2F%2Ftestsitewearesharing.com%2Fblog%2Fentry&entry=menu&relCanonUrl=&publicationId=pubId1&metrics=true",
-                delegate.buildServerUrl(serverUrl, shareUrl1, GURL.emptyGURL(), "pubId1",
+                delegate.buildServerUrlInternal(serverUrl, shareUrl1, GURL.emptyGURL(), "pubId1",
                         allowMetrics, isFollowing));
 
         // Experimental URL can be passed with an empty set of params.
         assertEquals(
                 "http://www.foo.com/v1/api?pageUrl=https%3A%2F%2Ftestsitewearesharing.com%2Fblog%2Fentry&entry=menu&relCanonUrl=https%3A%2F%2Ftestsitewearesharing.com%2Fblog%2Fentry&publicationId=pubId1&metrics=true",
-                delegate.buildServerUrl(serverUrlWithoutQueryString, shareUrl1, shareUrl1, "pubId1",
-                        allowMetrics, isFollowing));
+                delegate.buildServerUrlInternal(serverUrlWithoutQueryString, shareUrl1, shareUrl1,
+                        "pubId1", allowMetrics, isFollowing));
 
         // Metrics off and already following should be reflected.
         allowMetrics = false;
         isFollowing = true;
         assertEquals(
                 "https://www.foo.com/v1/api?q=hi&pageUrl=https%3A%2F%2Ftestsitewearesharing.com%2Fblog%2Fentry&entry=menu&relCanonUrl=https%3A%2F%2Ftestsitewearesharing.com%2Fblog%2Fentry&publicationId=pubId1&metrics=false&following=true",
-                delegate.buildServerUrl(
+                delegate.buildServerUrlInternal(
                         serverUrl, shareUrl1, shareUrl1, "pubId1", allowMetrics, isFollowing));
     }
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategyTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategyTest.java
index a4ac94d..ee2737413 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategyTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategyTest.java
@@ -62,6 +62,7 @@
 import org.chromium.base.Callback;
 import org.chromium.base.CommandLine;
 import org.chromium.base.ContextUtils;
+import org.chromium.base.test.util.MetricsUtils.HistogramDelta;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.customtabs.PartialCustomTabHeightStrategy.PartialCustomTabHandleStrategy;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
@@ -729,6 +730,56 @@
         verify(mDragHandlebar).setVisibility(View.GONE);
     }
 
+    @Test
+    public void invokeResizeCallbackExpansion() {
+        PartialCustomTabHeightStrategy strategy = createPcctAtHeight(500);
+        verifyWindowFlagsSet();
+
+        assertEquals(
+                "mAttributeResults should have exactly 1 element.", 1, mAttributeResults.size());
+        assertTabIsAtInitialPos(mAttributeResults.get(0));
+
+        PartialCustomTabHandleStrategy handleStrategy =
+                strategy.new PartialCustomTabHandleStrategy(null);
+
+        int expected = PartialCustomTabHeightStrategy.ResizeType.EXPANSION;
+        HistogramDelta histogramExpansion = new HistogramDelta("CustomTabs.ResizeType", expected);
+
+        // Drag to the top.
+        assertTabIsFullHeight(dragTab(handleStrategy, 1500, 1000, 0));
+
+        // invokeResizeCallback() should have been called and ResizeType.EXPANSION logged once.
+        assertEquals(
+                "ResizeType.EXPANSION should be recorded once.", 1, histogramExpansion.getDelta());
+    }
+
+    @Test
+    public void invokeResizeCallbackMinimization() {
+        PartialCustomTabHeightStrategy strategy = createPcctAtHeight(500);
+        verifyWindowFlagsSet();
+
+        assertEquals(
+                "mAttributeResults should have exactly 1 element.", 1, mAttributeResults.size());
+        assertTabIsAtInitialPos(mAttributeResults.get(0));
+
+        PartialCustomTabHandleStrategy handleStrategy =
+                strategy.new PartialCustomTabHandleStrategy(null);
+
+        // Drag to the top so it can be minimized in the next step.
+        assertTabIsFullHeight(dragTab(handleStrategy, 1500, 1000, 0));
+
+        int expected = PartialCustomTabHeightStrategy.ResizeType.MINIMIZATION;
+        HistogramDelta histogramMinimization =
+                new HistogramDelta("CustomTabs.ResizeType", expected);
+
+        // Drag down enough -> slide to the initial position.
+        assertTabIsAtInitialPos(dragTab(handleStrategy, 50, 650, 1300));
+
+        // invokeResizeCallback() should have been called and ResizeType.MINIMIZATION logged once.
+        assertEquals("ResizeType.MINIMIZATION should be recorded once.", 1,
+                histogramMinimization.getDelta());
+    }
+
     private void verifyWindowFlagsSet() {
         verify(mWindow).addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
         verify(mWindow).clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 74768be..3eda6103 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-107.0.5270.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-amd64-107.0.5271.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp
index 86ffa05..0d82528 100644
--- a/chrome/app/os_settings_strings.grdp
+++ b/chrome/app/os_settings_strings.grdp
@@ -4440,7 +4440,7 @@
     If you move away from your device, your screen will lock automatically. When you're in front of your device, your screen will stay awake longer. If you aren't using a lock screen, your device will sleep instead of lock.
   </message>
   <message name="IDS_OS_SETTINGS_SMART_PRIVACY_SNOOPING_TITLE" desc="Text in the smart privacy section which is the subheader for snooping protection options.">
-    Viewing protection
+    Viewing protection (Beta)
   </message>
   <message name="IDS_OS_SETTINGS_SMART_PRIVACY_SNOOPING_SUBTEXT" desc="Sub-label elaborating on the meaning of snooping protection.">
     When someone else looks at your screen, show the Privacy eye icon on the bottom right of your screen
diff --git a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SMART_PRIVACY_SNOOPING_TITLE.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SMART_PRIVACY_SNOOPING_TITLE.png.sha1
index cbbabe2..7f2758b 100644
--- a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SMART_PRIVACY_SNOOPING_TITLE.png.sha1
+++ b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SMART_PRIVACY_SNOOPING_TITLE.png.sha1
@@ -1 +1 @@
-24b763e83948c424b7bfdc46881da886778b47eb
\ No newline at end of file
+1e3ca564d0be5c7d0e717f8bf5ad950b86aba326
\ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index c7507e720..1b4442d7 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2790,6 +2790,7 @@
 constexpr char kBorealisPermittedInternalName[] = "borealis-enabled";
 constexpr char kBorealisStorageBallooningInternalName[] =
     "borealis-storage-ballooning";
+constexpr char kVmPerBootShaderCacheName[] = "vm-per-boot-shader-cache";
 constexpr char kClipboardHistoryReorderInternalName[] =
     "clipboard-history-reorder";
 constexpr char kWelcomeScreenInternalName[] = "welcome-screen";
@@ -3715,9 +3716,6 @@
      flag_descriptions::kCellularCustomAPNProfilesName,
      flag_descriptions::kCellularCustomAPNProfilesDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(chromeos::features::kCellularCustomAPNProfiles)},
-    {"cellular-use-attach-apn", flag_descriptions::kCellularUseAttachApnName,
-     flag_descriptions::kCellularUseAttachApnDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(chromeos::features::kCellularUseAttachApn)},
     {"cellular-use-second-euicc",
      flag_descriptions::kCellularUseSecondEuiccName,
      flag_descriptions::kCellularUseSecondEuiccDescription, kOsCrOS,
@@ -4205,7 +4203,10 @@
      FEATURE_WITH_PARAMS_VALUE_TYPE(chrome::android::kChromeShareLongScreenshot,
                                     kLongScreenshotVariations,
                                     "ChromeShareLongScreenshot")},
-
+    {"chrome-sharing-crow-launch-tab",
+     flag_descriptions::kChromeSharingCrowLaunchTabName,
+     flag_descriptions::kChromeSharingCrowLaunchTabDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(share::kCrowLaunchTab)},
     {"chrome-sharing-hub-launch-adjacent",
      flag_descriptions::kChromeSharingHubLaunchAdjacentName,
      flag_descriptions::kChromeSharingHubLaunchAdjacentDescription, kOsAndroid,
@@ -4927,6 +4928,10 @@
      kOsCrOS,
      FEATURE_VALUE_TYPE(
          chromeos::features::kSystemTransliterationPhysicalTyping)},
+    {"enable-cros-touch-text-editing-redesign",
+     flag_descriptions::kTouchTextEditingRedesignName,
+     flag_descriptions::kTouchTextEditingRedesignDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(chromeos::features::kTouchTextEditingRedesign)},
     {"enable-cros-virtual-keyboard-bordered-key",
      flag_descriptions::kVirtualKeyboardBorderedKeyName,
      flag_descriptions::kVirtualKeyboardBorderedKeyDescription, kOsCrOS,
@@ -8394,6 +8399,9 @@
      flag_descriptions::kBorealisStorageBallooningName,
      flag_descriptions::kBorealisStorageBallooningDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(ash::features::kBorealisStorageBallooning)},
+    {kVmPerBootShaderCacheName, flag_descriptions::kVmPerBootShaderCacheName,
+     flag_descriptions::kVmPerBootShaderCacheDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(ash::features::kVmPerBootShaderCache)},
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
     {"https-only-mode-setting", flag_descriptions::kHttpsOnlyModeName,
@@ -9294,6 +9302,11 @@
                                     "BindingManagerConnectionLimit")},
 #endif
 
+    {"sync-access-handle-all-sync-surface",
+     flag_descriptions::kSyncAccessHandleAllSyncSurfaceName,
+     flag_descriptions::kSyncAccessHandleAllSyncSurfaceDescription, kOsAll,
+     FEATURE_VALUE_TYPE(blink::features::kSyncAccessHandleAllSyncSurface)},
+
     // NOTE: Adding a new flag requires adding a corresponding entry to enum
     // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag
     // Histograms" in tools/metrics/histograms/README.md (run the
diff --git a/chrome/browser/apps/app_service/app_service_proxy_factory.cc b/chrome/browser/apps/app_service/app_service_proxy_factory.cc
index 3504fd3..97757d45 100644
--- a/chrome/browser/apps/app_service/app_service_proxy_factory.cc
+++ b/chrome/browser/apps/app_service/app_service_proxy_factory.cc
@@ -63,11 +63,11 @@
   // once we have audited and removed code paths that call here with a profile
   // that doesn't have an App Service.
   if (!IsAppServiceAvailableForProfile(profile)) {
-    DVLOG(1) << "Called AppServiceProxyFactory::GetForProfile() on a profile "
-                "which does not contain an AppServiceProxy. Please check "
-                "whether this is appropriate as you may be leaking information "
-                "out of this profile. Returning the AppServiceProxy attached "
-                "to the parent profile instead.";
+    // See comments in app_service_proxy_factory.h for how to handle profiles
+    // with no AppServiceProxy. As an interim measure, we return the parent
+    // profile in non-guest Incognito profiles.
+    LOG(ERROR) << "Called AppServiceProxyFactory::GetForProfile() on a profile "
+                  "which does not contain an AppServiceProxy";
     // Fail tests that would trigger DumpWithoutCrashing.
     DCHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch(
         switches::kTestType));
diff --git a/chrome/browser/apps/app_service/app_service_proxy_factory.h b/chrome/browser/apps/app_service/app_service_proxy_factory.h
index 19650c7..9175644 100644
--- a/chrome/browser/apps/app_service/app_service_proxy_factory.h
+++ b/chrome/browser/apps/app_service/app_service_proxy_factory.h
@@ -17,8 +17,21 @@
 // Singleton that owns all AppServiceProxy's and associates them with Profile.
 class AppServiceProxyFactory : public BrowserContextKeyedServiceFactory {
  public:
+  // Returns true if App Service is available for use in the given `profile`.
+  // App Service is unavailable in profiles which do not run apps (e.g.
+  // non-guest Incognito profiles).
+  // All client code which uses AppServiceProxy should verify that App Service
+  // is available before calling GetForProfile. When App Service is unavailable,
+  // a common pattern is to fall back to an associated real profile (e.g. the
+  // parent of the incognito profile). As this constitutes a data leak out of
+  // Incognito, it is up to individual client teams to decide whether this is
+  // appropriate behavior for their feature. Alternatively, feature teams can
+  // disable the App Service integration in these profiles.
   static bool IsAppServiceAvailableForProfile(Profile* profile);
 
+  // Returns the AppServiceProxy instance for the given `profile`. Should only
+  // be called with a profile for which IsAppServiceAvailableForProfile returns
+  // true.
   static AppServiceProxy* GetForProfile(Profile* profile);
 
   static AppServiceProxyFactory* GetInstance();
diff --git a/chrome/browser/apps/app_service/metrics/app_platform_metrics.h b/chrome/browser/apps/app_service/metrics/app_platform_metrics.h
index c4e220bc..1fe24ce8 100644
--- a/chrome/browser/apps/app_service/metrics/app_platform_metrics.h
+++ b/chrome/browser/apps/app_service/metrics/app_platform_metrics.h
@@ -19,7 +19,6 @@
 #include "components/services/app_service/public/cpp/app_registry_cache.h"
 #include "components/services/app_service/public/cpp/app_types.h"
 #include "components/services/app_service/public/cpp/instance_registry.h"
-#include "components/services/app_service/public/mojom/types.mojom.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
 
 class Profile;
diff --git a/chrome/browser/apps/app_service/metrics/app_platform_metrics_browsertest.cc b/chrome/browser/apps/app_service/metrics/app_platform_metrics_browsertest.cc
index a9ee73a3..8e20897 100644
--- a/chrome/browser/apps/app_service/metrics/app_platform_metrics_browsertest.cc
+++ b/chrome/browser/apps/app_service/metrics/app_platform_metrics_browsertest.cc
@@ -18,7 +18,6 @@
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/services/app_service/public/cpp/app_launch_util.h"
-#include "components/services/app_service/public/mojom/types.mojom.h"
 #include "content/public/test/browser_test.h"
 #include "third_party/blink/public/mojom/manifest/display_mode.mojom.h"
 #include "url/gurl.h"
diff --git a/chrome/browser/apps/app_service/metrics/app_platform_metrics_service_unittest.cc b/chrome/browser/apps/app_service/metrics/app_platform_metrics_service_unittest.cc
index 4b32d55..b3cb90744 100644
--- a/chrome/browser/apps/app_service/metrics/app_platform_metrics_service_unittest.cc
+++ b/chrome/browser/apps/app_service/metrics/app_platform_metrics_service_unittest.cc
@@ -198,25 +198,6 @@
   return app;
 }
 
-void AddMojomApp(
-    apps::AppRegistryCache& cache,
-    const std::string& app_id,
-    apps::mojom::AppType app_type,
-    const std::string& publisher_id,
-    apps::mojom::Readiness readiness,
-    apps::mojom::InstallReason install_reason,
-    apps::mojom::InstallSource install_source,
-    bool should_notify_initialized,
-    apps::mojom::OptionalBool is_platform_app =
-        apps::mojom::OptionalBool::kUnknown,
-    apps::mojom::WindowMode window_mode = apps::mojom::WindowMode::kUnknown) {
-  std::vector<apps::mojom::AppPtr> deltas;
-  deltas.push_back(MakeApp(app_id, app_type, publisher_id, readiness,
-                           install_reason, install_source, is_platform_app,
-                           window_mode));
-  cache.OnApps(std::move(deltas), app_type, should_notify_initialized);
-}
-
 void AddApp(apps::AppRegistryCache& cache,
             const std::string& app_id,
             apps::AppType app_type,
@@ -232,13 +213,6 @@
                            install_reason, install_source, is_platform_app,
                            window_mode));
   cache.OnApps(std::move(deltas), app_type, should_notify_initialized);
-
-  AddMojomApp(cache, app_id, apps::ConvertAppTypeToMojomAppType(app_type),
-              publisher_id, apps::ConvertReadinessToMojomReadiness(readiness),
-              apps::ConvertInstallReasonToMojomInstallReason(install_reason),
-              apps::ConvertInstallSourceToMojomInstallSource(install_source),
-              should_notify_initialized, GetMojomOptionalBool(is_platform_app),
-              ConvertWindowModeToMojomWindowMode(window_mode));
 }
 
 std::unique_ptr<KeyedService> TestingSyncFactoryFunction(
@@ -351,9 +325,10 @@
            Readiness::kReady, InstallReason::kUser, InstallSource::kPlayStore,
            true /* should_notify_initialized */);
 
+    // BuiltIn apps are initialized by the BuiltIn app publisher.
     AddApp(cache, /*app_id=*/"bu", AppType::kBuiltIn, "", Readiness::kReady,
            InstallReason::kSystem, InstallSource::kSystem,
-           true /* should_notify_initialized */);
+           false /* should_notify_initialized */);
 
     AddApp(cache, /*app_id=*/borealis::kClientAppId, AppType::kBorealis, "",
            Readiness::kReady, InstallReason::kUser, InstallSource::kUnknown,
@@ -424,30 +399,6 @@
         InstallReason::kSubApp, InstallSource::kUnknown));
     cache.OnApps(std::move(deltas), AppType::kUnknown,
                  false /* should_notify_initialized */);
-
-    std::vector<apps::mojom::AppPtr> mojom_deltas;
-    mojom_deltas.push_back(MakeApp(
-        /*app_id=*/"u", apps::mojom::AppType::kUnknown, "",
-        apps::mojom::Readiness::kReady, apps::mojom::InstallReason::kUnknown,
-        apps::mojom::InstallSource::kUnknown));
-    mojom_deltas.push_back(MakeApp(
-        /*app_id=*/"m", apps::mojom::AppType::kMacOs, "",
-        apps::mojom::Readiness::kReady, apps::mojom::InstallReason::kUnknown,
-        apps::mojom::InstallSource::kUnknown));
-    mojom_deltas.push_back(MakeApp(
-        /*app_id=*/"p", apps::mojom::AppType::kPluginVm, "",
-        apps::mojom::Readiness::kReady, apps::mojom::InstallReason::kUser,
-        apps::mojom::InstallSource::kUnknown));
-    mojom_deltas.push_back(MakeApp(
-        /*app_id=*/"r", apps::mojom::AppType::kRemote, "",
-        apps::mojom::Readiness::kReady, apps::mojom::InstallReason::kPolicy,
-        apps::mojom::InstallSource::kUnknown));
-    mojom_deltas.push_back(MakeApp(
-        /*app_id=*/"subapp", apps::mojom::AppType::kWeb, "",
-        apps::mojom::Readiness::kReady, apps::mojom::InstallReason::kSubApp,
-        apps::mojom::InstallSource::kUnknown));
-    cache.OnApps(std::move(mojom_deltas), apps::mojom::AppType::kUnknown,
-                 false /* should_notify_initialized */);
   }
 
   void InstallOneApp(const std::string& app_id,
@@ -855,8 +806,8 @@
 
   void VerifyInstalledAppsUkm(const std::string& app_info,
                               AppTypeName app_type_name,
-                              apps::mojom::InstallReason install_reason,
-                              apps::mojom::InstallSource install_source,
+                              apps::InstallReason install_reason,
+                              apps::InstallSource install_source,
                               InstallTime install_time) {
     const auto entries =
         test_ukm_recorder()->GetEntriesByName("ChromeOSApp.InstalledApp");
@@ -2041,42 +1992,38 @@
 TEST_P(AppPlatformMetricsServiceTest, InstalledAppsUkm) {
   // Verify the apps installed during the init phase.
   VerifyInstalledAppsUkm("app://com.google.A", AppTypeName::kArc,
-                         apps::mojom::InstallReason::kUser,
-                         apps::mojom::InstallSource::kPlayStore,
-                         InstallTime::kInit);
-  VerifyInstalledAppsUkm(
-      "app://bu", AppTypeName::kBuiltIn, apps::mojom::InstallReason::kSystem,
-      apps::mojom::InstallSource::kSystem, InstallTime::kInit);
-  VerifyInstalledAppsUkm(
-      "app://s", AppTypeName::kSystemWeb, apps::mojom::InstallReason::kSystem,
-      apps::mojom::InstallSource::kSystem, InstallTime::kInit);
+                         apps::InstallReason::kUser,
+                         apps::InstallSource::kPlayStore, InstallTime::kInit);
+  VerifyInstalledAppsUkm("app://bu", AppTypeName::kBuiltIn,
+                         apps::InstallReason::kSystem,
+                         apps::InstallSource::kSystem, InstallTime::kRunning);
+  VerifyInstalledAppsUkm("app://s", AppTypeName::kSystemWeb,
+                         apps::InstallReason::kSystem,
+                         apps::InstallSource::kSystem, InstallTime::kInit);
   VerifyInstalledAppsUkm("https://foo.com", GetWebAppTypeName(),
-                         apps::mojom::InstallReason::kSync,
-                         apps::mojom::InstallSource::kSync, InstallTime::kInit);
+                         apps::InstallReason::kSync, apps::InstallSource::kSync,
+                         InstallTime::kInit);
+  VerifyInstalledAppsUkm("app://" + std::string(app_constants::kLacrosAppId),
+                         AppTypeName::kStandaloneBrowser,
+                         apps::InstallReason::kSystem,
+                         apps::InstallSource::kSystem, InstallTime::kInit);
   VerifyInstalledAppsUkm(
-      "app://" + std::string(app_constants::kLacrosAppId),
-      AppTypeName::kStandaloneBrowser, apps::mojom::InstallReason::kSystem,
-      apps::mojom::InstallSource::kSystem, InstallTime::kInit);
-  VerifyInstalledAppsUkm("app://" + std::string(kChromeAppId),
-                         AppTypeName::kStandaloneBrowserChromeApp,
-                         apps::mojom::InstallReason::kUser,
-                         apps::mojom::InstallSource::kChromeWebStore,
-                         InstallTime::kInit);
-  VerifyInstalledAppsUkm("app://" + std::string(kExtensionId),
-                         AppTypeName::kStandaloneBrowserExtension,
-                         apps::mojom::InstallReason::kUser,
-                         apps::mojom::InstallSource::kChromeWebStore,
-                         InstallTime::kInit);
+      "app://" + std::string(kChromeAppId),
+      AppTypeName::kStandaloneBrowserChromeApp, apps::InstallReason::kUser,
+      apps::InstallSource::kChromeWebStore, InstallTime::kInit);
+  VerifyInstalledAppsUkm(
+      "app://" + std::string(kExtensionId),
+      AppTypeName::kStandaloneBrowserExtension, apps::InstallReason::kUser,
+      apps::InstallSource::kChromeWebStore, InstallTime::kInit);
 
   // Install a new ARC app during the running time.
   InstallOneApp("aa", AppType::kArc, "com.google.AA", Readiness::kReady,
                 InstallSource::kPlayStore);
 
   // Verify the ARC app installed during the running time.
-  VerifyInstalledAppsUkm("app://com.google.AA", AppTypeName::kArc,
-                         apps::mojom::InstallReason::kUser,
-                         apps::mojom::InstallSource::kPlayStore,
-                         InstallTime::kRunning);
+  VerifyInstalledAppsUkm(
+      "app://com.google.AA", AppTypeName::kArc, apps::InstallReason::kUser,
+      apps::InstallSource::kPlayStore, InstallTime::kRunning);
 
   // Install Chrome apps (hosted apps) during the running time.
   std::string kChromeAppId1 = "bb";
@@ -2093,12 +2040,12 @@
   // Verify Chrome apps (hosted apps) installed during the running time.
   VerifyInstalledAppsUkm(
       "app://" + kChromeAppId1, AppTypeName::kStandaloneBrowser,
-      apps::mojom::InstallReason::kUser,
-      apps::mojom::InstallSource::kChromeWebStore, InstallTime::kRunning);
+      apps::InstallReason::kUser, apps::InstallSource::kChromeWebStore,
+      InstallTime::kRunning);
   VerifyInstalledAppsUkm(
       "app://" + kChromeAppId2, AppTypeName::kStandaloneBrowserChromeApp,
-      apps::mojom::InstallReason::kUser,
-      apps::mojom::InstallSource::kChromeWebStore, InstallTime::kRunning);
+      apps::InstallReason::kUser, apps::InstallSource::kChromeWebStore,
+      InstallTime::kRunning);
 }
 
 TEST_P(AppPlatformMetricsServiceTest, LaunchApps) {
@@ -2868,8 +2815,9 @@
 
   auto* const proxy = apps::AppServiceProxyFactory::GetForProfile(profile());
   proxy->SetAppPlatformMetricsServiceForTesting(GetAppPlatformMetricsService());
-  proxy->Launch(app_id, ui::EF_NONE,
-                apps::mojom::LaunchSource::kFromChromeInternal, nullptr);
+  FakePublisher fake_arc_apps(proxy, AppType::kArc);
+  proxy->Launch(app_id, ui::EF_NONE, apps::LaunchSource::kFromChromeInternal,
+                nullptr);
   task_environment_.RunUntilIdle();
 }
 
diff --git a/chrome/browser/apps/app_service/metrics/app_platform_metrics_utils.h b/chrome/browser/apps/app_service/metrics/app_platform_metrics_utils.h
index 3fc9688..5a173df 100644
--- a/chrome/browser/apps/app_service/metrics/app_platform_metrics_utils.h
+++ b/chrome/browser/apps/app_service/metrics/app_platform_metrics_utils.h
@@ -8,7 +8,6 @@
 #include "base/time/time.h"
 #include "components/services/app_service/public/cpp/app_launch_util.h"
 #include "components/services/app_service/public/cpp/app_types.h"
-#include "components/services/app_service/public/mojom/types.mojom.h"
 
 class Profile;
 
diff --git a/chrome/browser/apps/app_service/metrics/app_service_metrics.cc b/chrome/browser/apps/app_service/metrics/app_service_metrics.cc
index abbffab..529cf2f 100644
--- a/chrome/browser/apps/app_service/metrics/app_service_metrics.cc
+++ b/chrome/browser/apps/app_service/metrics/app_service_metrics.cc
@@ -288,6 +288,8 @@
     RecordDefaultAppLaunch(DefaultAppName::kProjector, launch_source);
   } else if (app_id == web_app::kFirmwareUpdateAppId) {
     RecordDefaultAppLaunch(DefaultAppName::kFirmwareUpdateApp, launch_source);
+  } else if (app_id == arc::kGoogleTVAppId) {
+    RecordDefaultAppLaunch(DefaultAppName::kGoogleTv, launch_source);
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   }
 
diff --git a/chrome/browser/apps/app_service/metrics/app_service_metrics.h b/chrome/browser/apps/app_service/metrics/app_service_metrics.h
index 8f87c42..1e82327 100644
--- a/chrome/browser/apps/app_service/metrics/app_service_metrics.h
+++ b/chrome/browser/apps/app_service/metrics/app_service_metrics.h
@@ -68,9 +68,10 @@
   kProjector = 49,
   kCalculator = 50,
   kFirmwareUpdateApp = 51,
+  kGoogleTv = 52,
   // Add any new values above this one, and update kMaxValue to the highest
   // enumerator value.
-  kMaxValue = kFirmwareUpdateApp,
+  kMaxValue = kGoogleTv,
 };
 
 // The built-in app's histogram name. This is used for logging so do not change
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index 68cdf32..20d9e02 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -89,6 +89,7 @@
 #include "content/public/test/hit_test_region_observer.h"
 #include "content/public/test/no_renderer_crashes_assertion.h"
 #include "content/public/test/test_file_error_injector.h"
+#include "content/public/test/test_frame_navigation_observer.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/test_utils.h"
 #include "content/public/test/url_loader_interceptor.h"
@@ -833,7 +834,7 @@
     return guest_view_->web_contents();
   }
   content::RenderFrameHost* GetGuestRenderFrameHost() {
-    return guest_view_->web_contents()->GetPrimaryMainFrame();
+    return guest_view_->GetGuestMainFrame();
   }
 
   content::WebContents* GetEmbedderWebContents() {
@@ -3914,30 +3915,15 @@
              NEEDS_TEST_SERVER);
 }
 
-namespace {
-// Fails the test if a navigation is started in the given WebContents.
-class FailOnNavigation : public content::WebContentsObserver {
- public:
-  explicit FailOnNavigation(content::WebContents* contents)
-      : content::WebContentsObserver(contents) {}
-
-  // content::WebContentsObserver:
-  void DidStartNavigation(
-      content::NavigationHandle* navigation_handle) override {
-    ADD_FAILURE() << "Unexpected navigation: " << navigation_handle->GetURL();
-  }
-};
-}  // namespace
-
 IN_PROC_BROWSER_TEST_P(WebViewTest, LoadDataAPINotRelativeToAnotherExtension) {
   ASSERT_TRUE(StartEmbeddedTestServer());
   const extensions::Extension* other_extension =
       LoadExtension(test_data_dir_.AppendASCII("simple_with_file"));
   LoadAppWithGuest("web_view/simple");
   content::WebContents* embedder = GetEmbedderWebContents();
-  content::WebContents* guest = GetGuestWebContents();
+  content::RenderFrameHost* guest = GetGuestView()->GetGuestMainFrame();
 
-  FailOnNavigation fail_if_webview_navigates(guest);
+  content::TestFrameNavigationObserver fail_if_webview_navigates(guest);
   ASSERT_TRUE(content::ExecuteScript(
       embedder, content::JsReplace(
                     "var webview = document.querySelector('webview'); "
@@ -3952,6 +3938,7 @@
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout());
   run_loop.Run();
+  EXPECT_FALSE(fail_if_webview_navigates.navigation_started());
 }
 
 // This test verifies that the resize and contentResize events work correctly.
@@ -4539,24 +4526,27 @@
 IN_PROC_BROWSER_TEST_P(WebViewTest, ReloadAfterCrash) {
   // Load guest and wait for it to appear.
   LoadAppWithGuest("web_view/simple");
-  EXPECT_TRUE(GetGuestWebContents()->GetPrimaryMainFrame()->GetView());
-  content::RenderFrameSubmissionObserver frame_observer(GetGuestWebContents());
+
+  EXPECT_TRUE(GetGuestView()->GetGuestMainFrame()->GetView());
+  content::RenderFrameSubmissionObserver frame_observer(
+      GetGuestView()->GetGuestMainFrame());
   frame_observer.WaitForMetadataChange();
 
   // Kill guest.
-  auto* rph = GetGuestWebContents()->GetPrimaryMainFrame()->GetProcess();
+  auto* rph = GetGuestView()->GetGuestMainFrame()->GetProcess();
   content::RenderProcessHostWatcher crash_observer(
       rph, content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
   EXPECT_TRUE(rph->Shutdown(content::RESULT_CODE_KILLED));
   crash_observer.Wait();
-  EXPECT_FALSE(GetGuestWebContents()->GetPrimaryMainFrame()->GetView());
+  EXPECT_FALSE(GetGuestView()->GetGuestMainFrame()->GetView());
 
   // Reload guest and make sure it appears.
-  content::TestNavigationObserver load_observer(GetGuestWebContents());
+  content::TestFrameNavigationObserver load_observer(
+      GetGuestView()->GetGuestMainFrame());
   EXPECT_TRUE(ExecuteScript(GetEmbedderWebContents(),
                             "document.querySelector('webview').reload()"));
   load_observer.Wait();
-  EXPECT_TRUE(GetGuestWebContents()->GetPrimaryMainFrame()->GetView());
+  EXPECT_TRUE(GetGuestView()->GetGuestMainFrame()->GetView());
   // Ensure that the guest produces a new frame.
   frame_observer.WaitForAnyFrameSubmission();
 }
@@ -6254,9 +6244,8 @@
 
   // Load an app with a <webview> guest that starts at a data: URL.
   LoadAppWithGuest("web_view/simple");
-  content::WebContents* guest = GetGuestWebContents();
-  ASSERT_TRUE(guest);
-  content::RenderFrameHost* main_frame = guest->GetPrimaryMainFrame();
+  content::RenderFrameHost* main_frame = GetGuestRenderFrameHost();
+  ASSERT_TRUE(main_frame);
   auto original_id = main_frame->GetGlobalId();
   scoped_refptr<content::SiteInstance> starting_instance =
       main_frame->GetSiteInstance();
@@ -6275,15 +6264,16 @@
   const GURL start_url =
       embedded_test_server()->GetURL("a.test", "/iframe.html");
   {
-    content::TestNavigationObserver load_observer(guest);
-    EXPECT_TRUE(
-        ExecuteScript(guest, "location.href = '" + start_url.spec() + "';"));
+    content::TestFrameNavigationObserver load_observer(main_frame);
+    EXPECT_TRUE(ExecuteScript(main_frame,
+                              "location.href = '" + start_url.spec() + "';"));
     load_observer.Wait();
   }
 
   // Expect that we stayed in the same (default) SiteInstance and
   // RenderFrameHost.
-  main_frame = guest->GetPrimaryMainFrame();
+  main_frame = GetGuestRenderFrameHost();
+  ASSERT_TRUE(main_frame);
   EXPECT_EQ(main_frame->GetGlobalId(), original_id);
   EXPECT_EQ(starting_instance, main_frame->GetSiteInstance());
   EXPECT_FALSE(main_frame->GetSiteInstance()->RequiresDedicatedProcess());
@@ -6293,8 +6283,9 @@
   // SiteInstance and process.
   const GURL frame_url =
       embedded_test_server()->GetURL("b.test", "/title1.html");
-  EXPECT_TRUE(NavigateIframeToURL(guest, "test", frame_url));
   content::RenderFrameHost* subframe = content::ChildFrameAt(main_frame, 0);
+  ASSERT_TRUE(subframe);
+  EXPECT_TRUE(NavigateToURLFromRenderer(subframe, frame_url));
   EXPECT_EQ(main_frame->GetSiteInstance(), subframe->GetSiteInstance());
   EXPECT_EQ(main_frame->GetProcess(), subframe->GetProcess());
   EXPECT_TRUE(subframe->GetSiteInstance()->IsGuest());
diff --git a/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.cc b/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.cc
index 37e27ac..0db364f 100644
--- a/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.cc
+++ b/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.cc
@@ -116,7 +116,7 @@
       web_contents, std::move(apps),
       /*show_stay_in_chrome=*/true,
       /*show_remember_selection=*/true,
-      base::BindOnce(&OnIntentPickerClosedChromeOs, web_contents,
+      base::BindOnce(&OnIntentPickerClosedChromeOs, web_contents->GetWeakPtr(),
                      PickerShowState::kPopOut, url));
 }
 
@@ -140,13 +140,18 @@
       base::BindOnce(&OnAppIconsLoaded, web_contents, url));
 }
 
-void OnIntentPickerClosedChromeOs(content::WebContents* web_contents,
-                                  PickerShowState show_state,
-                                  const GURL& url,
-                                  const std::string& launch_name,
-                                  PickerEntryType entry_type,
-                                  IntentPickerCloseReason close_reason,
-                                  bool should_persist) {
+void OnIntentPickerClosedChromeOs(
+    base::WeakPtr<content::WebContents> web_contents,
+    PickerShowState show_state,
+    const GURL& url,
+    const std::string& launch_name,
+    PickerEntryType entry_type,
+    IntentPickerCloseReason close_reason,
+    bool should_persist) {
+  if (!web_contents) {
+    return;
+  }
+
   Profile* profile =
       Profile::FromBrowserContext(web_contents->GetBrowserContext());
 // TODO(crbug.com/1225828): Handle this for lacros-chrome as well.
@@ -169,8 +174,6 @@
   const bool should_launch_app =
       close_reason == IntentPickerCloseReason::OPEN_APP;
 
-  auto* proxy = AppServiceProxyFactory::GetForProfile(profile);
-
   // If the picker was closed without an app being chosen,
   // e.g. due to the tab being closed. Keep count of this scenario so we can
   // stop the UI from showing after 2+ dismissals.
@@ -182,6 +185,8 @@
 
   if (should_persist) {
     DCHECK(!launch_name.empty());
+    auto* proxy = AppServiceProxyFactory::GetForProfile(profile);
+    DCHECK(proxy);
     proxy->AddPreferredApp(launch_name, url);
     apps::IntentHandlingMetrics::RecordLinkCapturingEvent(
         entry_type,
@@ -189,7 +194,7 @@
   }
 
   if (should_launch_app) {
-    LaunchAppFromIntentPickerChromeOs(web_contents, url, launch_name,
+    LaunchAppFromIntentPickerChromeOs(web_contents.get(), url, launch_name,
                                       entry_type);
   }
 
@@ -214,8 +219,6 @@
   apps::IntentHandlingMetrics::RecordLinkCapturingEvent(
       app_type, apps::IntentHandlingMetrics::LinkCapturingEvent::kAppOpened);
 
-  auto* proxy = AppServiceProxyFactory::GetForProfile(profile);
-
   if (app_type == PickerEntryType::kWeb) {
     web_app::ReparentWebContentsIntoAppBrowser(web_contents, launch_name);
 
@@ -224,6 +227,8 @@
           web_contents, launch_name);
     }
   } else {
+    auto* proxy = AppServiceProxyFactory::GetForProfile(profile);
+
     // TODO(crbug.com/853604): Distinguish the source from link and omnibox.
     if (base::FeatureList::IsEnabled(apps::kAppServiceLaunchWithoutMojom)) {
       proxy->LaunchAppWithUrl(
diff --git a/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.h b/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.h
index e5f1c8a..72f32dc 100644
--- a/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.h
+++ b/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.h
@@ -7,6 +7,7 @@
 
 #include <vector>
 
+#include "base/memory/weak_ptr.h"
 #include "chrome/browser/apps/intent_helper/apps_navigation_types.h"
 #include "url/gurl.h"
 
@@ -27,13 +28,14 @@
   kPopOut = 2,   // show the intent picker icon and pop out bubble
 };
 
-void OnIntentPickerClosedChromeOs(content::WebContents* web_contents,
-                                  PickerShowState show_state,
-                                  const GURL& url,
-                                  const std::string& launch_name,
-                                  PickerEntryType entry_type,
-                                  IntentPickerCloseReason close_reason,
-                                  bool should_persist);
+void OnIntentPickerClosedChromeOs(
+    base::WeakPtr<content::WebContents> web_contents,
+    PickerShowState show_state,
+    const GURL& url,
+    const std::string& launch_name,
+    PickerEntryType entry_type,
+    IntentPickerCloseReason close_reason,
+    bool should_persist);
 
 void LaunchAppFromIntentPickerChromeOs(content::WebContents* web_contents,
                                        const GURL& url,
diff --git a/chrome/browser/apps/intent_helper/intent_picker_helpers.cc b/chrome/browser/apps/intent_helper/intent_picker_helpers.cc
index ef43af6..2d6aedd6 100644
--- a/chrome/browser/apps/intent_helper/intent_picker_helpers.cc
+++ b/chrome/browser/apps/intent_helper/intent_picker_helpers.cc
@@ -7,6 +7,7 @@
 #include <string>
 #include <utility>
 
+#include "base/memory/weak_ptr.h"
 #include "base/notreached.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
@@ -99,12 +100,16 @@
 #endif  // BUILDFLAG(IS_CHROMEOS)
 }
 
-void OnIntentPickerClosed(content::WebContents* web_contents,
+void OnIntentPickerClosed(base::WeakPtr<content::WebContents> web_contents,
                           const GURL& url,
                           const std::string& launch_name,
                           PickerEntryType entry_type,
                           IntentPickerCloseReason close_reason,
                           bool should_persist) {
+  if (!web_contents) {
+    return;
+  }
+
 #if BUILDFLAG(IS_CHROMEOS)
   OnIntentPickerClosedChromeOs(web_contents, PickerShowState::kOmnibox, url,
                                launch_name, entry_type, close_reason,
@@ -113,7 +118,7 @@
   const bool should_launch_app =
       close_reason == apps::IntentPickerCloseReason::OPEN_APP;
   if (should_launch_app) {
-    LaunchAppFromIntentPicker(web_contents, url, launch_name, entry_type);
+    LaunchAppFromIntentPicker(web_contents.get(), url, launch_name, entry_type);
   }
 #endif  // BUILDFLAG(IS_CHROMEOS)
 }
@@ -130,7 +135,7 @@
       /*show_stay_in_chrome=*/false,
       /*show_remember_selection=*/false,
 #endif  // BUILDFLAG(IS_CHROMEOS)
-      base::BindOnce(&OnIntentPickerClosed, web_contents, url));
+      base::BindOnce(&OnIntentPickerClosed, web_contents->GetWeakPtr(), url));
 }
 
 std::vector<IntentPickerAppInfo> GetAppsForIntentPicker(
diff --git a/chrome/browser/ash/arc/input_method_manager/arc_input_method_manager_service.cc b/chrome/browser/ash/arc/input_method_manager/arc_input_method_manager_service.cc
index 2d8c280..5e28af1 100644
--- a/chrome/browser/ash/arc/input_method_manager/arc_input_method_manager_service.cc
+++ b/chrome/browser/ash/arc/input_method_manager/arc_input_method_manager_service.cc
@@ -247,10 +247,10 @@
       // events here to make sure that Android side receives "keyup" events
       // always to prevent never-ending key repeat from happening.
       owner_->SendHideVirtualKeyboard();
-      std::move(key_data).Run(true);
+      std::move(key_data).Run(ui::ime::KeyEventHandledState::kHandledByIME);
       return;
     }
-    std::move(key_data).Run(false);
+    std::move(key_data).Run(ui::ime::KeyEventHandledState::kNotHandled);
   }
   void OnReset(const std::string& engine_id) override {}
   void OnDeactivated(const std::string& engine_id) override {
diff --git a/chrome/browser/ash/arc/instance_throttle/arc_instance_throttle.cc b/chrome/browser/ash/arc/instance_throttle/arc_instance_throttle.cc
index 2bc9ba91..7a22d06 100644
--- a/chrome/browser/ash/arc/instance_throttle/arc_instance_throttle.cc
+++ b/chrome/browser/ash/arc/instance_throttle/arc_instance_throttle.cc
@@ -296,7 +296,7 @@
   AddObserver(std::make_unique<ArcPowerThrottleObserver>());
   AddObserver(std::make_unique<ArcProvisioningThrottleObserver>());
   AddObserver(std::make_unique<ArcSwitchThrottleObserver>());
-  // This one is controlled by chromeos::ArcPowerControlHandler.
+  // This one is controlled by ash::ArcPowerControlHandler.
   AddObserver(std::make_unique<ash::ThrottleObserver>(
       kChromeArcPowerControlPageObserver));
 
diff --git a/chrome/browser/ash/dbus/chrome_features_service_provider.cc b/chrome/browser/ash/dbus/chrome_features_service_provider.cc
index d79a88c..5ab1e09 100644
--- a/chrome/browser/ash/dbus/chrome_features_service_provider.cc
+++ b/chrome/browser/ash/dbus/chrome_features_service_provider.cc
@@ -185,6 +185,7 @@
       &arc::kNativeBridgeToggleFeature,
       &features::kSessionManagerLongKillTimeout,
       &features::kSessionManagerLivenessCheck,
+      &features::kVmPerBootShaderCache,
   };
 
   dbus::MessageReader reader(method_call);
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest.cc b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
index 1bbb750..fce4a0b0 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
@@ -1333,7 +1333,8 @@
         TestCase("trashTraversingFolderShowsDisallowedDialog").EnableTrash(),
         TestCase("trashDontShowTrashRootOnSelectFileDialog").EnableTrash(),
         TestCase("trashDontShowTrashRootWhenOpeningAsAndroidFilePicker")
-            .EnableTrash()));
+            .EnableTrash(),
+        TestCase("trashEnsureOldEntriesArePeriodicallyRemoved").EnableTrash()));
 
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
     AndroidPhotos, /* android_photos.js */
diff --git a/chrome/browser/ash/fusebox/fusebox_moniker.cc b/chrome/browser/ash/fusebox/fusebox_moniker.cc
index e7576f5b..c4ebc6f 100644
--- a/chrome/browser/ash/fusebox/fusebox_moniker.cc
+++ b/chrome/browser/ash/fusebox/fusebox_moniker.cc
@@ -55,11 +55,12 @@
 MonikerMap::MonikerMap() = default;
 MonikerMap::~MonikerMap() = default;
 
-Moniker MonikerMap::CreateMoniker(storage::FileSystemURL target) {
+Moniker MonikerMap::CreateMoniker(storage::FileSystemURL target,
+                                  bool read_only) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   Moniker moniker = base::Token::CreateRandom();
-  map_.insert({moniker, std::move(target)});
+  map_.insert({moniker, std::make_pair(std::move(target), read_only)});
   return moniker;
 }
 
@@ -72,14 +73,14 @@
   }
 }
 
-storage::FileSystemURL MonikerMap::Resolve(const Moniker& moniker) {
+MonikerMap::FSURLAndReadOnlyState MonikerMap::Resolve(const Moniker& moniker) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   auto iter = map_.find(moniker);
   if (iter != map_.end()) {
     return iter->second;
   }
-  return storage::FileSystemURL();
+  return std::make_pair(storage::FileSystemURL(), false);
 }
 
 }  // namespace fusebox
diff --git a/chrome/browser/ash/fusebox/fusebox_moniker.h b/chrome/browser/ash/fusebox/fusebox_moniker.h
index f0258dd..5976dd7 100644
--- a/chrome/browser/ash/fusebox/fusebox_moniker.h
+++ b/chrome/browser/ash/fusebox/fusebox_moniker.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_ASH_FUSEBOX_FUSEBOX_MONIKER_H_
 
 #include <map>
+#include <utility>
 
 #include "base/token.h"
 #include "storage/browser/file_system/file_system_url.h"
@@ -73,6 +74,8 @@
     base::Token token;
   };
 
+  using FSURLAndReadOnlyState = std::pair<storage::FileSystemURL, bool>;
+
   // Returns the 1234etc base::Token from a storage::FileSystemURL in its
   // string form (like "dummy://moniker/1234etc"), where "dummy://moniker" is
   // the fusebox::kMonikerFileSystemURL prefix.
@@ -95,19 +98,21 @@
   // string form) for the target. It is the caller's responsibility to call
   // DestroyMoniker when the moniker is no longer required but also to keep the
   // FileSystemURL's backing content alive until that DestroyMoniker call.
-  Moniker CreateMoniker(storage::FileSystemURL target);
+  Moniker CreateMoniker(storage::FileSystemURL target, bool read_only);
 
   // Tears down the link, so that Resolve will return invalid FileSystemURL
   // values.
   void DestroyMoniker(const Moniker& moniker);
 
   // Returns the target for the previously created moniker, as identified by
-  // its base::Token. The return value's is_valid() will be false if there was
-  // no such moniker or if it was destroyed.
-  storage::FileSystemURL Resolve(const Moniker& moniker);
+  // its base::Token. The return value's storage::FileSystemURL element
+  // is_valid() will be false if there was no such moniker or if it was
+  // destroyed. If valid, the bool element is the read_only argument passed to
+  // CreateMoniker.
+  FSURLAndReadOnlyState Resolve(const Moniker& moniker);
 
  private:
-  std::map<base::Token, storage::FileSystemURL> map_;
+  std::map<base::Token, FSURLAndReadOnlyState> map_;
 };
 
 }  // namespace fusebox
diff --git a/chrome/browser/ash/fusebox/fusebox_server.cc b/chrome/browser/ash/fusebox/fusebox_server.cc
index 78f8e66b..5f49287 100644
--- a/chrome/browser/ash/fusebox/fusebox_server.cc
+++ b/chrome/browser/ash/fusebox/fusebox_server.cc
@@ -114,13 +114,16 @@
   auto extract_token_result =
       fusebox::MonikerMap::ExtractToken(fs_url_as_string);
   switch (extract_token_result.result_type) {
-    case ResultType::OK:
-      fs_url = moniker_map.Resolve(extract_token_result.token);
-      if (!fs_url.is_valid()) {
+    case ResultType::OK: {
+      auto resolved = moniker_map.Resolve(extract_token_result.token);
+      if (!resolved.first.is_valid()) {
         LOG(ERROR) << "Unresolvable Moniker";
         return ParseResult(base::File::Error::FILE_ERROR_NOT_FOUND);
       }
+      fs_url = std::move(resolved.first);
+      read_only = resolved.second;
       break;
+    }
     case ResultType::NOT_A_MONIKER_FS_URL: {
       auto resolved = ResolvePrefixMap(prefix_map, fs_url_as_string);
       if (resolved.first.empty()) {
@@ -288,10 +291,11 @@
   g_server_instance = nullptr;
 }
 
-fusebox::Moniker Server::CreateMoniker(storage::FileSystemURL target) {
+fusebox::Moniker Server::CreateMoniker(storage::FileSystemURL target,
+                                       bool read_only) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  return moniker_map_.CreateMoniker(target);
+  return moniker_map_.CreateMoniker(target, read_only);
 }
 
 void Server::DestroyMoniker(fusebox::Moniker moniker) {
diff --git a/chrome/browser/ash/fusebox/fusebox_server.h b/chrome/browser/ash/fusebox/fusebox_server.h
index 3a11c03b..a365bc6 100644
--- a/chrome/browser/ash/fusebox/fusebox_server.h
+++ b/chrome/browser/ash/fusebox/fusebox_server.h
@@ -37,7 +37,7 @@
   ~Server();
 
   // Manages monikers in the context of the Server's MonikerMap.
-  fusebox::Moniker CreateMoniker(storage::FileSystemURL target);
+  fusebox::Moniker CreateMoniker(storage::FileSystemURL target, bool read_only);
   void DestroyMoniker(fusebox::Moniker moniker);
 
   void RegisterFSURLPrefix(const std::string& subdir,
diff --git a/chrome/browser/ash/input_method/autocorrect_manager.cc b/chrome/browser/ash/input_method/autocorrect_manager.cc
index db83836..8c67abb 100644
--- a/chrome/browser/ash/input_method/autocorrect_manager.cc
+++ b/chrome/browser/ash/input_method/autocorrect_manager.cc
@@ -91,8 +91,13 @@
     return;
   }
 
+  bool virtual_keyboard_visible =
+      ChromeKeyboardControllerClient::HasInstance() &&
+      ChromeKeyboardControllerClient::Get()->is_keyboard_visible();
+
   pending_autocorrect_ = AutocorrectManager::PendingAutocorrectState(
-      /*original_text=*/original_text, /*start_time=*/base::TimeTicks::Now());
+      /*original_text=*/original_text, /*start_time=*/base::TimeTicks::Now(),
+      /*virtual_keyboard_visible=*/virtual_keyboard_visible);
 
   LogAssistiveAutocorrectAction(AutocorrectActions::kUnderlined);
   RecordAssistiveCoverage(AssistiveType::kAutocorrectUnderlined);
@@ -105,8 +110,8 @@
   base::UmaHistogramEnumeration("InputMethod.Assistive.Autocorrect.Actions",
                                 action);
 
-  if (ChromeKeyboardControllerClient::HasInstance() &&
-      ChromeKeyboardControllerClient::Get()->is_keyboard_visible()) {
+  if (pending_autocorrect_.has_value() &&
+      pending_autocorrect_->virtual_keyboard_visible) {
     base::UmaHistogramEnumeration(
         "InputMethod.Assistive.Autocorrect.Actions.VK", action);
   }
@@ -415,8 +420,14 @@
 
 AutocorrectManager::PendingAutocorrectState::PendingAutocorrectState(
     const std::u16string& original_text,
-    const base::TimeTicks& start_time)
-    : original_text(original_text), start_time(start_time) {}
+    const base::TimeTicks& start_time,
+    bool virtual_keyboard_visible)
+    : original_text(original_text),
+      start_time(start_time),
+      virtual_keyboard_visible(virtual_keyboard_visible) {}
+
+AutocorrectManager::PendingAutocorrectState::PendingAutocorrectState(
+  const PendingAutocorrectState& other) = default;
 
 AutocorrectManager::PendingAutocorrectState::~PendingAutocorrectState() =
     default;
diff --git a/chrome/browser/ash/input_method/autocorrect_manager.h b/chrome/browser/ash/input_method/autocorrect_manager.h
index f857582..8292b37 100644
--- a/chrome/browser/ash/input_method/autocorrect_manager.h
+++ b/chrome/browser/ash/input_method/autocorrect_manager.h
@@ -106,9 +106,11 @@
   void HighlightUndoButton();
 
   struct PendingAutocorrectState {
-    explicit PendingAutocorrectState(const std::u16string& original_text,
-                                     const base::TimeTicks& start_time);
-    PendingAutocorrectState(const PendingAutocorrectState& other) = default;
+    explicit PendingAutocorrectState(
+        const std::u16string& original_text,
+        const base::TimeTicks& start_time,
+        bool virtual_keyboard_visible = false);
+    PendingAutocorrectState(const PendingAutocorrectState& other);
     ~PendingAutocorrectState();
 
     // Original text that is now corrected by autocorrect.
@@ -138,6 +140,10 @@
 
     // The time of setting the pending range.
     base::TimeTicks start_time;
+
+    // Specifies if virtual keyboard was visible when suggesting the pending
+    // autocorrect or not.
+    bool virtual_keyboard_visible = false;
   };
 
   // State variable for pending autocorrect, nullopt means no autocorrect
diff --git a/chrome/browser/ash/input_method/autocorrect_manager_unittest.cc b/chrome/browser/ash/input_method/autocorrect_manager_unittest.cc
index 2e206ec..51852984 100644
--- a/chrome/browser/ash/input_method/autocorrect_manager_unittest.cc
+++ b/chrome/browser/ash/input_method/autocorrect_manager_unittest.cc
@@ -1017,6 +1017,46 @@
                               /*exited_text_field_with_underline=*/0);
 }
 
+TEST_F(AutocorrectManagerTest,
+       RecordMetricsForVkWhenVkWasVisibleAtUnderlineTime) {
+  // VK is visible at the time of suggesting an autocorrect.
+  keyboard_client_->set_keyboard_visible_for_test(true);
+  manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
+
+  // To suppress strict mock.
+  EXPECT_CALL(mock_suggestion_handler_, SetAssistiveWindowProperties(_, _, _));
+
+  // VK is made hidden, but still the metrics need to be recorded for VK
+  // given VK was visible at underline time.
+  keyboard_client_->set_keyboard_visible_for_test(false);
+  manager_.OnSurroundingTextChanged(u"teh ", 1, 1);
+
+  ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/true,
+                              /*window_shown=*/1, /*underlined=*/1,
+                              /*reverted=*/0, /*accepted=*/0,
+                              /*cleared_underline=*/0);
+}
+
+TEST_F(AutocorrectManagerTest,
+       DoesNotRecordMetricsForVkWhenVkWasNotVisibleAtUnderlineTime) {
+  // VK is not visible at the time of suggesting an autocorrect.
+  keyboard_client_->set_keyboard_visible_for_test(false);
+  manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
+
+  // To suppress strict mock.
+  EXPECT_CALL(mock_suggestion_handler_, SetAssistiveWindowProperties(_, _, _));
+
+  // VK is made visible, but still metrics must not be recorded for VK
+  // as it was not visible at the time of underline.
+  keyboard_client_->set_keyboard_visible_for_test(true);
+  manager_.OnSurroundingTextChanged(u"teh ", 1, 1);
+
+  ExpectAutocorrectHistograms(histogram_tester_, /*visible_vk=*/false,
+                              /*window_shown=*/1, /*underlined=*/1,
+                              /*reverted=*/0, /*accepted=*/0,
+                              /*cleared_underline=*/0);
+}
+
 TEST_F(AutocorrectManagerTest, HandleAutocorrectRecordsMetricsWhenVkIsVisible) {
   keyboard_client_->set_keyboard_visible_for_test(true);
   manager_.HandleAutocorrect(gfx::Range(0, 3), u"teh", u"the");
diff --git a/chrome/browser/ash/input_method/input_method_engine.cc b/chrome/browser/ash/input_method/input_method_engine.cc
index 4e91ea01..a87a0190 100644
--- a/chrome/browser/ash/input_method/input_method_engine.cc
+++ b/chrome/browser/ash/input_method/input_method_engine.cc
@@ -577,7 +577,9 @@
     return;
   }
 
-  std::move(it->second.callback).Run(handled);
+  std::move(it->second.callback)
+      .Run(handled ? ui::ime::KeyEventHandledState::kHandledByIME
+                   : ui::ime::KeyEventHandledState::kNotHandled);
   pending_key_events_.erase(it);
 }
 
@@ -595,7 +597,8 @@
 
 void InputMethodEngine::CancelPendingKeyEvents() {
   for (auto& event : pending_key_events_) {
-    std::move(event.second.callback).Run(false);
+    std::move(event.second.callback)
+        .Run(ui::ime::KeyEventHandledState::kNotHandled);
   }
   pending_key_events_.clear();
 }
@@ -669,7 +672,7 @@
 void InputMethodEngine::ProcessKeyEvent(const ui::KeyEvent& key_event,
                                         KeyEventDoneCallback callback) {
   if (key_event.IsCommandDown()) {
-    std::move(callback).Run(false);
+    std::move(callback).Run(ui::ime::KeyEventHandledState::kNotHandled);
     return;
   }
 
@@ -681,11 +684,12 @@
         active_component_id_, key_event,
         base::BindOnce(
             [](base::Time start, int context_id, int* context_id_ptr,
-               KeyEventDoneCallback callback, bool handled) {
+               KeyEventDoneCallback callback,
+               ui::ime::KeyEventHandledState handled_state) {
               // If the input_context has changed, assume the key event is
               // invalid as a precaution.
               if (context_id == *context_id_ptr) {
-                std::move(callback).Run(handled);
+                std::move(callback).Run(handled_state);
               }
               UMA_HISTOGRAM_TIMES("InputMethod.KeyEventLatency",
                                   base::Time::Now() - start);
diff --git a/chrome/browser/ash/input_method/input_method_engine_browsertests.cc b/chrome/browser/ash/input_method/input_method_engine_browsertests.cc
index a99b7967..41e2545e 100644
--- a/chrome/browser/ash/input_method/input_method_engine_browsertests.cc
+++ b/chrome/browser/ash/input_method/input_method_engine_browsertests.cc
@@ -137,7 +137,7 @@
 
 class KeyEventDoneCallback {
  public:
-  explicit KeyEventDoneCallback(bool expected_argument)
+  explicit KeyEventDoneCallback(ui::ime::KeyEventHandledState expected_argument)
       : expected_argument_(expected_argument) {}
 
   KeyEventDoneCallback(const KeyEventDoneCallback&) = delete;
@@ -145,7 +145,7 @@
 
   ~KeyEventDoneCallback() = default;
 
-  void Run(bool consumed) {
+  void Run(ui::ime::KeyEventHandledState consumed) {
     if (consumed == expected_argument_)
       run_loop_.Quit();
   }
@@ -153,7 +153,7 @@
   void WaitUntilCalled() { run_loop_.Run(); }
 
  private:
-  bool expected_argument_;
+  ui::ime::KeyEventHandledState expected_argument_;
   base::RunLoop run_loop_;
 };
 
@@ -228,7 +228,9 @@
   ASSERT_TRUE(focus_listener.was_satisfied());
 
   // onKeyEvent should be fired if ProcessKeyEvent is called.
-  KeyEventDoneCallback callback(false);  // EchoBackIME doesn't consume keys.
+  KeyEventDoneCallback callback(
+      ui::ime::KeyEventHandledState::kNotHandled);  // EchoBackIME doesn't
+                                                    // consume keys.
   ExtensionTestMessageListener keyevent_listener("onKeyEvent");
   ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE);
   ui::IMEEngineHandlerInterface::KeyEventDoneCallback keyevent_callback =
@@ -310,7 +312,7 @@
 
   {
     SCOPED_TRACE("KeyDown, Ctrl:No, Alt:No, AltGr:No, Shift:No, Caps:No");
-    KeyEventDoneCallback callback(false);
+    KeyEventDoneCallback callback(ui::ime::KeyEventHandledState::kNotHandled);
     const std::string expected_value =
         "onKeyEvent::true:keydown:a:KeyA:false:false:false:false:false";
     ExtensionTestMessageListener keyevent_listener(expected_value);
@@ -326,7 +328,7 @@
   }
   {
     SCOPED_TRACE("KeyDown, Ctrl:Yes, Alt:No, AltGr:No, Shift:No, Caps:No");
-    KeyEventDoneCallback callback(false);
+    KeyEventDoneCallback callback(ui::ime::KeyEventHandledState::kNotHandled);
     const std::string expected_value =
         "onKeyEvent::true:keydown:a:KeyA:true:false:false:false:false";
     ExtensionTestMessageListener keyevent_listener(expected_value);
@@ -342,7 +344,7 @@
   }
   {
     SCOPED_TRACE("KeyDown, Ctrl:No, Alt:Yes, AltGr:No, Shift:No, Caps:No");
-    KeyEventDoneCallback callback(false);
+    KeyEventDoneCallback callback(ui::ime::KeyEventHandledState::kNotHandled);
     const std::string expected_value =
         "onKeyEvent::true:keydown:a:KeyA:false:true:false:false:false";
     ExtensionTestMessageListener keyevent_listener(expected_value);
@@ -358,7 +360,7 @@
   }
   {
     SCOPED_TRACE("KeyDown, Ctrl:No, Alt:No, AltGr:No, Shift:Yes, Caps:No");
-    KeyEventDoneCallback callback(false);
+    KeyEventDoneCallback callback(ui::ime::KeyEventHandledState::kNotHandled);
     const std::string expected_value =
         "onKeyEvent::true:keydown:A:KeyA:false:false:false:true:false";
     ExtensionTestMessageListener keyevent_listener(expected_value);
@@ -374,7 +376,7 @@
   }
   {
     SCOPED_TRACE("KeyDown, Ctrl:No, Alt:No, AltGr:No, Shift:No, Caps:Yes");
-    KeyEventDoneCallback callback(false);
+    KeyEventDoneCallback callback(ui::ime::KeyEventHandledState::kNotHandled);
     const std::string expected_value =
         "onKeyEvent::true:keydown:A:KeyA:false:false:false:false:true";
     ExtensionTestMessageListener keyevent_listener(expected_value);
@@ -390,7 +392,7 @@
   }
   {
     SCOPED_TRACE("KeyDown, Ctrl:Yes, Alt:Yes, AltGr:No, Shift:No, Caps:No");
-    KeyEventDoneCallback callback(false);
+    KeyEventDoneCallback callback(ui::ime::KeyEventHandledState::kNotHandled);
     const std::string expected_value =
         "onKeyEvent::true:keydown:a:KeyA:true:true:false:false:false";
     ExtensionTestMessageListener keyevent_listener(expected_value);
@@ -406,7 +408,7 @@
   }
   {
     SCOPED_TRACE("KeyDown, Ctrl:No, Alt:No, AltGr:No, Shift:Yes, Caps:Yes");
-    KeyEventDoneCallback callback(false);
+    KeyEventDoneCallback callback(ui::ime::KeyEventHandledState::kNotHandled);
     const std::string expected_value =
         "onKeyEvent::true:keydown:a:KeyA:false:false:false:true:true";
     ExtensionTestMessageListener keyevent_listener(expected_value);
@@ -422,7 +424,7 @@
   }
   {
     SCOPED_TRACE("KeyDown, Ctrl:No, Alt:No, AltGr:Yes, Shift:No, Caps:No");
-    KeyEventDoneCallback callback(false);
+    KeyEventDoneCallback callback(ui::ime::KeyEventHandledState::kNotHandled);
     const std::string expected_value =
         "onKeyEvent::true:keydown:a:KeyA:false:false:true:false:false";
     ExtensionTestMessageListener keyevent_listener(expected_value);
@@ -467,7 +469,7 @@
 
   for (size_t i = 0; i < std::size(kMediaKeyCases); ++i) {
     SCOPED_TRACE(std::string("KeyDown, ") + kMediaKeyCases[i].code);
-    KeyEventDoneCallback callback(false);
+    KeyEventDoneCallback callback(ui::ime::KeyEventHandledState::kNotHandled);
     const std::string expected_value = base::StringPrintf(
         "onKeyEvent::true:keydown:%s:%s:false:false:false:false:false",
         kMediaKeyCases[i].key, kMediaKeyCases[i].code);
diff --git a/chrome/browser/ash/input_method/input_method_engine_unittest.cc b/chrome/browser/ash/input_method/input_method_engine_unittest.cc
index 7c36be10..24a5232 100644
--- a/chrome/browser/ash/input_method/input_method_engine_unittest.cc
+++ b/chrome/browser/ash/input_method/input_method_engine_unittest.cc
@@ -106,7 +106,7 @@
       const std::string& engine_id,
       const ui::KeyEvent& event,
       ui::IMEEngineHandlerInterface::KeyEventDoneCallback callback) override {
-    std::move(callback).Run(/* handled */ true);
+    std::move(callback).Run(ui::ime::KeyEventHandledState::kHandledByIME);
   }
   void OnCompositionBoundsChanged(
       const std::vector<gfx::Rect>& bounds) override {
diff --git a/chrome/browser/ash/input_method/multi_word_suggester.cc b/chrome/browser/ash/input_method/multi_word_suggester.cc
index ef85d73..b04689a 100644
--- a/chrome/browser/ash/input_method/multi_word_suggester.cc
+++ b/chrome/browser/ash/input_method/multi_word_suggester.cc
@@ -139,8 +139,12 @@
          text.size() >= kMinimumNumberOfCharsToProduceSuggestion;
 }
 
+bool u16_isalpha(char16_t ch) {
+  return (ch >= u'A' && ch <= u'Z') || (ch >= u'a' && ch <= u'z');
+}
+
 bool WouldBeInCompletionMode(const base::StringPiece16& text) {
-  return !text.empty() && std::isalpha(text.back());
+  return !text.empty() && u16_isalpha(text.back());
 }
 
 // TODO(crbug/1146266): Add DismissedAccuracy metric back in.
diff --git a/chrome/browser/ash/input_method/native_input_method_engine_observer.cc b/chrome/browser/ash/input_method/native_input_method_engine_observer.cc
index 1eee625..668b67b 100644
--- a/chrome/browser/ash/input_method/native_input_method_engine_observer.cc
+++ b/chrome/browser/ash/input_method/native_input_method_engine_observer.cc
@@ -794,17 +794,18 @@
     ui::IMEEngineHandlerInterface::KeyEventDoneCallback callback) {
   if (assistive_suggester_->IsAssistiveFeatureEnabled()) {
     if (assistive_suggester_->OnKeyEvent(event)) {
-      std::move(callback).Run(true);
+      std::move(callback).Run(
+          ui::ime::KeyEventHandledState::kHandledByAssistiveSuggester);
       return;
     }
   }
   if (autocorrect_manager_->OnKeyEvent(event)) {
-    std::move(callback).Run(true);
+    std::move(callback).Run(ui::ime::KeyEventHandledState::kHandledByIME);
     return;
   }
   if (grammar_manager_->IsOnDeviceGrammarEnabled() &&
       grammar_manager_->OnKeyEvent(event)) {
-    std::move(callback).Run(true);
+    std::move(callback).Run(ui::ime::KeyEventHandledState::kHandledByIME);
     return;
   }
 
@@ -818,20 +819,20 @@
       // Don't send dead keys to the system IME. Dead keys should be handled at
       // the OS level and not exposed to IMEs.
       if (event.GetDomKey().IsDeadKey()) {
-        std::move(callback).Run(true);
+        std::move(callback).Run(ui::ime::KeyEventHandledState::kHandledByIME);
         return;
       }
 
       mojom::PhysicalKeyEventPtr key_event =
           CreatePhysicalKeyEventFromKeyEvent(event);
       if (!key_event) {
-        std::move(callback).Run(false);
+        std::move(callback).Run(ui::ime::KeyEventHandledState::kNotHandled);
         return;
       }
 
       // Hot switches to turn on/off certain IME features.
       if (IsFstEngine(engine_id) && autocorrect_manager_->DisabledByRule()) {
-        std::move(callback).Run(false);
+        std::move(callback).Run(ui::ime::KeyEventHandledState::kNotHandled);
         return;
       }
 
@@ -847,14 +848,16 @@
                  original_callback,
              mojom::KeyEventResult result) {
             std::move(original_callback)
-                .Run(result == mojom::KeyEventResult::kConsumedByIme);
+                .Run((result == mojom::KeyEventResult::kConsumedByIme)
+                         ? ui::ime::KeyEventHandledState::kHandledByIME
+                         : ui::ime::KeyEventHandledState::kNotHandled);
           },
           std::move(callback));
 
       input_method_->ProcessKeyEvent(std::move(key_event),
                                      std::move(process_key_event_callback));
     } else {
-      std::move(callback).Run(false);
+      std::move(callback).Run(ui::ime::KeyEventHandledState::kNotHandled);
     }
   } else {
     ime_base_observer_->OnKeyEvent(engine_id, event, std::move(callback));
diff --git a/chrome/browser/ash/input_method/native_input_method_engine_with_ime_service_browsertest.cc b/chrome/browser/ash/input_method/native_input_method_engine_with_ime_service_browsertest.cc
index e34459c..8e49721 100644
--- a/chrome/browser/ash/input_method/native_input_method_engine_with_ime_service_browsertest.cc
+++ b/chrome/browser/ash/input_method/native_input_method_engine_with_ime_service_browsertest.cc
@@ -31,7 +31,7 @@
       const std::string& engine_id,
       const ui::KeyEvent& event,
       ui::IMEEngineHandlerInterface::KeyEventDoneCallback callback) override {
-    std::move(callback).Run(/*handled=*/false);
+    std::move(callback).Run(ui::ime::KeyEventHandledState::kNotHandled);
   }
 };
 
@@ -42,7 +42,9 @@
                           base::Unretained(this));
   }
 
-  void OnKeyEventDone(bool consumed) { run_loop_.Quit(); }
+  void OnKeyEventDone(ui::ime::KeyEventHandledState handled_state) {
+    run_loop_.Quit();
+  }
 
   void Wait() { run_loop_.Run(); }
 
diff --git a/chrome/browser/ash/input_method/native_input_method_engine_without_ime_service_browsertest.cc b/chrome/browser/ash/input_method/native_input_method_engine_without_ime_service_browsertest.cc
index 36635b6..cd6e07c8 100644
--- a/chrome/browser/ash/input_method/native_input_method_engine_without_ime_service_browsertest.cc
+++ b/chrome/browser/ash/input_method/native_input_method_engine_without_ime_service_browsertest.cc
@@ -64,7 +64,7 @@
       const std::string& engine_id,
       const ui::KeyEvent& event,
       ui::IMEEngineHandlerInterface::KeyEventDoneCallback callback) override {
-    std::move(callback).Run(/*handled=*/false);
+    std::move(callback).Run(ui::ime::KeyEventHandledState::kNotHandled);
   }
   void OnInputMethodOptionsChanged(const std::string& engine_id) override {
     changed_engine_id_ = engine_id;
@@ -105,7 +105,9 @@
                           base::Unretained(this));
   }
 
-  void OnKeyEventDone(bool consumed) { run_loop_.Quit(); }
+  void OnKeyEventDone(ui::ime::KeyEventHandledState handled_state) {
+    run_loop_.Quit();
+  }
 
   void Wait() { run_loop_.Run(); }
 
diff --git a/chrome/browser/ash/kerberos/kerberos_credentials_manager.cc b/chrome/browser/ash/kerberos/kerberos_credentials_manager.cc
index ffea3daa..943cb98 100644
--- a/chrome/browser/ash/kerberos/kerberos_credentials_manager.cc
+++ b/chrome/browser/ash/kerberos/kerberos_credentials_manager.cc
@@ -314,7 +314,8 @@
   substitutions[kLoginId] =
       primary_user->GetAccountName(false /* use_display_email */);
   substitutions[kLoginEmail] = primary_user->GetAccountId().GetUserEmail();
-  principal_expander_ = std::make_unique<VariableExpander>(substitutions);
+  principal_expander_ =
+      std::make_unique<chromeos::VariableExpander>(substitutions);
 
   // Connect to a signal that indicates when Kerberos files change.
   kerberos_file_changed_signal_subscription_ =
diff --git a/chrome/browser/ash/kerberos/kerberos_credentials_manager.h b/chrome/browser/ash/kerberos/kerberos_credentials_manager.h
index ee14d20..1bf8c61 100644
--- a/chrome/browser/ash/kerberos/kerberos_credentials_manager.h
+++ b/chrome/browser/ash/kerberos/kerberos_credentials_manager.h
@@ -16,19 +16,21 @@
 #include "base/timer/timer.h"
 #include "chrome/browser/ash/authpolicy/kerberos_files_handler.h"
 #include "chromeos/ash/components/dbus/kerberos/kerberos_service.pb.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
-// TODO(https://crbug.com/1164001): forward declare when moved ash.
-#include "chromeos/components/onc/variable_expander.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/policy/core/common/policy_namespace.h"
 #include "components/policy/core/common/policy_service.h"
 #include "net/base/backoff_entry.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 class PrefRegistrySimple;
 class PrefService;
 class PrefChangeRegistrar;
 class Profile;
 
+namespace chromeos {
+class VariableExpander;
+}
+
 namespace policy {
 class PolicyMap;
 }  // namespace policy
@@ -285,7 +287,7 @@
   std::vector<std::unique_ptr<KerberosAddAccountRunner>> add_account_runners_;
 
   // Variable expander for the principal name (replaces ${LOGIN_ID} etc.).
-  std::unique_ptr<VariableExpander> principal_expander_;
+  std::unique_ptr<chromeos::VariableExpander> principal_expander_;
 
   // List of objects that observe this instance.
   base::ObserverList<Observer, true /* check_empty */> observers_;
diff --git a/chrome/browser/ash/login/app_mode/kiosk_launch_controller.cc b/chrome/browser/ash/login/app_mode/kiosk_launch_controller.cc
index b95dca38..fabd1741 100644
--- a/chrome/browser/ash/login/app_mode/kiosk_launch_controller.cc
+++ b/chrome/browser/ash/login/app_mode/kiosk_launch_controller.cc
@@ -559,7 +559,13 @@
   DCHECK_NE(KioskAppLaunchError::Error::kNone, error);
   SYSLOG(ERROR) << "Kiosk launch failed, error=" << static_cast<int>(error);
 
-  if (kiosk_app_id_.type == KioskAppType::kWebApp) {
+  // App Service launcher requires the web app to be installed. Temporary issues
+  // like URL redirection should not stop the app from being installed as
+  // placeholder. Force launching the app is not possible in case installation
+  // fails.
+  if (kiosk_app_id_.type == KioskAppType::kWebApp &&
+      (!base::FeatureList::IsEnabled(features::kKioskEnableAppService) ||
+       crosapi::browser_util::IsLacrosEnabled())) {
     HandleWebAppInstallFailed();
     return;
   }
diff --git a/chrome/browser/ash/printing/oauth2/authorization_zone_impl.cc b/chrome/browser/ash/printing/oauth2/authorization_zone_impl.cc
index eaa2c5d..f0a854b 100644
--- a/chrome/browser/ash/printing/oauth2/authorization_zone_impl.cc
+++ b/chrome/browser/ash/printing/oauth2/authorization_zone_impl.cc
@@ -116,17 +116,6 @@
   std::move(callback).Run(status, (status == StatusCode::kOK) ? "" : data);
 }
 
-// Calls `callback`. Adds a prefix with `context` to an error sent in `data`.
-void PrefixForError(StatusCallback callback,
-                    const std::string& context,
-                    StatusCode status,
-                    const std::string& data) {
-  std::string msg = status == StatusCode::kOK
-                        ? data
-                        : base::StrCat({"[", context, "] ", data});
-  std::move(callback).Run(status, msg);
-}
-
 }  // namespace
 
 AuthorizationZoneImpl::WaitingAuthorization::WaitingAuthorization(
@@ -154,7 +143,6 @@
 void AuthorizationZoneImpl::InitAuthorization(const std::string& scope,
                                               StatusCallback callback) {
   DCHECK_LE(waiting_authorizations_.size(), kMaxNumberOfSessions);
-  AddContextToErrorMessage(callback);
 
   // If there are too many callbacks waiting, remove the oldest one.
   if (waiting_authorizations_.size() == kMaxNumberOfSessions) {
@@ -190,8 +178,6 @@
 
 void AuthorizationZoneImpl::FinishAuthorization(const GURL& redirect_url,
                                                 StatusCallback callback) {
-  AddContextToErrorMessage(callback);
-
   // Parse the URL and retrieve the query segment.
   chromeos::Uri uri(redirect_url.spec());
   if (uri.GetLastParsingError().status !=
@@ -567,13 +553,6 @@
   return true;
 }
 
-void AuthorizationZoneImpl::AddContextToErrorMessage(StatusCallback& callback) {
-  // Wrap the `callback` with the function PrefixForError() defined above.
-  const std::string prefix = server_data_.AuthorizationServerURI().spec();
-  auto new_call = base::BindOnce(&PrefixForError, std::move(callback), prefix);
-  callback = std::move(new_call);
-}
-
 std::unique_ptr<AuthorizationZone> AuthorizationZone::Create(
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     const GURL& authorization_server_uri,
diff --git a/chrome/browser/ash/printing/oauth2/authorization_zone_impl.h b/chrome/browser/ash/printing/oauth2/authorization_zone_impl.h
index 2da8d1e..7813f74 100644
--- a/chrome/browser/ash/printing/oauth2/authorization_zone_impl.h
+++ b/chrome/browser/ash/printing/oauth2/authorization_zone_impl.h
@@ -101,9 +101,6 @@
                                          base::flat_set<std::string>& scopes,
                                          std::string& code_verifier);
 
-  // Adds context info to error messages returned with `callback`.
-  void AddContextToErrorMessage(StatusCallback& callback);
-
   // Represents started authorization procedure waiting for opening
   // communication with the server. This object is created when
   // InitAuthorization() is called and its callback does not return yet.
diff --git a/chrome/browser/ash/printing/oauth2/authorization_zone_unittest.cc b/chrome/browser/ash/printing/oauth2/authorization_zone_unittest.cc
index 97df23a..0abf8c5 100644
--- a/chrome/browser/ash/printing/oauth2/authorization_zone_unittest.cc
+++ b/chrome/browser/ash/printing/oauth2/authorization_zone_unittest.cc
@@ -510,21 +510,6 @@
   EXPECT_EQ(cr_1.status, StatusCode::kUntrustedAuthorizationServer);
 }
 
-TEST_F(PrintingOAuth2AuthorizationZoneTest, PrefixInErrorMessage) {
-  CallbackResult cr;
-  CreateAuthorizationZone("");
-
-  // Respond with error to Metadata Request.
-  authorization_zone_->InitAuthorization("", BindResult(cr));
-  server_.ReceiveGET(metadata_uri_);
-  server_.ResponseWithJSON(net::HttpStatusCode::HTTP_INTERNAL_SERVER_ERROR, {});
-
-  // Check if the error message begins with the URI of the server.
-  EXPECT_EQ(cr.status, printing::oauth2::StatusCode::kServerError);
-  const std::string msg_prefix = "[" + authorization_server_uri_ + "]";
-  EXPECT_EQ(cr.data.substr(0, msg_prefix.length()), msg_prefix);
-}
-
 }  // namespace
 }  // namespace oauth2
 }  // namespace printing
diff --git a/chrome/browser/ash/printing/oauth2/authorization_zones_manager.cc b/chrome/browser/ash/printing/oauth2/authorization_zones_manager.cc
index 0d216a3..3a5743d 100644
--- a/chrome/browser/ash/printing/oauth2/authorization_zones_manager.cc
+++ b/chrome/browser/ash/printing/oauth2/authorization_zones_manager.cc
@@ -15,22 +15,83 @@
 #include "base/check.h"
 #include "base/containers/contains.h"
 #include "base/notreached.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_piece.h"
 #include "chrome/browser/ash/printing/oauth2/authorization_zone.h"
 #include "chrome/browser/ash/printing/oauth2/profile_auth_servers_sync_bridge.h"
 #include "chrome/browser/ash/printing/oauth2/status_code.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/model_type_store_service_factory.h"
 #include "chromeos/printing/uri.h"
+#include "components/device_event_log/device_event_log.h"
 #include "components/sync/model/model_type_change_processor.h"
 #include "components/sync/model/model_type_store.h"
 #include "components/sync/model/model_type_store_service.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "url/gurl.h"
 
 namespace ash::printing::oauth2 {
 
 namespace {
 
+// Builds a single log entry for device-log.
+std::string BuildLogEntry(base::StringPiece method,
+                          const GURL& auth_server,
+                          const chromeos::Uri& ipp_endpoint = chromeos::Uri(),
+                          absl::optional<StatusCode> status = absl::nullopt,
+                          const std::string& data = "") {
+  std::vector<base::StringPiece> strv;
+  strv.reserve(10);
+  strv.emplace_back("oauth ");
+  strv.emplace_back(method);
+  strv.emplace_back(";server=");
+  strv.emplace_back(auth_server.possibly_invalid_spec());
+  const std::string endpoint = ipp_endpoint.GetNormalized();
+  if (!endpoint.empty()) {
+    strv.emplace_back(";endpoint=");
+    strv.emplace_back(endpoint);
+  }
+  if (status) {
+    strv.emplace_back(";status=");
+    strv.emplace_back(ToStringPiece(*status));
+  }
+  if (!data.empty()) {
+    strv.emplace_back(": ");
+    strv.emplace_back(data);
+  }
+  return base::StrCat(strv);
+}
+
+// Logs results to device-log and calls `callback` with parameters `status` and
+// `data`.
+void LogAndCall(StatusCallback callback,
+                base::StringPiece method,
+                const GURL& auth_server,
+                const chromeos::Uri& ipp_endpoint,
+                StatusCode status,
+                const std::string& data) {
+  if (status == StatusCode::kOK || status == StatusCode::kAuthorizationNeeded) {
+    PRINTER_LOG(EVENT) << BuildLogEntry(
+        method, auth_server, ipp_endpoint, status,
+        (status == StatusCode::kOK) ? "" : data);
+  } else {
+    PRINTER_LOG(ERROR) << BuildLogEntry(method, auth_server, ipp_endpoint,
+                                        status, data);
+  }
+  std::move(callback).Run(status, data);
+}
+
+void AddLoggingToCallback(StatusCallback& callback,
+                          const base::StringPiece method,
+                          const GURL& auth_server,
+                          const chromeos::Uri& ipp_endpoint = chromeos::Uri()) {
+  // Wrap the `callback` with the function LogAndCall() defined above.
+  auto new_call = base::BindOnce(&LogAndCall, std::move(callback), method,
+                                 auth_server, ipp_endpoint);
+  callback = std::move(new_call);
+}
+
 class AuthorizationZonesManagerImpl
     : public AuthorizationZonesManager,
       private ProfileAuthServersSyncBridge::Observer {
@@ -58,14 +119,15 @@
 
   StatusCode SaveAuthorizationServerAsTrusted(
       const GURL& auth_server) override {
-    std::unique_ptr<AuthorizationZone> auth_zone =
-        auth_zone_creator_.Run(auth_server, /*client_id=*/"");
     if (!auth_server.is_valid() || !auth_server.SchemeIs("https") ||
         !auth_server.has_host() || auth_server.has_username() ||
         auth_server.has_query() || auth_server.has_ref()) {
-      // TODO(pawliczek): log why the URL is invalid
+      PRINTER_LOG(USER) << BuildLogEntry(__func__, auth_server, chromeos::Uri(),
+                                         StatusCode::kInvalidURL);
       return StatusCode::kInvalidURL;
     }
+    std::unique_ptr<AuthorizationZone> auth_zone =
+        auth_zone_creator_.Run(auth_server, /*client_id=*/"");
     if (sync_bridge_->IsInitialized()) {
       if (!base::Contains(servers_, auth_server)) {
         servers_.emplace(auth_server, std::move(auth_zone));
@@ -76,18 +138,23 @@
         waiting_servers_[auth_server].server = std::move(auth_zone);
       }
     }
+    PRINTER_LOG(USER) << BuildLogEntry(__func__, auth_server, chromeos::Uri(),
+                                       StatusCode::kOK);
     return StatusCode::kOK;
   }
 
   void InitAuthorization(const GURL& auth_server,
                          const std::string& scope,
                          StatusCallback callback) override {
+    PRINTER_LOG(USER) << BuildLogEntry(__func__, auth_server, chromeos::Uri(),
+                                       absl::nullopt, "scope=" + scope);
+    AddLoggingToCallback(callback, __func__, auth_server);
     AuthorizationZone* zone = GetAuthorizationZone(auth_server);
+
     if (!zone) {
       auto it = waiting_servers_.find(auth_server);
       if (it == waiting_servers_.end()) {
-        std::move(callback).Run(StatusCode::kUntrustedAuthorizationServer,
-                                auth_server.possibly_invalid_spec());
+        std::move(callback).Run(StatusCode::kUntrustedAuthorizationServer, "");
       } else {
         it->second.init_calls.emplace_back(
             InitAuthorizationCall{scope, std::move(callback)});
@@ -101,12 +168,15 @@
   void FinishAuthorization(const GURL& auth_server,
                            const GURL& redirect_url,
                            StatusCallback callback) override {
+    PRINTER_LOG(USER) << BuildLogEntry(__func__, auth_server);
+    AddLoggingToCallback(callback, __func__, auth_server);
+
     AuthorizationZone* zone = GetAuthorizationZone(auth_server);
     if (!zone) {
       const StatusCode code = base::Contains(waiting_servers_, auth_server)
                                   ? StatusCode::kAuthorizationNeeded
                                   : StatusCode::kUntrustedAuthorizationServer;
-      std::move(callback).Run(code, auth_server.possibly_invalid_spec());
+      std::move(callback).Run(code, "");
       return;
     }
 
@@ -117,12 +187,16 @@
                               const chromeos::Uri& ipp_endpoint,
                               const std::string& scope,
                               StatusCallback callback) override {
+    PRINTER_LOG(USER) << BuildLogEntry(__func__, auth_server, ipp_endpoint,
+                                       absl::nullopt, "scope=" + scope);
+    AddLoggingToCallback(callback, __func__, auth_server, ipp_endpoint);
+
     AuthorizationZone* zone = GetAuthorizationZone(auth_server);
     if (!zone) {
       const StatusCode code = base::Contains(waiting_servers_, auth_server)
                                   ? StatusCode::kAuthorizationNeeded
                                   : StatusCode::kUntrustedAuthorizationServer;
-      std::move(callback).Run(code, auth_server.possibly_invalid_spec());
+      std::move(callback).Run(code, "");
       return;
     }
 
@@ -134,11 +208,13 @@
       const chromeos::Uri& ipp_endpoint,
       const std::string& endpoint_access_token) override {
     AuthorizationZone* zone = GetAuthorizationZone(auth_server);
-    if (!zone) {
-      return;
+    PRINTER_LOG(EVENT) << BuildLogEntry(
+        __func__, auth_server, ipp_endpoint,
+        zone ? StatusCode::kOK : StatusCode::kUntrustedAuthorizationServer);
+    if (zone) {
+      zone->MarkEndpointAccessTokenAsExpired(ipp_endpoint,
+                                             endpoint_access_token);
     }
-
-    zone->MarkEndpointAccessTokenAsExpired(ipp_endpoint, endpoint_access_token);
   }
 
  private:
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 49d85e6..54c2e46 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -323,6 +323,8 @@
     "//chromeos/ash/components/feature_usage",
     "//chromeos/ash/components/hibernate:buildflags",
     "//chromeos/ash/components/install_attributes",
+    "//chromeos/ash/components/language/language_packs",
+    "//chromeos/ash/components/language/public/mojom",
     "//chromeos/ash/components/local_search_service/public/cpp",
     "//chromeos/ash/components/memory",
     "//chromeos/ash/components/network",
@@ -364,8 +366,6 @@
     "//chromeos/dbus/u2f",
     "//chromeos/dbus/u2f:u2f_proto",
     "//chromeos/ime:gencode",
-    "//chromeos/language/language_packs",
-    "//chromeos/language/public/mojom",
     "//chromeos/login/login_state",
     "//chromeos/printing",
     "//chromeos/services/bluetooth_config:in_process_bluetooth_config",
diff --git a/chrome/browser/devtools/chrome_devtools_session.cc b/chrome/browser/devtools/chrome_devtools_session.cc
index 8b1d5f8..9804b31 100644
--- a/chrome/browser/devtools/chrome_devtools_session.cc
+++ b/chrome/browser/devtools/chrome_devtools_session.cc
@@ -66,7 +66,8 @@
   }
   if (IsDomainAvailableToUntrustedClient<TargetHandler>() ||
       channel->GetClient()->IsTrusted()) {
-    target_handler_ = std::make_unique<TargetHandler>(&dispatcher_);
+    target_handler_ = std::make_unique<TargetHandler>(
+        &dispatcher_, channel->GetClient()->IsTrusted());
   }
   if (IsDomainAvailableToUntrustedClient<BrowserHandler>() ||
       channel->GetClient()->IsTrusted()) {
diff --git a/chrome/browser/devtools/protocol/target_handler.cc b/chrome/browser/devtools/protocol/target_handler.cc
index a210b9d8..0e7ebdc 100644
--- a/chrome/browser/devtools/protocol/target_handler.cc
+++ b/chrome/browser/devtools/protocol/target_handler.cc
@@ -12,6 +12,8 @@
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/common/webui_url_constants.h"
 #include "content/public/browser/devtools_agent_host.h"
+#include "content/public/common/url_constants.h"
+#include "content/public/common/url_utils.h"
 
 namespace {
 NavigateParams CreateNavigateParams(Profile* profile,
@@ -36,7 +38,9 @@
 }
 }  // namespace
 
-TargetHandler::TargetHandler(protocol::UberDispatcher* dispatcher) {
+TargetHandler::TargetHandler(protocol::UberDispatcher* dispatcher,
+                             bool is_trusted)
+    : is_trusted_(is_trusted) {
   protocol::Target::Dispatcher::wire(dispatcher, this);
 }
 
@@ -118,6 +122,11 @@
     gurl = GURL(url::kAboutBlankURL);
   }
 
+  if (!is_trusted_ && gurl.SchemeIs(content::kChromeUIUntrustedScheme)) {
+    return protocol::Response::ServerError(
+        "Refusing to create a target with the specified URL");
+  }
+
   create_new_window = !target_browser;
   NavigateParams params = CreateNavigateParams(
       profile, gurl, ui::PAGE_TRANSITION_AUTO_TOPLEVEL, create_new_window,
diff --git a/chrome/browser/devtools/protocol/target_handler.h b/chrome/browser/devtools/protocol/target_handler.h
index 8b003f0..c72cf67 100644
--- a/chrome/browser/devtools/protocol/target_handler.h
+++ b/chrome/browser/devtools/protocol/target_handler.h
@@ -17,7 +17,7 @@
 
 class TargetHandler : public protocol::Target::Backend {
  public:
-  explicit TargetHandler(protocol::UberDispatcher* dispatcher);
+  TargetHandler(protocol::UberDispatcher* dispatcher, bool is_trusted);
 
   TargetHandler(const TargetHandler&) = delete;
   TargetHandler& operator=(const TargetHandler&) = delete;
@@ -42,6 +42,7 @@
 
  private:
   RemoteLocations remote_locations_;
+  const bool is_trusted_;
 };
 
 #endif  // CHROME_BROWSER_DEVTOOLS_PROTOCOL_TARGET_HANDLER_H_
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index f39bd1b..c213860 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -1171,11 +1171,11 @@
       "//chromeos/ash/components/dbus/update_engine",
       "//chromeos/ash/components/disks",
       "//chromeos/ash/components/enhanced_network_tts/mojom",
+      "//chromeos/ash/components/language/language_packs",
+      "//chromeos/ash/components/language/public/mojom",
       "//chromeos/ash/components/network",
       "//chromeos/ash/services/assistant/public/cpp",
       "//chromeos/components/remote_apps/mojom",
-      "//chromeos/language/language_packs",
-      "//chromeos/language/public/mojom",
       "//chromeos/login/login_state",
       "//chromeos/process_proxy",
       "//chromeos/services/machine_learning/public/cpp",
diff --git a/chrome/browser/extensions/api/debugger/debugger_apitest.cc b/chrome/browser/extensions/api/debugger/debugger_apitest.cc
index e850e804..8eb69065 100644
--- a/chrome/browser/extensions/api/debugger/debugger_apitest.cc
+++ b/chrome/browser/extensions/api/debugger/debugger_apitest.cc
@@ -712,6 +712,17 @@
       << message_;
 }
 
+IN_PROC_BROWSER_TEST_F(DebuggerExtensionApiTest, NavigateToUntrustedWebUIUrl) {
+  ASSERT_TRUE(RunExtensionTest("debugger_navigate_to_untrusted_webui_url"))
+      << message_;
+}
+
+// Tests that Target.createTarget to WebUI origins are blocked.
+IN_PROC_BROWSER_TEST_F(DebuggerExtensionApiTest, CreateTargetToUntrustedWebUI) {
+  ASSERT_TRUE(RunExtensionTest("debugger_create_target_to_untrusted_webui"))
+      << message_;
+}
+
 IN_PROC_BROWSER_TEST_F(DebuggerExtensionApiTest, IsDeveloperModeTrueHistogram) {
   profile()->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, true);
   base::HistogramTester histograms;
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
index ca3da1be..be0ba0fd 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
@@ -335,7 +335,7 @@
     if (!ShouldForwardKeyEvent()) {
       // Continue processing the key event so that the physical keyboard can
       // still work.
-      std::move(callback).Run(false);
+      std::move(callback).Run(ui::ime::KeyEventHandledState::kNotHandled);
       return;
     }
 
diff --git a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
index 63d94ac..f11df70 100644
--- a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
+++ b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
@@ -570,6 +570,10 @@
   features.Append(GenerateFeatureFlag(
       "darkmode",
       base::FeatureList::IsEnabled(chromeos::features::kDarkLightMode)));
+  features.Append(
+      GenerateFeatureFlag("touchtexteditingredesign",
+                          base::FeatureList::IsEnabled(
+                              chromeos::features::kTouchTextEditingRedesign)));
   features.Append(GenerateFeatureFlag(
       "newheader", base::FeatureList::IsEnabled(
                        chromeos::features::kVirtualKeyboardNewHeader)));
diff --git a/chrome/browser/extensions/chrome_extensions_browser_interface_binders.cc b/chrome/browser/extensions/chrome_extensions_browser_interface_binders.cc
index b5d2f3959..2bd1c06 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_interface_binders.cc
+++ b/chrome/browser/extensions/chrome_extensions_browser_interface_binders.cc
@@ -31,9 +31,9 @@
 #include "chrome/browser/speech/extension_api/tts_engine_extension_observer_chromeos.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chromeos/ash/components/enhanced_network_tts/mojom/enhanced_network_tts.mojom.h"
+#include "chromeos/ash/components/language/language_packs/language_packs_impl.h"
+#include "chromeos/ash/components/language/public/mojom/language_packs.mojom.h"
 #include "chromeos/components/remote_apps/mojom/remote_apps.mojom.h"
-#include "chromeos/language/language_packs/language_packs_impl.h"
-#include "chromeos/language/public/mojom/language_packs.mojom.h"
 #include "chromeos/services/media_perception/public/mojom/media_perception.mojom.h"
 #include "chromeos/services/tts/public/mojom/tts_service.mojom.h"
 #include "extensions/browser/api/extensions_api_client.h"
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedMainMenuItem.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedMainMenuItem.java
index 2793748f..6517155 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedMainMenuItem.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedMainMenuItem.java
@@ -293,7 +293,8 @@
             tracker.notifyEvent(EventConstants.CROW_TAB_MENU_ITEM_CLICKED);
             Activity activity = mTab.getWindowAndroid().getActivity().get();
             mCrowButtonDelegate.requestCanonicalUrl(mTab, (canonicalUrl) -> {
-                mCrowButtonDelegate.launchCustomTab(activity, mUrl, canonicalUrl, isFollowing);
+                mCrowButtonDelegate.launchCustomTab(
+                        mTab, activity, mUrl, canonicalUrl, isFollowing);
             });
         });
         RecordUserAction.record("Crow.EntryPointShown.AppMenu");
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 87b7b50..c80f330e 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -746,7 +746,7 @@
   {
     "name": "borealis-disk-management",
     "owners": [ "danielng" ],
-    "expiry_milestone": 103
+    "expiry_milestone": 110
   },
   {
     "name": "borealis-enabled",
@@ -896,11 +896,6 @@
     "expiry_milestone": 110
   },
   {
-    "name": "cellular-use-attach-apn",
-    "owners": [ "andrewlassalle", "ejcaruso", "chromeos-cellular-platform@google.com" ],
-    "expiry_milestone": 105
-  },
-  {
     "name": "cellular-use-second-euicc",
     "owners": [ "azeemarshad", "khorimoto", "cros-connectivity@google.com" ],
     // Never expires. This used in ChromeOS to switch to removable EUICC for
@@ -923,6 +918,11 @@
     "expiry_milestone": 104
   },
   {
+    "name": "chrome-sharing-crow-launch-tab",
+    "owners": [ "skare", "chrome-with-friends-robots@google.com" ],
+    "expiry_milestone": 110
+  },
+  {
     "name": "chrome-sharing-hub-launch-adjacent",
     "owners": [ "skare", "chrome-with-friends-robots@google.com" ],
     "expiry_milestone": 109
@@ -1923,6 +1923,11 @@
     "expiry_milestone": 111
   },
   {
+    "name": "enable-cros-touch-text-editing-redesign",
+    "owners": [ "michellegc", "essential-inputs-team@google.com" ],
+    "expiry_milestone": 120
+  },
+  {
     "name": "enable-cros-virtual-keyboard-api",
     "owners": [ "keithlee", "essential-inputs-team@google.com" ],
     "expiry_milestone": 97
@@ -6114,6 +6119,11 @@
     "expiry_milestone": 110
   },
   {
+    "name": "sync-access-handle-all-sync-surface",
+    "owners": [ "dslee@google.com", "chrome-owp-storage@google.com" ],
+    "expiry_milestone": 110
+  },
+  {
     "name": "sync-android-limit-ntp-promo-impressions",
     "owners": ["mmrashad@google.com", "chrome-sync-dev@google.com"],
     "expiry_milestone": 109
@@ -6597,6 +6607,11 @@
     "expiry_milestone": 102
   },
   {
+    "name": "vm-per-boot-shader-cache",
+    "owners": [ "endlesspring", "hollingum", "cpelling", "renatopereyra", "davidriley"],
+    "expiry_milestone": 111
+  },
+  {
     "name": "voice-button-in-top-toolbar",
     "owners": [
       "jds@google.com",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 2e3395d..2f642d6e 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2266,6 +2266,10 @@
     "Enables support for XFA forms in PDFs. "
     "Has no effect if Chrome was not built with XFA support.";
 
+const char kVmPerBootShaderCacheName[] = "VM per-boot shader cache";
+const char kVmPerBootShaderCacheDescription[] =
+    "Enable per-boot VM shader cache (default is per OS build).";
+
 const char kAutoWebContentsDarkModeName[] = "Auto Dark Mode for Web Contents";
 const char kAutoWebContentsDarkModeDescription[] =
     "Automatically render all web contents using a dark theme.";
@@ -2673,6 +2677,11 @@
 const char kSuppressToolbarCapturesDescription[] =
     "Suppress Toolbar Captures except when certain properties change.";
 
+const char kSyncAccessHandleAllSyncSurfaceName[] =
+    "Sync Access Handle All Sync Surface";
+const char kSyncAccessHandleAllSyncSurfaceDescription[] =
+    "Enables all-sync surface for SyncAccessHandle in File System Access API.";
+
 const char kSyncEnableHistoryDataTypeName[] = "Enable History sync data type";
 const char kSyncEnableHistoryDataTypeDescription[] =
     "Enables the History sync data type instead of TypedURLs";
@@ -3388,6 +3397,12 @@
 const char kChromeShareLongScreenshotDescription[] =
     "Enables UI to edit and share long screenshots on Android";
 
+const char kChromeSharingCrowLaunchTabName[] =
+    "Launch Thank Creator actions in standard tab";
+const char kChromeSharingCrowLaunchTabDescription[] =
+    "Launches Thank Creator actions in a traditional  new tab; default is a "
+    "custom tab. For internal debugging.";
+
 const char kChromeSharingHubLaunchAdjacentName[] =
     "Launch new share hub actions in adjacent window";
 const char kChromeSharingHubLaunchAdjacentDescription[] =
@@ -4831,12 +4846,6 @@
     "If enabled, the Settings UI will allow the user to create, edit, and "
     "delete custom APN profiles for a Cellular network.";
 
-const char kCellularUseAttachApnName[] = "Cellular use Attach APN";
-const char kCellularUseAttachApnDescription[] =
-    "Use the mobile operator database to set explicitly an Attach APN "
-    "for the LTE connections rather than letting the modem decide which "
-    "attach APN to use or retrieve it from the network";
-
 const char kCellularUseSecondEuiccName[] = "Use second Euicc";
 const char kCellularUseSecondEuiccDescription[] =
     "When enabled Cellular Setup and Settings UI will use the second available "
@@ -5955,6 +5964,10 @@
     "If enabled, the user can calibrate the touch screen displays in "
     "chrome://settings/display.";
 
+const char kTouchTextEditingRedesignName[] = "Touch Text Editing Redesign";
+const char kTouchTextEditingRedesignDescription[] =
+    "Enables new touch text editing features.";
+
 const char kTrafficCountersEnabledName[] = "Traffic counters enabled";
 const char kTrafficCountersEnabledDescription[] =
     "If enabled, data usage will be visible in the Cellular Settings UI and "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 7e69d67a..77c83cf 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1509,6 +1509,9 @@
 extern const char kSuggestionsWithSubStringMatchName[];
 extern const char kSuggestionsWithSubStringMatchDescription[];
 
+extern const char kSyncAccessHandleAllSyncSurfaceName[];
+extern const char kSyncAccessHandleAllSyncSurfaceDescription[];
+
 extern const char kSyncEnableHistoryDataTypeName[];
 extern const char kSyncEnableHistoryDataTypeDescription[];
 
@@ -1655,6 +1658,9 @@
 extern const char kGlobalVaapiLockName[];
 extern const char kGlobalVaapiLockDescription[];
 
+extern const char kVmPerBootShaderCacheDescription[];
+extern const char kVmPerBootShaderCacheName[];
+
 extern const char kVp9kSVCHWDecodingName[];
 extern const char kVp9kSVCHWDecodingDescription[];
 
@@ -1907,6 +1913,9 @@
 extern const char kChromeShareLongScreenshotName[];
 extern const char kChromeShareLongScreenshotDescription[];
 
+extern const char kChromeSharingCrowLaunchTabName[];
+extern const char kChromeSharingCrowLaunchTabDescription[];
+
 extern const char kChromeSharingHubLaunchAdjacentName[];
 extern const char kChromeSharingHubLaunchAdjacentDescription[];
 
@@ -2762,9 +2771,6 @@
 extern const char kCellularCustomAPNProfilesName[];
 extern const char kCellularCustomAPNProfilesDescription[];
 
-extern const char kCellularUseAttachApnName[];
-extern const char kCellularUseAttachApnDescription[];
-
 extern const char kCellularUseSecondEuiccName[];
 extern const char kCellularUseSecondEuiccDescription[];
 
@@ -3408,6 +3414,9 @@
 extern const char kTouchscreenCalibrationName[];
 extern const char kTouchscreenCalibrationDescription[];
 
+extern const char kTouchTextEditingRedesignName[];
+extern const char kTouchTextEditingRedesignDescription[];
+
 extern const char kTrafficCountersEnabledName[];
 extern const char kTrafficCountersEnabledDescription[];
 
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index e36d89c4..1d3ee01 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -526,6 +526,7 @@
     public static final String SEND_TAB_TO_SELF_V2 = "SendTabToSelfV2";
     public static final String SHARE_BUTTON_IN_TOP_TOOLBAR = "ShareButtonInTopToolbar";
     public static final String SHARE_CROW_BUTTON = "ShareCrowButton";
+    public static final String SHARE_CROW_BUTTON_LAUNCH_TAB = "ShareCrowLaunchTab";
     public static final String SHARED_HIGHLIGHTING_AMP = "SharedHighlightingAmp";
     public static final String SHOPPING_LIST = "ShoppingList";
     public static final String SHOW_EXTENDED_PRELOADING_SETTING = "ShowExtendedPreloadingSetting";
diff --git a/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_browsertest.cc b/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_browsertest.cc
index 9fca93e..05219c77 100644
--- a/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_browsertest.cc
+++ b/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_browsertest.cc
@@ -25,10 +25,12 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/devtools_agent_host.h"
 #include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
+#include "content/public/test/hit_test_region_observer.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/test_renderer_host.h"
 #include "content/public/test/test_utils.h"
@@ -140,6 +142,18 @@
     return browser()->tab_strip_model()->GetWebContentsAt(0);
   }
 
+  // In preparation for the migration of guest view from inner WebContents to
+  // MPArch (crbug/1261928), individual tests should avoid accessing the guest's
+  // inner WebContents. The direct access is centralized in this helper function
+  // for easier migration.
+  //
+  // TODO(crbug/1261928): Update this implementation for MPArch, and consider
+  // relocate it to `content/public/test/browser_test_utils.h`.
+  void WaitForGuestViewLoadStop(GuestViewBase* guest_view) {
+    auto* guest_contents = guest_view->web_contents();
+    ASSERT_TRUE(content::WaitForLoadStop(guest_contents));
+  }
+
   int basic_count() const { return basic_count_; }
 
  private:
@@ -160,8 +174,8 @@
 
 class UserActivationUpdateWaiter {
  public:
-  explicit UserActivationUpdateWaiter(content::WebContents* web_contents)
-      : user_activation_interceptor_(web_contents->GetPrimaryMainFrame()) {}
+  explicit UserActivationUpdateWaiter(content::RenderFrameHost* rfh)
+      : user_activation_interceptor_(rfh) {}
   ~UserActivationUpdateWaiter() = default;
 
   void Wait() {
@@ -176,28 +190,6 @@
   content::UpdateUserActivationStateInterceptor user_activation_interceptor_;
 };
 
-// Helper class to wait for document load event in the main frame.
-class DocumentLoadCompletionWaiter : public content::WebContentsObserver {
- public:
-  explicit DocumentLoadCompletionWaiter(content::WebContents* web_contents)
-      : content::WebContentsObserver(web_contents) {}
-  ~DocumentLoadCompletionWaiter() override = default;
-
-  void DocumentOnLoadCompletedInPrimaryMainFrame() override {
-    did_load_ = true;
-    run_loop_.Quit();
-  }
-
-  void Wait() {
-    if (!did_load_)
-      run_loop_.Run();
-  }
-
- private:
-  bool did_load_ = false;
-  base::RunLoop run_loop_;
-};
-
 // A DevToolsAgentHostClient implementation doing nothing.
 class StubDevToolsAgentHostClient : public content::DevToolsAgentHostClient {
  public:
@@ -523,13 +515,18 @@
   content::PrepContentsForBeforeUnloadTest(web_contents, false);
 
   // Make sure we have a guestviewmanager.
-  auto* guest_contents =
-      GetGuestViewManager()->DeprecatedWaitForSingleGuestCreated();
-  UserActivationUpdateWaiter activation_waiter(guest_contents);
+  auto* guest_view = GetGuestViewManager()->WaitForSingleGuestViewCreated();
+  ASSERT_TRUE(guest_view);
 
-  // Activate |guest_contents| through a click, then wait until the activation
-  // IPC reaches the browser process.
-  SimulateMouseClick(guest_contents, 0, blink::WebMouseEvent::Button::kLeft);
+  UserActivationUpdateWaiter activation_waiter(guest_view->GetGuestMainFrame());
+
+  // Activate |guest_view| through a click, then wait until the activation IPC
+  // reaches the browser process.
+  content::WaitForHitTestData(guest_view->GetGuestMainFrame());
+  SimulateMouseClickAt(web_contents, 0, blink::WebMouseEvent::Button::kLeft,
+                       guest_view->GetGuestMainFrame()
+                           ->GetView()
+                           ->TransformPointToRootCoordSpace(gfx::Point(5, 5)));
   activation_waiter.Wait();
 
   // Wait for a round trip to the outer renderer to ensure any beforeunload
@@ -555,9 +552,11 @@
                               "const e = document.createElement('embed');"
                               "e.src = './testEmbedded.csv'; e.type='text/csv';"
                               "document.body.appendChild(e);"));
-  DocumentLoadCompletionWaiter(
-      GetGuestViewManager()->DeprecatedWaitForNextGuestCreated())
-      .Wait();
+
+  auto* guest_view = GetGuestViewManager()->WaitForNextGuestViewCreated();
+  ASSERT_TRUE(guest_view);
+  WaitForGuestViewLoadStop(guest_view);
+
   // After load, an IPC has been sent to the renderer to update routing IDs for
   // the guest frame and the content frame (and activate the
   // PostMessageSupport). Run some JS to Ensure no DCHECKs have fired in the
diff --git a/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_interactive_uitest.cc b/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_interactive_uitest.cc
index 06fd7e1..9c8348a 100644
--- a/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_interactive_uitest.cc
+++ b/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_interactive_uitest.cc
@@ -19,6 +19,7 @@
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
+#include "content/public/test/hit_test_region_observer.h"
 #include "extensions/browser/api/extensions_api_client.h"
 #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
 #include "extensions/browser/guest_view/mime_handler_view/test_mime_handler_view_guest.h"
@@ -152,10 +153,10 @@
 
   // Make sure we have a guestviewmanager.
   auto* embedder_contents = browser()->tab_strip_model()->GetWebContentsAt(0);
-  auto* guest_contents =
-      GetGuestViewManager()->DeprecatedWaitForSingleGuestCreated();
-  auto* guest_rwh =
-      guest_contents->GetRenderWidgetHostView()->GetRenderWidgetHost();
+  auto* guest_view = GetGuestViewManager()->WaitForSingleGuestViewCreated();
+  ASSERT_TRUE(guest_view);
+
+  auto* guest_rwh = guest_view->GetGuestMainFrame()->GetRenderWidgetHost();
 
   // Wait for fullscreen mode.
   fullscreen_waiter.Wait();
@@ -163,14 +164,20 @@
 
   // Send a touch to focus the guest. We can't directly test that the correct
   // RenderWidgetHost got focus, but the wait seems to work.
-  SimulateMouseClick(guest_contents, 0, blink::WebMouseEvent::Button::kLeft);
+  content::WaitForHitTestData(guest_view->GetGuestMainFrame());
+  SimulateMouseClickAt(
+      embedder_contents, 0, blink::WebMouseEvent::Button::kLeft,
+      guest_rwh->GetView()->TransformPointToRootCoordSpace(gfx::Point(7, 7)));
+
   while (!IsRenderWidgetHostFocused(guest_rwh)) {
     base::RunLoop run_loop;
     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout());
     run_loop.Run();
   }
-  EXPECT_EQ(guest_contents, content::GetFocusedWebContents(embedder_contents));
+
+  EXPECT_EQ(embedder_contents->GetFocusedFrame(),
+            guest_view->GetGuestMainFrame());
 
   // Send <esc> to exit fullscreen.
   ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_ESCAPE, false,
diff --git a/chrome/browser/policy/webhid_device_policy_handler.cc b/chrome/browser/policy/webhid_device_policy_handler.cc
index 46a187f3..be8ed624 100644
--- a/chrome/browser/policy/webhid_device_policy_handler.cc
+++ b/chrome/browser/policy/webhid_device_policy_handler.cc
@@ -53,14 +53,17 @@
   DCHECK(value);
   int item_index = 0;
   for (const auto& item : value->GetList()) {
+    if (!item.is_dict())
+      continue;
     int url_index = 0;
     auto* urls_list = item.GetDict().FindList(kUrlsKey);
     if (!urls_list)
       continue;
 
     for (const auto& url_value : *urls_list) {
-      DCHECK(url_value.is_string());
-      GURL url(url_value.GetString());
+      GURL url;
+      if (url_value.is_string())
+        url = GURL(url_value.GetString());
       // If `url` is invalid, emit an error but do not prevent the policy from
       // being applied.
       if (errors && !url.is_valid()) {
diff --git a/chrome/browser/policy/webhid_device_policy_handler_unittest.cc b/chrome/browser/policy/webhid_device_policy_handler_unittest.cc
index e970a2e..8761800 100644
--- a/chrome/browser/policy/webhid_device_policy_handler_unittest.cc
+++ b/chrome/browser/policy/webhid_device_policy_handler_unittest.cc
@@ -621,6 +621,51 @@
         ])",
     },
     {
+        key::kWebHidAllowDevicesForUrls,
+        prefs::kManagedWebHidAllowDevicesForUrls,
+        R"(
+        [
+          {
+            "devices": [
+              {
+                "vendor_id": 1234
+              }
+            ],
+            "urls": [
+              123
+            ]
+          }
+        ])",
+        u"Error at WebHidAllowDevicesForUrls[0].urls[0]: Schema validation "
+        u"error: Policy type mismatch: expected: \"string\", actual: "
+        u"\"integer\".\nError at WebHidAllowDevicesForUrls[0].urls[0]: Invalid "
+        u"URL.",
+        R"(
+        [
+          {
+            "devices": [
+              {
+                "vendor_id": 1234
+              }
+            ],
+            "urls": [
+            ]
+          }
+        ])",
+    },
+    {
+        key::kWebHidAllowDevicesForUrls,
+        prefs::kManagedWebHidAllowDevicesForUrls,
+        R"(
+        [123]
+        )",
+        u"Error at WebHidAllowDevicesForUrls[0]: Schema validation error: "
+        u"Policy type mismatch: expected: \"dictionary\", actual: \"integer\".",
+        R"(
+        []
+        )",
+    },
+    {
         key::kWebHidAllowDevicesWithHidUsagesForUrls,
         prefs::kManagedWebHidAllowDevicesWithHidUsagesForUrls,
         R"(
@@ -873,6 +918,52 @@
           }
         ])",
     },
+    {
+        key::kWebHidAllowDevicesWithHidUsagesForUrls,
+        prefs::kManagedWebHidAllowDevicesWithHidUsagesForUrls,
+        R"(
+        [
+          {
+            "usages": [
+              {
+                "usage_page": 1234
+              }
+            ],
+            "urls": [
+              123
+            ]
+          }
+        ])",
+        u"Error at WebHidAllowDevicesWithHidUsagesForUrls[0].urls[0]: Schema "
+        u"validation error: Policy type mismatch: expected: \"string\", "
+        u"actual: \"integer\".\nError at "
+        u"WebHidAllowDevicesWithHidUsagesForUrls[0].urls[0]: Invalid URL.",
+        R"(
+        [
+          {
+            "usages": [
+              {
+                "usage_page": 1234
+              }
+            ],
+            "urls": [
+            ]
+          }
+        ])",
+    },
+    {
+        key::kWebHidAllowDevicesWithHidUsagesForUrls,
+        prefs::kManagedWebHidAllowDevicesWithHidUsagesForUrls,
+        R"(
+        [123]
+        )",
+        u"Error at WebHidAllowDevicesWithHidUsagesForUrls[0]: Schema "
+        u"validation error: Policy type mismatch: expected: \"dictionary\", "
+        u"actual: \"integer\".",
+        R"(
+        []
+        )",
+    },
 };
 
 INSTANTIATE_TEST_SUITE_P(WebHidInvalidPolicyTests,
diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h
index d6126b9f..05257a6a 100644
--- a/chrome/browser/profiles/profile.h
+++ b/chrome/browser/profiles/profile.h
@@ -287,7 +287,7 @@
   // profile is not OffTheRecord.
   virtual const Profile* GetOriginalProfile() const = 0;
 
-  // Returns whether the profile is associated with a child account.
+  // Returns whether the profile is associated with the account of a child.
   virtual bool IsChild() const = 0;
 
   // Returns whether opening browser windows is allowed in this profile. For
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_search.html b/chrome/browser/resources/chromeos/emoji_picker/emoji_search.html
index 082a8c6..a501e02 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_search.html
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_search.html
@@ -126,7 +126,7 @@
   }
 
   :host([v2-enabled]) #results {
-    padding-top: 13px;
+    padding: 13px 2px 2px 2px;
   }
 
   #no-emoji-image {
diff --git a/chrome/browser/resources/omnibox/BUILD.gn b/chrome/browser/resources/omnibox/BUILD.gn
index d06c5a7..20565f1d 100644
--- a/chrome/browser/resources/omnibox/BUILD.gn
+++ b/chrome/browser/resources/omnibox/BUILD.gn
@@ -10,7 +10,7 @@
 ts_files = [
   "omnibox_element.ts",
   "omnibox_input.ts",
-  "omnibox.js",
+  "omnibox.ts",
   "omnibox_output.js",
 ]
 
diff --git a/chrome/browser/resources/omnibox/omnibox.js b/chrome/browser/resources/omnibox/omnibox.js
deleted file mode 100644
index e1eca82..0000000
--- a/chrome/browser/resources/omnibox/omnibox.js
+++ /dev/null
@@ -1,439 +0,0 @@
-// Copyright (c) 2012 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 './strings.m.js';
-import './omnibox_input.js';
-import './omnibox_output.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';
-
-import {OmniboxPageCallbackRouter, OmniboxPageHandler, OmniboxPageHandlerRemote, OmniboxResponse} from './omnibox.mojom-webui.js';
-import {DisplayInputs, OmniboxInput, QueryInputs} from './omnibox_input.js';
-import {OmniboxOutput} from './omnibox_output.js';
-
-/**
- * Javascript for omnibox.html, served from chrome://omnibox/
- * This is used to debug omnibox ranking.  The user enters some text
- * into a box, submits it, and then sees lots of debug information
- * from the autocompleter that shows what omnibox would do with that
- * input.
- *
- * The simple object defined in this javascript file listens for
- * certain events on omnibox.html, sends (when appropriate) the
- * input text to C++ code to start the omnibox autcomplete controller
- * working, and listens from callbacks from the C++ code saying that
- * results are available.  When results (possibly intermediate ones)
- * are available, the Javascript formats them and displays them.
- */
-
-/**
- * @typedef {{
- *   inputText: string,
- *   callback: function(!OmniboxResponse):Promise,
- *   display: boolean,
- * }}
- */
-let OmniboxRequest;
-
-/**
- * @typedef {{
- *   batchMode: string,
- *   batchQueryInputs: Array<QueryInputs>,
- * }}
- */
-let BatchSpecifier;
-
-/**
- * @typedef {{
- *   queryInputs: QueryInputs,
- *   displayInputs: DisplayInputs,
- *   responsesHistory: !Array<!Array<!OmniboxResponse>>,
- * }}
- */
-let OmniboxExport;
-
-/** @type {!BrowserProxy} */
-let browserProxy;
-/** @type {!OmniboxInput} */
-let omniboxInput;
-/** @type {!OmniboxOutput} */
-let omniboxOutput;
-/** @type {!ExportDelegate} */
-let exportDelegate;
-
-class BrowserProxy {
-  /** @param {!OmniboxOutput} omniboxOutput */
-  constructor(omniboxOutput) {
-    /** @private {!OmniboxPageCallbackRouter} */
-    this.callbackRouter_ = new OmniboxPageCallbackRouter();
-
-    this.callbackRouter_.handleNewAutocompleteResponse.addListener(
-        this.handleNewAutocompleteResponse.bind(this));
-    this.callbackRouter_.handleNewAutocompleteQuery.addListener(
-        this.handleNewAutocompleteQuery.bind(this));
-    this.callbackRouter_.handleAnswerImageData.addListener(
-        omniboxOutput.updateAnswerImage.bind(omniboxOutput));
-
-    /** @private {!OmniboxPageHandlerRemote} */
-    this.handler_ = OmniboxPageHandler.getRemote();
-    this.handler_.setClientPage(
-        this.callbackRouter_.$.bindNewPipeAndPassRemote());
-
-    /** @private {?OmniboxRequest} */
-    this.lastRequest;
-  }
-
-  /**
-   * @param {!OmniboxResponse} response
-   * @param {boolean} isPageController
-   */
-  handleNewAutocompleteResponse(response, isPageController) {
-    const isForLastPageRequest =
-        this.isForLastPageRequest(response.inputText, isPageController);
-
-    // When unfocusing the browser omnibox, the autocomplete controller
-    // sends a response with no combined results. This response is ignored
-    // in order to prevent the previous non-empty response from being
-    // hidden and because these results wouldn't normally be displayed by
-    // the browser window omnibox.
-    if (isForLastPageRequest && this.lastRequest.display ||
-        omniboxInput.connectWindowOmnibox && !isPageController &&
-            response.combinedResults.length) {
-      omniboxOutput.addAutocompleteResponse(response);
-    }
-
-    // TODO(orinj|manukh): If |response.done| but not |isForLastPageRequest|
-    // then callback is being dropped. We should guarantee that callback is
-    // always called because some callers await promises.
-    if (isForLastPageRequest && response.done) {
-      this.lastRequest.callback(response);
-      this.lastRequest = null;
-    }
-  }
-
-  /**
-   * @param {boolean} isPageController
-   * @param {string} inputText
-   */
-  handleNewAutocompleteQuery(isPageController, inputText) {
-    // If the request originated from the debug page and is not for display,
-    // then we don't want to clear the omniboxOutput.
-    if (this.isForLastPageRequest(inputText, isPageController) &&
-            this.lastRequest.display ||
-        omniboxInput.connectWindowOmnibox && !isPageController) {
-      omniboxOutput.prepareNewQuery();
-    }
-  }
-
-  /**
-   * @param {string} inputText
-   * @param {boolean} resetAutocompleteController
-   * @param {number} cursorPosition
-   * @param {boolean} zeroSuggest
-   * @param {boolean} preventInlineAutocomplete
-   * @param {boolean} preferKeyword
-   * @param {string} currentUrl
-   * @param {number} pageClassification
-   * @param {boolean} display
-   * @return {!Promise}
-   */
-  makeRequest(
-      inputText, resetAutocompleteController, cursorPosition, zeroSuggest,
-      preventInlineAutocomplete, preferKeyword, currentUrl, pageClassification,
-      display) {
-    return new Promise(resolve => {
-      this.lastRequest = {inputText, callback: resolve, display};
-      this.handler_.startOmniboxQuery(
-          inputText, resetAutocompleteController, cursorPosition, zeroSuggest,
-          preventInlineAutocomplete, preferKeyword, currentUrl,
-          pageClassification);
-    });
-  }
-
-  /**
-   * @param {string} inputText
-   * @param {boolean} isPageController
-   * @return {boolean}
-   */
-  isForLastPageRequest(inputText, isPageController) {
-    // Note: Using inputText is a sufficient fix for the way this is used today,
-    // but in principle it would be better to associate requests with responses
-    // using a unique session identifier, for example by rolling an integer each
-    // time a request is made. Doing so would require extra bookkeeping on the
-    // host side, so for now we keep it simple.
-    return isPageController && this.lastRequest !== null &&
-        this.lastRequest.inputText.trimStart() === inputText;
-  }
-}
-
-document.addEventListener('DOMContentLoaded', () => {
-  omniboxInput = /** @type {!OmniboxInput} */ ($('omnibox-input'));
-  omniboxOutput =
-      /** @type {!OmniboxOutput} */ ($('omnibox-output'));
-  browserProxy = new BrowserProxy(omniboxOutput);
-  exportDelegate = new ExportDelegate(omniboxOutput, omniboxInput);
-
-  omniboxInput.addEventListener('query-inputs-changed', e => {
-    browserProxy.makeRequest(
-        e.detail.inputText, e.detail.resetAutocompleteController,
-        e.detail.cursorPosition, e.detail.zeroSuggest,
-        e.detail.preventInlineAutocomplete, e.detail.preferKeyword,
-        e.detail.currentUrl, e.detail.pageClassification, true);
-  });
-  omniboxInput.addEventListener(
-      'display-inputs-changed',
-      e => omniboxOutput.updateDisplayInputs(e.detail));
-  omniboxInput.addEventListener(
-      'filter-input-changed', e => omniboxOutput.updateFilterText(e.detail));
-  omniboxInput.addEventListener('import', e => exportDelegate.import(e.detail));
-  omniboxInput.addEventListener(
-      'process-batch', e => exportDelegate.processBatchData(e.detail));
-  omniboxInput.addEventListener(
-      'export-clipboard', () => exportDelegate.exportClipboard());
-  omniboxInput.addEventListener(
-      'export-file', () => exportDelegate.exportFile());
-  omniboxInput.addEventListener(
-      'response-select',
-      e => omniboxOutput.updateSelectedResponseIndex(e.detail));
-
-  omniboxOutput.addEventListener(
-      'responses-count-changed', e => omniboxInput.responsesCount = e.detail);
-
-  omniboxOutput.updateDisplayInputs(omniboxInput.displayInputs);
-});
-
-class ExportDelegate {
-  /**
-   * @param {!OmniboxOutput} omniboxOutput
-   * @param {!OmniboxInput} omniboxInput
-   */
-  constructor(omniboxOutput, omniboxInput) {
-    /** @private {!OmniboxInput} */
-    this.omniboxInput_ = omniboxInput;
-    /** @private {!OmniboxOutput} */
-    this.omniboxOutput_ = omniboxOutput;
-  }
-
-  /**
-   * Import a single data item previously exported.
-   * @param {OmniboxExport} importData
-   * @return {boolean} true if a single data item was imported for viewing;
-   * false if import failed.
-   */
-  import(importData) {
-    if (!validateImportData_(importData)) {
-      // TODO(manukh): Make use of this return value to fix the UI state
-      // bug in omnibox_input.js -- see the related TODO there.
-      return false;
-    }
-    this.omniboxInput_.queryInputs = importData.queryInputs;
-    this.omniboxInput_.displayInputs = importData.displayInputs;
-    this.omniboxOutput_.updateDisplayInputs(importData.displayInputs);
-    this.omniboxOutput_.setResponsesHistory(importData.responsesHistory);
-    return true;
-  }
-
-  /**
-   * This is the worker function that transforms query inputs to accumulate
-   * batch exports, then finally initiates a download for the complete set.
-   * @param {!Array<!QueryInputs>} batchQueryInputs
-   * @param {string} batchName
-   */
-  async processBatch(batchQueryInputs, batchName) {
-    const batchExports = [];
-    for (const queryInputs of batchQueryInputs) {
-    const omniboxResponse = await browserProxy.makeRequest(
-        queryInputs.inputText, queryInputs.resetAutocompleteController,
-        queryInputs.cursorPosition, queryInputs.zeroSuggest,
-        queryInputs.preventInlineAutocomplete, queryInputs.preferKeyword,
-        queryInputs.currentUrl, queryInputs.pageClassification, false);
-    const exportData = {
-      queryInputs,
-      // TODO(orinj|manukh): Make the schema consistent and remove
-      // the extra level of array nesting.  [[This]] is done for now
-      // so that elements can be extracted in the form import expects.
-      responsesHistory: [[omniboxResponse]],
-      displayInputs: this.omniboxInput_.displayInputs,
-    };
-    batchExports.push(exportData);
-    }
-    const variationInfo =
-        await sendWithPromise('requestVariationInfo', true);
-    const pathInfo = await sendWithPromise('requestPathInfo');
-
-    const now = new Date();
-    const fileName = `omnibox_batch_${ExportDelegate.getTimeStamp(now)}.json`;
-    // If this data format changes, please roll schemaVersion.
-    const batchData = {
-      schemaKind: 'Omnibox Batch Export',
-      schemaVersion: 3,
-      dateCreated: now.toISOString(),
-      author: '',
-      description: '',
-      authorTool: 'chrome://omnibox',
-      batchName,
-      versionDetails: ExportDelegate.getVersionDetails_(),
-      variationInfo,
-      pathInfo,
-      appVersion: navigator.appVersion,
-      batchExports,
-    };
-    ExportDelegate.download_(batchData, fileName);
-  }
-
-  /**
-   * Event handler for uploaded batch processing specifier data, kicks off
-   * the processBatch asynchronous pipeline.
-   * @param {!BatchSpecifier} processBatchData
-   */
-  processBatchData(processBatchData) {
-    if (processBatchData.batchMode && processBatchData.batchQueryInputs &&
-        processBatchData.batchName) {
-      this.processBatch(
-          processBatchData.batchQueryInputs, processBatchData.batchName);
-    } else {
-    const expected = {
-      batchMode: 'combined',
-      batchName: 'name for this batch of queries',
-      batchQueryInputs: [{
-        inputText: 'example input text',
-        cursorPosition: 18,
-        resetAutocompleteController: false,
-        cursorLock: false,
-        zeroSuggest: false,
-        preventInlineAutocomplete: false,
-        preferKeyword: false,
-        currentUrl: '',
-        pageClassification: '4',
-      }],
-    };
-    console.error(`Invalid batch specifier data.  Expected format: \n${
-        JSON.stringify(expected, null, 2)}`);
-    }
-  }
-
-  exportClipboard() {
-    navigator.clipboard.writeText(JSON.stringify(this.exportData_, null, 2))
-        .catch(error => console.error('unable to export to clipboard:', error));
-  }
-
-  exportFile() {
-    const exportData = this.exportData_;
-    const timeStamp = ExportDelegate.getTimeStamp();
-    const fileName =
-        `omnibox_debug_export_${exportData.queryInputs.inputText}_${timeStamp}.json`;
-    ExportDelegate.download_(exportData, fileName);
-  }
-
-  /** @private @return {OmniboxExport} */
-  get exportData_() {
-    return {
-      versionDetails: ExportDelegate.getVersionDetails_(),
-      queryInputs: this.omniboxInput_.queryInputs,
-      displayInputs: this.omniboxInput_.displayInputs,
-      responsesHistory: this.omniboxOutput_.responsesHistory,
-    };
-  }
-
-  /**
-   * @private
-   * @param {Object} object
-   * @param {string} fileName
-   */
-  static download_(object, fileName) {
-    const content = JSON.stringify(object, null, 2);
-    const blob = new Blob([content], {type: 'application/json'});
-    const url = URL.createObjectURL(blob);
-    const a = document.createElement('a');
-    a.href = url;
-    a.download = fileName;
-    a.click();
-  }
-
-  /**
-   * @param {Date=} date
-   * @return {string} A sortable timestamp string for use in filenames.
-   */
-  static getTimeStamp(date) {
-    if (!date) {
-      date = new Date();
-    }
-    const iso = date.toISOString();
-    return iso.replace(/:/g, '').split('.')[0];
-  }
-
-  /** @private @return {Object} */
-  static getVersionDetails_() {
-    const loadTimeDataKeys = ['cl', 'command_line', 'executable_path',
-      'language', 'official', 'os_type', 'profile_path', 'useragent',
-      'version', 'version_processor_variation', 'version_modifier'];
-    return Object.fromEntries(
-        loadTimeDataKeys.map(key => {
-    let valueOrError;
-    try {
-      valueOrError = loadTimeData.getValue(key);
-    } catch (e) {
-      valueOrError = e.toString();
-    }
-    return [key, valueOrError];
-        }));
-  }
-}
-
-/**
- * This is the minimum validation required to ensure no console errors.
- * Invalid importData that passes validation will be processed with a
- * best-attempt; e.g. if responses are missing 'relevance' values, then those
- * cells will be left blank.
- * @private
- * @param {OmniboxExport} importData
- * @return {boolean}
- */
-function validateImportData_(importData) {
-  const EXPECTED_FORMAT = {
-    queryInputs: {},
-    displayInputs: {},
-    responsesHistory: [[{combinedResults: [], resultsByProvider: []}]],
-  };
-  const INVALID_MESSAGE = `Invalid import format; expected \n${
-      JSON.stringify(EXPECTED_FORMAT, null, 2)};\n`;
-
-  if (!importData) {
-    console.error(INVALID_MESSAGE + 'received non object.');
-    return false;
-  }
-
-  if (!importData.queryInputs || !importData.displayInputs) {
-    console.error(
-        INVALID_MESSAGE +
-        'import missing objects queryInputs and displayInputs.');
-    return false;
-  }
-
-  if (!Array.isArray(importData.responsesHistory)) {
-    console.error(INVALID_MESSAGE + 'import missing array responsesHistory.');
-    return false;
-  }
-
-  if (!importData.responsesHistory.every(Array.isArray)) {
-    console.error(INVALID_MESSAGE + 'responsesHistory contains non arrays.');
-    return false;
-  }
-
-  if (!importData.responsesHistory.every(
-      responses => responses.every(
-          ({combinedResults, resultsByProvider}) =>
-              Array.isArray(combinedResults) &&
-              Array.isArray(resultsByProvider)))) {
-    console.error(
-        INVALID_MESSAGE +
-        'responsesHistory items\' items missing combinedResults and ' +
-        'resultsByProvider arrays.');
-    return false;
-  }
-
-  return true;
-}
diff --git a/chrome/browser/resources/omnibox/omnibox.ts b/chrome/browser/resources/omnibox/omnibox.ts
new file mode 100644
index 0000000..c421673
--- /dev/null
+++ b/chrome/browser/resources/omnibox/omnibox.ts
@@ -0,0 +1,399 @@
+// Copyright (c) 2012 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 './strings.m.js';
+import './omnibox_input.js';
+import './omnibox_output.js';
+
+import {assert} from 'chrome://resources/js/assert_ts.js';
+import {sendWithPromise} from 'chrome://resources/js/cr.m.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
+
+import {OmniboxPageCallbackRouter, OmniboxPageHandler, OmniboxPageHandlerRemote, OmniboxResponse} from './omnibox.mojom-webui.js';
+import {DisplayInputs, OmniboxInput, QueryInputs} from './omnibox_input.js';
+import {OmniboxOutput} from './omnibox_output.js';
+
+/**
+ * Javascript for omnibox.html, served from chrome://omnibox/
+ * This is used to debug omnibox ranking. The user enters some text into a box,
+ * submits it, and then sees lots of debug information from the autocompleter
+ * that shows what omnibox would do with that input.
+ *
+ * The simple object defined in this javascript file listens for contain events
+ * on omnibox.html, sends (when appropriate) the input text to C++ code to start
+ * the omnibox autcomplete controller working, and listens from callbacks from
+ * the C++ code saying that results are available. When results (possibly
+ * intermediate ones) are available, the Javascript formats them and displays
+ * them.
+ */
+
+declare global {
+  interface HTMLElementEventMap {
+    'query-inputs-changed': CustomEvent<QueryInputs>;
+    'display-inputs-changed': CustomEvent<DisplayInputs>;
+    'filter-input-changed': CustomEvent<string>;
+    'import': CustomEvent<OmniboxExport>;
+    'process-batch': CustomEvent<BatchSpecifier>;
+    'response-select': CustomEvent<number>;
+    'responses-count-changed': CustomEvent<number>;
+  }
+
+  interface HTMLElementTagNameMap {
+    'OmniboxInput': OmniboxInput;
+    'OmniboxOutput': OmniboxOutput;
+  }
+}
+
+interface OmniboxRequest {
+  inputText: string;
+  callback: (omniboxResponse: OmniboxResponse) => void;
+  display: boolean;
+}
+
+interface BatchSpecifier {
+  batchName: string;
+  batchMode: string;
+  batchQueryInputs: QueryInputs[];
+}
+
+interface OmniboxExport {
+  versionDetails: Record<string, string>;
+  queryInputs: QueryInputs;
+  displayInputs: DisplayInputs;
+  responsesHistory: OmniboxResponse[][];
+}
+
+let browserProxy: BrowserProxy;
+let omniboxInput: OmniboxInput;
+let omniboxOutput: OmniboxOutput;
+let exportDelegate: ExportDelegate;
+
+class BrowserProxy {
+  private callbackRouter_: OmniboxPageCallbackRouter =
+      new OmniboxPageCallbackRouter();
+  private handler_: OmniboxPageHandlerRemote;
+  private lastRequest: OmniboxRequest | null = null;
+
+  constructor(omniboxOutput: OmniboxOutput) {
+    this.callbackRouter_.handleNewAutocompleteResponse.addListener(
+        this.handleNewAutocompleteResponse.bind(this));
+    this.callbackRouter_.handleNewAutocompleteQuery.addListener(
+        this.handleNewAutocompleteQuery.bind(this));
+    this.callbackRouter_.handleAnswerImageData.addListener(
+        omniboxOutput.updateAnswerImage.bind(omniboxOutput));
+
+    this.handler_ = OmniboxPageHandler.getRemote();
+    this.handler_.setClientPage(
+        this.callbackRouter_.$.bindNewPipeAndPassRemote());
+  }
+
+  private handleNewAutocompleteResponse(
+      response: OmniboxResponse, isPageController: boolean) {
+    const isForLastPageRequest =
+        this.isForLastPageRequest(response.inputText, isPageController);
+
+    // When unfocusing the browser omnibox, the autocomplete controller
+    // sends a response with no combined results. This response is ignored
+    // in order to prevent the previous non-empty response from being
+    // hidden and because these results wouldn't normally be displayed by
+    // the browser window omnibox.
+    if (isForLastPageRequest && this.lastRequest!.display ||
+        omniboxInput.connectWindowOmnibox && !isPageController &&
+        response.combinedResults.length) {
+      omniboxOutput.addAutocompleteResponse(response);
+    }
+
+    // TODO(orinj|manukh): If `response.done` but not `isForLastPageRequest`
+    //  then callback is being dropped. We should guarantee that callback is
+    //  always called because some callers await promises.
+    if (isForLastPageRequest && response.done) {
+      assert(this.lastRequest);
+      this.lastRequest.callback(response);
+      this.lastRequest = null;
+    }
+  }
+
+  private handleNewAutocompleteQuery(
+      isPageController: boolean, inputText: string) {
+    // If the request originated from the debug page and is not for display,
+    // then we don't want to clear the omniboxOutput.
+    if (this.isForLastPageRequest(inputText, isPageController) &&
+        this.lastRequest!.display ||
+        omniboxInput.connectWindowOmnibox && !isPageController) {
+      omniboxOutput.prepareNewQuery();
+    }
+  }
+
+  makeRequest(
+      inputText: string, resetAutocompleteController: boolean,
+      cursorPosition: number, zeroSuggest: boolean,
+      preventInlineAutocomplete: boolean, preferKeyword: boolean,
+      currentUrl: string, pageClassification: number,
+      display: boolean): Promise<OmniboxResponse> {
+    return new Promise(resolve => {
+      this.lastRequest = {inputText, callback: resolve, display};
+      this.handler_.startOmniboxQuery(
+          inputText, resetAutocompleteController, cursorPosition, zeroSuggest,
+          preventInlineAutocomplete, preferKeyword, currentUrl,
+          pageClassification);
+    });
+  }
+
+  isForLastPageRequest(inputText: string, isPageController: boolean): boolean {
+    // Note: Using inputText is a sufficient fix for the way this is used today,
+    // but in principle it would be better to associate requests with responses
+    // using a unique session identifier, for example by rolling an integer each
+    // time a request is made. Doing so would require extra bookkeeping on the
+    // host side, so for now we keep it simple.
+    return isPageController && !!this.lastRequest &&
+        this.lastRequest!.inputText.trimStart() === inputText;
+  }
+}
+
+document.addEventListener('DOMContentLoaded', () => {
+  omniboxInput = document.querySelector('omnibox-input')!;
+  omniboxOutput = document.querySelector('omnibox-output')!;
+  browserProxy = new BrowserProxy(omniboxOutput);
+  exportDelegate = new ExportDelegate(omniboxOutput, omniboxInput);
+
+  omniboxInput.addEventListener('query-inputs-changed', e => {
+    browserProxy.makeRequest(
+        e.detail.inputText, e.detail.resetAutocompleteController,
+        e.detail.cursorPosition, e.detail.zeroSuggest,
+        e.detail.preventInlineAutocomplete, e.detail.preferKeyword,
+        e.detail.currentUrl, e.detail.pageClassification, true);
+  });
+  omniboxInput.addEventListener(
+      'display-inputs-changed',
+      e => omniboxOutput.updateDisplayInputs(e.detail));
+  omniboxInput.addEventListener(
+      'filter-input-changed', e => omniboxOutput.updateFilterText(e.detail));
+  omniboxInput.addEventListener('import', e => exportDelegate.import(e.detail));
+  omniboxInput.addEventListener(
+      'process-batch', e => exportDelegate.processBatchData(e.detail));
+  omniboxInput.addEventListener(
+      'export-clipboard', () => exportDelegate.exportClipboard());
+  omniboxInput.addEventListener(
+      'export-file', () => exportDelegate.exportFile());
+  omniboxInput.addEventListener(
+      'response-select',
+      e => omniboxOutput.updateSelectedResponseIndex(e.detail));
+
+  omniboxOutput.addEventListener(
+      'responses-count-changed', e => omniboxInput.responsesCount = e.detail);
+
+  omniboxOutput.updateDisplayInputs(omniboxInput.displayInputs);
+});
+
+class ExportDelegate {
+  private omniboxInput_: OmniboxInput;
+  private omniboxOutput_: OmniboxOutput;
+
+  constructor(omniboxOutput: OmniboxOutput, omniboxInput: OmniboxInput) {
+    this.omniboxInput_ = omniboxInput;
+    this.omniboxOutput_ = omniboxOutput;
+  }
+
+  /**
+   * Import a single data item previously exported. Returns true if a single
+   * data item was imported for viewing; false if import failed.
+   */
+  import(importData: OmniboxExport): boolean {
+    if (!validateImportData(importData)) {
+      // TODO(manukh): Make use of this return value to fix the UI state bug in
+      //  omnibox_input.js -- see the related TODO there.
+      return false;
+    }
+    this.omniboxInput_.queryInputs = importData.queryInputs;
+    this.omniboxInput_.displayInputs = importData.displayInputs;
+    this.omniboxOutput_.updateDisplayInputs(importData.displayInputs);
+    this.omniboxOutput_.setResponsesHistory(importData.responsesHistory);
+    return true;
+  }
+
+  /**
+   * This is the worker function that transforms query inputs to accumulate
+   * batch exports, then finally initiates a download for the complete set.
+   */
+  private async processBatch(
+      batchQueryInputs: QueryInputs[], batchName: string) {
+    const batchExports = [];
+    for (const queryInputs of batchQueryInputs) {
+      const omniboxResponse = await browserProxy.makeRequest(
+          queryInputs.inputText, queryInputs.resetAutocompleteController,
+          queryInputs.cursorPosition, queryInputs.zeroSuggest,
+          queryInputs.preventInlineAutocomplete, queryInputs.preferKeyword,
+          queryInputs.currentUrl, queryInputs.pageClassification, false);
+      const exportData = {
+        queryInputs,
+        // TODO(orinj|manukh): Make the schema consistent and remove the extra
+        //  level of array nesting. [[This]] is done for now so that elements
+        //  can be extracted in the form import expects.
+        responsesHistory: [[omniboxResponse]],
+        displayInputs: this.omniboxInput_.displayInputs,
+      };
+      batchExports.push(exportData);
+    }
+    const variationInfo =
+        await sendWithPromise('requestVariationInfo', true);
+    const pathInfo = await sendWithPromise('requestPathInfo');
+
+    const now = new Date();
+    const fileName = `omnibox_batch_${ExportDelegate.getTimeStamp(now)}.json`;
+    // If this data format changes, please roll schemaVersion.
+    const batchData = {
+      schemaKind: 'Omnibox Batch Export',
+      schemaVersion: 3,
+      dateCreated: now.toISOString(),
+      author: '',
+      description: '',
+      authorTool: 'chrome://omnibox',
+      batchName,
+      versionDetails: ExportDelegate.getVersionDetails(),
+      variationInfo,
+      pathInfo,
+      appVersion: navigator.appVersion,
+      batchExports,
+    };
+    ExportDelegate.download(batchData, fileName);
+  }
+
+  /**
+   * Event handler for uploaded batch processing specifier data, kicks off
+   * the processBatch asynchronous pipeline.
+   */
+  processBatchData(processBatchData: BatchSpecifier) {
+    if (processBatchData.batchMode && processBatchData.batchQueryInputs &&
+        processBatchData.batchName) {
+      this.processBatch(
+          processBatchData.batchQueryInputs, processBatchData.batchName);
+    } else {
+      const expected = {
+        batchMode: 'combined',
+        batchName: 'name for this batch of queries',
+        batchQueryInputs: [{
+          inputText: 'example input text',
+          cursorPosition: 18,
+          resetAutocompleteController: false,
+          cursorLock: false,
+          zeroSuggest: false,
+          preventInlineAutocomplete: false,
+          preferKeyword: false,
+          currentUrl: '',
+          pageClassification: '4',
+        }],
+      };
+      console.error(`Invalid batch specifier data.  Expected format: \n${
+          JSON.stringify(expected, null, 2)}`);
+    }
+  }
+
+  exportClipboard() {
+    navigator.clipboard.writeText(JSON.stringify(this.exportData, null, 2))
+        .catch(error => console.error('unable to export to clipboard:', error));
+  }
+
+  exportFile() {
+    const exportData = this.exportData;
+    const timeStamp = ExportDelegate.getTimeStamp();
+    const fileName =
+        `omnibox_debug_export_${exportData.queryInputs.inputText}_${timeStamp}.json`;
+    ExportDelegate.download(exportData, fileName);
+  }
+
+  private get exportData(): OmniboxExport {
+    return {
+      versionDetails: ExportDelegate.getVersionDetails(),
+      queryInputs: this.omniboxInput_.queryInputs,
+      displayInputs: this.omniboxInput_.displayInputs,
+      responsesHistory: this.omniboxOutput_.responsesHistory,
+    };
+  }
+
+  private static download(object: Object, fileName: string) {
+    const content = JSON.stringify(object, null, 2);
+    const blob = new Blob([content], {type: 'application/json'});
+    const url = URL.createObjectURL(blob);
+    const a = document.createElement('a');
+    a.href = url;
+    a.download = fileName;
+    a.click();
+  }
+
+  /**
+   * Returns a sortable timestamp string for use in filenames.
+   */
+  private static getTimeStamp(date: Date = new Date()): string {
+    const iso = date.toISOString();
+    return iso.replace(/:/g, '').split('.')[0]!;
+  }
+
+  private static getVersionDetails(): Record<string, string> {
+    const loadTimeDataKeys = ['cl', 'command_line', 'executable_path',
+      'language', 'official', 'os_type', 'profile_path', 'useragent',
+      'version', 'version_processor_variation', 'version_modifier'];
+    return Object.fromEntries(
+        loadTimeDataKeys.map(key => {
+          let valueOrError;
+          try {
+            valueOrError = loadTimeData.getValue(key);
+          } catch (e) {
+            valueOrError = (e as Error).toString();
+          }
+          return [key, valueOrError];
+        }));
+  }
+}
+
+/**
+ * This is the minimum validation required to ensure no console errors.
+ * Invalid importData that passes validation will be processed with a
+ * best-attempt; e.g. if responses are missing 'relevance' values, then those
+ * cells will be left blank.
+ */
+function validateImportData(importData: OmniboxExport): boolean {
+  const EXPECTED_FORMAT = {
+    queryInputs: {},
+    displayInputs: {},
+    responsesHistory: [[{combinedResults: [], resultsByProvider: []}]],
+  };
+  const INVALID_MESSAGE = `Invalid import format; expected \n${
+      JSON.stringify(EXPECTED_FORMAT, null, 2)};\n`;
+
+  if (!importData) {
+    console.error(INVALID_MESSAGE + 'received non object.');
+    return false;
+  }
+
+  if (!importData.queryInputs || !importData.displayInputs) {
+    console.error(
+        INVALID_MESSAGE +
+        'import missing objects queryInputs and displayInputs.');
+    return false;
+  }
+
+  if (!Array.isArray(importData.responsesHistory)) {
+    console.error(INVALID_MESSAGE + 'import missing array responsesHistory.');
+    return false;
+  }
+
+  if (!importData.responsesHistory.every(Array.isArray)) {
+    console.error(INVALID_MESSAGE + 'responsesHistory contains non arrays.');
+    return false;
+  }
+
+  if (!importData.responsesHistory.every(
+      responses => responses.every(
+          ({combinedResults, resultsByProvider}) =>
+              Array.isArray(combinedResults) &&
+              Array.isArray(resultsByProvider)))) {
+    console.error(
+        INVALID_MESSAGE +
+        'responsesHistory items\' items missing combinedResults and ' +
+        'resultsByProvider arrays.');
+    return false;
+  }
+
+  return true;
+}
diff --git a/chrome/browser/resources/omnibox/omnibox_input.ts b/chrome/browser/resources/omnibox/omnibox_input.ts
index e597fd50..7c8cf02 100644
--- a/chrome/browser/resources/omnibox/omnibox_input.ts
+++ b/chrome/browser/resources/omnibox/omnibox_input.ts
@@ -4,7 +4,7 @@
 
 import {OmniboxElement} from './omnibox_element.js';
 
-interface QueryInputs {
+export interface QueryInputs {
   inputText: string;
   resetAutocompleteController: boolean;
   cursorLock: boolean;
@@ -16,7 +16,7 @@
   pageClassification: number;
 }
 
-interface DisplayInputs {
+export interface DisplayInputs {
   showIncompleteResults: boolean;
   showDetails: boolean;
   showAllProviders: boolean;
diff --git a/chrome/browser/resources/settings/languages_page/languages_page.html b/chrome/browser/resources/settings/languages_page/languages_page.html
index b783f67..00f01f67 100644
--- a/chrome/browser/resources/settings/languages_page/languages_page.html
+++ b/chrome/browser/resources/settings/languages_page/languages_page.html
@@ -178,7 +178,7 @@
 </div>
 <template is="dom-if" if="[[showAddLanguagesDialog_]]" restamp>
   <settings-add-languages-dialog languages="[[addLanguagesDialogLanguages_]]"
-      language-helper="{{languageHelper}}"
+      language-helper="[[languageHelper]]"
       on-languages-added="onLanguagesAdded_"
       on-close="onAddLanguagesDialogClose_">
   </settings-add-languages-dialog>
diff --git a/chrome/browser/resources/settings/languages_page/translate_page.html b/chrome/browser/resources/settings/languages_page/translate_page.html
index b116ddd..4df317b 100644
--- a/chrome/browser/resources/settings/languages_page/translate_page.html
+++ b/chrome/browser/resources/settings/languages_page/translate_page.html
@@ -77,14 +77,14 @@
 </iron-collapse>
 <template is="dom-if" if="[[showAddAlwaysTranslateDialog_]]" restamp>
   <settings-add-languages-dialog languages="[[addLanguagesDialogLanguages_]]"
-      language-helper="{{languageHelper}}" id="alwaysTranslateDialog"
+      language-helper="[[languageHelper]]" id="alwaysTranslateDialog"
       on-close="onAlwaysTranslateDialogClose_"
       on-languages-added="onAlwaysTranslateLanguagesAdded_">
   </settings-add-languages-dialog>
 </template>
 <template is="dom-if" if="[[showAddNeverTranslateDialog_]]" restamp>
   <settings-add-languages-dialog languages="[[addLanguagesDialogLanguages_]]"
-      language-helper="{{languageHelper}}" id="neverTranslateDialog"
+      language-helper="[[languageHelper]]" id="neverTranslateDialog"
       on-close="onNeverTranslateDialogClose_"
       on-languages-added="onNeverTranslateLanguagesAdded_">
   </settings-add-languages-dialog>
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegate.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegate.java
index ba1e50e..effac87 100644
--- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegate.java
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegate.java
@@ -31,11 +31,11 @@
      *                        entry point.
      * @param pageUrl URL for the page; passed in rather than derived from currentTab
      *     or WebContents's lastCommittedURL as it was used to construct UI in the caller.
-     * @param canonicalUrl Canonical URL for 'pageUrl.' May be empty.
+     * @param canonicalPageUrl Canonical URL for 'pageUrl.' May be empty.
      * @param isFollowing Whether the user is following the associated host in the feed.
      */
-    void launchCustomTab(
-            Context currentContext, GURL pageUrl, GURL canonicalUrl, boolean isFollowing);
+    void launchCustomTab(Tab tab, Context currentContext, GURL pageUrl, GURL canonicalPageUrl,
+            boolean isFollowing);
 
     /**
      * @return experiment-configured chip text.
@@ -48,4 +48,13 @@
      * @param Callback<String> callback returning the canonical URL, or empty.
      */
     void requestCanonicalUrl(Tab tab, Callback<GURL> url);
+
+    /**
+     * Returns a URL that can be loaded for the web-hosted piece of this feature.
+     *
+     * @param pageUrl the URL of the page with content.
+     * @param canonicalPageUrl canonical URL for |pageUrl|, may be an empty GURL.
+     * @param isFollowing whether the user is following |pageUrl|'s site on the feed.
+     */
+    String getUrlForWebFlow(GURL pageUrl, GURL canonicalPageUrl, boolean isFollowing);
 }
diff --git a/chrome/browser/share/share_features.cc b/chrome/browser/share/share_features.cc
index c5ba1be..9631794 100644
--- a/chrome/browser/share/share_features.cc
+++ b/chrome/browser/share/share_features.cc
@@ -20,6 +20,11 @@
     "ShareToGoogleCollections", base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kCormorant{"Cormorant", base::FEATURE_DISABLED_BY_DEFAULT};
 
+#if BUILDFLAG(IS_ANDROID)
+const base::Feature kCrowLaunchTab{"ShareCrowLaunchTab",
+                                   base::FEATURE_DISABLED_BY_DEFAULT};
+#endif  // BUILDFLAG(IS_ANDROID)
+
 #if !BUILDFLAG(IS_ANDROID)
 const base::Feature kDesktopSharePreview{"DesktopSharePreview",
                                          base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/browser/share/share_features.h b/chrome/browser/share/share_features.h
index 2fb4bbc2..968a6eb 100644
--- a/chrome/browser/share/share_features.h
+++ b/chrome/browser/share/share_features.h
@@ -19,6 +19,10 @@
 extern const base::Feature kShareToGoogleCollections;
 extern const base::Feature kCormorant;
 
+#if BUILDFLAG(IS_ANDROID)
+extern const base::Feature kCrowLaunchTab;
+#endif  // BUILDFLAG(IS_ANDROID)
+
 #if !BUILDFLAG(IS_ANDROID)
 extern const base::Feature kDesktopSharePreview;
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index c8980fd..3d3bf9c4 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2553,15 +2553,15 @@
       "webui/ash/add_supervision/add_supervision_ui.h",
       "webui/ash/add_supervision/confirm_signout_dialog.cc",
       "webui/ash/add_supervision/confirm_signout_dialog.h",
-      "webui/chromeos/arc_graphics_tracing/arc_graphics_tracing.h",
-      "webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.cc",
-      "webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.h",
-      "webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_ui.cc",
-      "webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_ui.h",
-      "webui/chromeos/arc_power_control/arc_power_control_handler.cc",
-      "webui/chromeos/arc_power_control/arc_power_control_handler.h",
-      "webui/chromeos/arc_power_control/arc_power_control_ui.cc",
-      "webui/chromeos/arc_power_control/arc_power_control_ui.h",
+      "webui/ash/arc_graphics_tracing/arc_graphics_tracing.h",
+      "webui/ash/arc_graphics_tracing/arc_graphics_tracing_handler.cc",
+      "webui/ash/arc_graphics_tracing/arc_graphics_tracing_handler.h",
+      "webui/ash/arc_graphics_tracing/arc_graphics_tracing_ui.cc",
+      "webui/ash/arc_graphics_tracing/arc_graphics_tracing_ui.h",
+      "webui/ash/arc_power_control/arc_power_control_handler.cc",
+      "webui/ash/arc_power_control/arc_power_control_handler.h",
+      "webui/ash/arc_power_control/arc_power_control_ui.cc",
+      "webui/ash/arc_power_control/arc_power_control_ui.h",
       "webui/chromeos/assistant_optin/assistant_optin_ui.cc",
       "webui/chromeos/assistant_optin/assistant_optin_ui.h",
       "webui/chromeos/assistant_optin/assistant_optin_utils.cc",
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
index cc547c5..9167201b 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
@@ -1242,7 +1242,12 @@
   base::Value* app_dict = update.Get();
   app_dict->GetDict().Set(kResizeLockState, static_cast<int32_t>(state));
 
-  NotifyAppStatesChanged(app_id);
+  // If the app is not "ready", we shouldn't fire the AppStatesChanged
+  // callbacks. Otherwise, it would cause a crash (See crbug.com/127660). When
+  // the app is changed to "ready", ArcAppListPrefs sends the notifications
+  // afterwards so it's fine not to fire it here.
+  if (app_info->ready)
+    NotifyAppStatesChanged(app_id);
 }
 
 bool ArcAppListPrefs::GetResizeLockNeedsConfirmation(
diff --git a/chrome/browser/ui/app_list/search/omnibox_provider.h b/chrome/browser/ui/app_list/search/omnibox_provider.h
index 20a50a57..40ae83c 100644
--- a/chrome/browser/ui/app_list/search/omnibox_provider.h
+++ b/chrome/browser/ui/app_list/search/omnibox_provider.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_UI_APP_LIST_SEARCH_OMNIBOX_PROVIDER_H_
 #define CHROME_BROWSER_UI_APP_LIST_SEARCH_OMNIBOX_PROVIDER_H_
 
+#include <algorithm>
 #include <memory>
 
 #include "base/time/time.h"
@@ -41,11 +42,10 @@
   // Populates result list from AutocompleteResult.
   void PopulateFromACResult(const AutocompleteResult& result);
 
-  // Change the query_finished_ flag for testing purpose.
-  // TODO(crbug.com/1356409): Replace this function with formal testing
-  // procedures.
-  void set_query_finished_for_test(bool query_finished) {
-    query_finished_ = query_finished;
+  // Change the controller_ for testing purpose.
+  void set_controller_for_test(
+      std::unique_ptr<AutocompleteController> controller) {
+    controller_ = std::move(controller);
   }
 
  private:
diff --git a/chrome/browser/ui/app_list/search/omnibox_provider_unittest.cc b/chrome/browser/ui/app_list/search/omnibox_provider_unittest.cc
index baedad3..b4b345bb4 100644
--- a/chrome/browser/ui/app_list/search/omnibox_provider_unittest.cc
+++ b/chrome/browser/ui/app_list/search/omnibox_provider_unittest.cc
@@ -19,6 +19,8 @@
 #include "chrome/common/chrome_constants.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile_manager.h"
+#include "components/omnibox/browser/autocomplete_controller.h"
+#include "components/omnibox/browser/fake_autocomplete_provider_client.h"
 #include "components/omnibox/browser/suggestion_answer.h"
 #include "components/variations/scoped_variations_ids_provider.h"
 #include "components/variations/variations_ids_provider.h"
@@ -75,10 +77,24 @@
   return result;
 }
 
+// A mock class for the AutoCompleteController.
+class MockAutoCompleteController : public AutocompleteController {
+ public:
+  MockAutoCompleteController()
+      : AutocompleteController(
+            std::make_unique<FakeAutocompleteProviderClient>(),
+            0) {}
+  MockAutoCompleteController(const MockAutoCompleteController&) = delete;
+  MockAutoCompleteController& operator=(const MockAutoCompleteController&) =
+      delete;
+  ~MockAutoCompleteController() override = default;
+
+  // Do nothing when it is called by OmniboxProvider.
+  void Start(const AutocompleteInput& input) override {}
+};
+
 }  // namespace
 
-// http://crbug.com/1357483
-#define OmniboxProviderTest DISABLED_OmniboxProviderTest
 class OmniboxProviderTest : public testing::Test {
  public:
   OmniboxProviderTest() {
@@ -110,6 +126,10 @@
         std::make_unique<OmniboxProvider>(profile_, list_controller_.get());
     provider_->set_controller(search_controller_.get());
 
+    std::unique_ptr<AutocompleteController> controller =
+        std::make_unique<MockAutoCompleteController>();
+    provider_->set_controller_for_test(std::move(controller));
+
     base::RunLoop().RunUntilIdle();
   }
 
@@ -123,7 +143,6 @@
   }
 
   void ProduceResults(const AutocompleteResult& results) {
-    provider_->set_query_finished_for_test(false);
     provider_->PopulateFromACResult(std::move(results));
     base::RunLoop().RunUntilIdle();
   }
@@ -188,6 +207,8 @@
   ProduceResults(std::move(result));
 
   // Then produce another.
+  StartSearch(u"query");
+
   to_produce.clear();
   AutocompleteResult new_result;
   to_produce.emplace_back(NewOpenTabResult("https://example.com/open_tab_2"));
diff --git a/chrome/browser/ui/ash/arc_open_url_delegate_impl.cc b/chrome/browser/ui/ash/arc_open_url_delegate_impl.cc
index 72a4237..3302a36 100644
--- a/chrome/browser/ui/ash/arc_open_url_delegate_impl.cc
+++ b/chrome/browser/ui/ash/arc_open_url_delegate_impl.cc
@@ -164,7 +164,8 @@
     return external_file_url;
   }
 
-  fusebox::Moniker moniker = fusebox_server->CreateMoniker(fs_url);
+  constexpr bool kReadOnly = true;
+  fusebox::Moniker moniker = fusebox_server->CreateMoniker(fs_url, kReadOnly);
 
   // Keep the Moniker alive for the same time as a file shared through the Web
   // Share API. We could be cleverer about scheduling the clean up, but "destroy
diff --git a/chrome/browser/ui/ash/shelf/app_service/web_app_shelf_browsertest.cc b/chrome/browser/ui/ash/shelf/app_service/web_app_shelf_browsertest.cc
new file mode 100644
index 0000000..395a386
--- /dev/null
+++ b/chrome/browser/ui/ash/shelf/app_service/web_app_shelf_browsertest.cc
@@ -0,0 +1,178 @@
+// Copyright 2022 The Chromium Authors.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/public/cpp/shelf_item.h"
+#include "ash/public/cpp/shelf_model.h"
+#include "ash/public/cpp/shelf_types.h"
+#include "ash/root_window_controller.h"
+#include "ash/shelf/shelf.h"
+#include "ash/shelf/shelf_app_button.h"
+#include "ash/shelf/shelf_view.h"
+#include "ash/shell.h"
+#include "chrome/browser/apps/app_service/app_launch_params.h"
+#include "chrome/browser/apps/app_service/app_service_proxy.h"
+#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
+#include "chrome/browser/ui/ash/shelf/chrome_shelf_controller.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_navigator_params.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/web_applications/test/app_registration_waiter.h"
+#include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
+#include "chrome/browser/web_applications/user_display_mode.h"
+#include "chrome/browser/web_applications/web_app_install_info.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/app_constants/constants.h"
+#include "components/services/app_service/public/cpp/app_launch_util.h"
+#include "content/public/test/browser_test.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "ui/base/window_open_disposition.h"
+#include "ui/display/screen.h"
+#include "url/gurl.h"
+
+class WebAppShelfBrowserTest : public InProcessBrowserTest {
+ public:
+  web_app::AppId InstallTestWebApp(const GURL& start_url,
+                                   web_app::UserDisplayMode user_display_mode) {
+    auto web_app_info = std::make_unique<WebAppInstallInfo>();
+    web_app_info->start_url = start_url;
+    web_app_info->user_display_mode = user_display_mode;
+    const web_app::AppId app_id =
+        web_app::test::InstallWebApp(profile(), std::move(web_app_info));
+    web_app::AppRegistrationWaiter(profile(), app_id).Await();
+    return app_id;
+  }
+
+  void PinToShelf(const web_app::AppId& app_id) {
+    ui_test_utils::BrowserChangeObserver observer(
+        nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
+    auto* const proxy = apps::AppServiceProxyFactory::GetForProfile(profile());
+    proxy->LaunchAppWithParams(apps::AppLaunchParams(
+        app_id, apps::LaunchContainer::kLaunchContainerWindow,
+        WindowOpenDisposition::NEW_WINDOW, apps::LaunchSource::kFromOmnibox));
+    Browser* app_browser = observer.Wait();
+    ash::ShelfModel::Get()->PinExistingItemWithID(app_id);
+    app_browser->window()->Close();
+  }
+
+  Profile* profile() { return browser()->profile(); }
+};
+
+IN_PROC_BROWSER_TEST_F(WebAppShelfBrowserTest, SwitchingBetweenApps) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  const GURL start_a =
+      embedded_test_server()->GetURL("/banners/scope_a/page_1.html");
+  const GURL start_b =
+      embedded_test_server()->GetURL("/banners/scope_b/scope_b.html");
+  const GURL start_c = embedded_test_server()->GetURL("/web_apps/basic.html");
+  // Outside the scope of any web app:
+  const GURL start_d = embedded_test_server()->GetURL("/simple.html");
+
+  const web_app::AppId app_a =
+      InstallTestWebApp(start_a, web_app::UserDisplayMode::kBrowser);
+  const web_app::AppId app_b =
+      InstallTestWebApp(start_b, web_app::UserDisplayMode::kBrowser);
+  const web_app::AppId app_c =
+      InstallTestWebApp(start_c, web_app::UserDisplayMode::kStandalone);
+
+  auto* const proxy = apps::AppServiceProxyFactory::GetForProfile(profile());
+
+  // Web apps only appear in Shelf when pinned or running in app windows.
+  // We don't need to pin |app_c| as it will be running in an app window.
+  PinToShelf(app_a);
+  PinToShelf(app_b);
+
+  content::WebContents* contents_a;
+  {
+    ui_test_utils::TabAddedWaiter waiter(browser());
+    proxy->Launch(app_a,
+                  /*event_flags=*/0, apps::LaunchSource::kFromAppListGrid);
+    waiter.Wait();
+    contents_a = browser()->tab_strip_model()->GetActiveWebContents();
+  }
+
+  content::WebContents* contents_b;
+  {
+    ui_test_utils::TabAddedWaiter waiter(browser());
+    proxy->Launch(app_b,
+                  /*event_flags=*/0, apps::LaunchSource::kFromAppListGrid);
+    waiter.Wait();
+    contents_b = browser()->tab_strip_model()->GetActiveWebContents();
+  }
+
+  Browser* browser_c;
+  content::WebContents* contents_c;
+  {
+    ui_test_utils::BrowserChangeObserver observer(
+        nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
+    ui_test_utils::AllBrowserTabAddedWaiter waiter;
+    proxy->Launch(app_c,
+                  /*event_flags=*/0, apps::LaunchSource::kFromAppListGrid);
+    browser_c = observer.Wait();
+    contents_c = waiter.Wait();
+  }
+
+  content::WebContents* contents_d;
+  {
+    ui_test_utils::TabAddedWaiter waiter(browser());
+    NavigateParams params(browser(), start_d, ui::PAGE_TRANSITION_LINK);
+    params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
+    ui_test_utils::NavigateToURL(&params);
+    waiter.Wait();
+    contents_d = browser()->tab_strip_model()->GetActiveWebContents();
+  }
+
+  // The Shelf model contains 3 web apps, and the Chrome browser.
+  auto* const shelf_model = ash::ShelfModel::Get();
+  EXPECT_EQ(shelf_model->item_count(), 4);
+  for (const ash::ShelfItem& item : shelf_model->items()) {
+    EXPECT_EQ(item.status, ash::STATUS_RUNNING);
+  }
+
+  ash::RootWindowController* const controller =
+      ash::Shell::GetRootWindowControllerWithDisplayId(
+          display::Screen::GetScreen()->GetPrimaryDisplay().id());
+  ash::ShelfView* const shelf_view =
+      controller->shelf()->GetShelfViewForTesting();
+  const ash::ShelfAppButton* const button_a =
+      shelf_view->GetShelfAppButton(ash::ShelfID(app_a));
+  const ash::ShelfAppButton* const button_b =
+      shelf_view->GetShelfAppButton(ash::ShelfID(app_b));
+  const ash::ShelfAppButton* const button_c =
+      shelf_view->GetShelfAppButton(ash::ShelfID(app_c));
+  const ash::ShelfAppButton* const button_chrome =
+      shelf_view->GetShelfAppButton(ash::ShelfID(app_constants::kChromeAppId));
+
+  browser()->ActivateContents(contents_a);
+  EXPECT_EQ(button_a->state(), ash::ShelfAppButton::STATE_ACTIVE);
+  EXPECT_EQ(button_b->state(), ash::ShelfAppButton::STATE_RUNNING);
+  EXPECT_EQ(button_c->state(), ash::ShelfAppButton::STATE_RUNNING);
+  EXPECT_EQ(button_chrome->state(), ash::ShelfAppButton::STATE_RUNNING);
+
+  browser()->ActivateContents(contents_b);
+  EXPECT_EQ(button_a->state(), ash::ShelfAppButton::STATE_RUNNING);
+  EXPECT_EQ(button_b->state(), ash::ShelfAppButton::STATE_ACTIVE);
+  EXPECT_EQ(button_c->state(), ash::ShelfAppButton::STATE_RUNNING);
+  EXPECT_EQ(button_chrome->state(), ash::ShelfAppButton::STATE_RUNNING);
+
+  browser_c->ActivateContents(contents_c);
+  EXPECT_EQ(button_a->state(), ash::ShelfAppButton::STATE_RUNNING);
+  EXPECT_EQ(button_b->state(), ash::ShelfAppButton::STATE_RUNNING);
+  EXPECT_EQ(button_c->state(), ash::ShelfAppButton::STATE_ACTIVE);
+  EXPECT_EQ(button_chrome->state(), ash::ShelfAppButton::STATE_RUNNING);
+
+  browser()->ActivateContents(contents_d);
+  EXPECT_EQ(button_a->state(), ash::ShelfAppButton::STATE_RUNNING);
+  EXPECT_EQ(button_b->state(), ash::ShelfAppButton::STATE_RUNNING);
+  EXPECT_EQ(button_c->state(), ash::ShelfAppButton::STATE_RUNNING);
+  EXPECT_EQ(button_chrome->state(), ash::ShelfAppButton::STATE_ACTIVE);
+
+  browser()->window()->Close();
+  EXPECT_EQ(button_a->state(), ash::ShelfAppButton::STATE_NORMAL);
+  EXPECT_EQ(button_b->state(), ash::ShelfAppButton::STATE_NORMAL);
+  EXPECT_EQ(button_c->state(), ash::ShelfAppButton::STATE_ACTIVE);
+  EXPECT_EQ(button_chrome->state(), ash::ShelfAppButton::STATE_RUNNING);
+}
diff --git a/chrome/browser/ui/views/bubble_anchor_util_views.cc b/chrome/browser/ui/views/bubble_anchor_util_views.cc
index b59e2b0..35001ec 100644
--- a/chrome/browser/ui/views/bubble_anchor_util_views.cc
+++ b/chrome/browser/ui/views/bubble_anchor_util_views.cc
@@ -7,6 +7,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/ui/views/frame/app_menu_button.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "chrome/browser/ui/views/location_bar/location_icon_view.h"
 #include "chrome/browser/ui/views/permissions/permission_chip.h"
@@ -27,6 +28,13 @@
             browser_view->GetLocationBarView()->location_icon_view(),
             views::BubbleBorder::TOP_LEFT};
 
+  if (anchor == kLocationBar && browser_view->GetIsPictureInPictureType()) {
+    auto* frame_view = static_cast<PictureInPictureBrowserFrameView*>(
+        browser_view->frame()->GetFrameView());
+    return {frame_view->GetLocationIconView(),
+            frame_view->GetLocationIconView(), views::BubbleBorder::TOP_LEFT};
+  }
+
   if (anchor == kCustomTabBar && browser_view->toolbar()->custom_tab_bar())
     return {browser_view->toolbar()->custom_tab_bar(),
             browser_view->toolbar()->custom_tab_bar()->location_icon_view(),
diff --git a/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc b/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc
index 2c3c3bc4..88a5724 100644
--- a/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc
@@ -108,7 +108,9 @@
   back_to_tab_button_ = controls_container_view_->AddChildView(
       std::make_unique<BackToTabButton>(base::BindRepeating(
           [](PictureInPictureBrowserFrameView* frame_view) {
-            // TODO(https://crbug.com/1346734): Implement functionality.
+            // TODO(https://crbug.com/1346734): Focus the original tab too.
+            PictureInPictureWindowManager::GetInstance()
+                ->ExitPictureInPicture();
           },
           base::Unretained(this))));
 
@@ -116,8 +118,8 @@
   close_image_button_ = controls_container_view_->AddChildView(
       std::make_unique<CloseImageButton>(base::BindRepeating(
           [](PictureInPictureBrowserFrameView* frame_view) {
-            frame_view->frame()->CloseWithReason(
-                views::Widget::ClosedReason::kCloseButtonClicked);
+            PictureInPictureWindowManager::GetInstance()
+                ->ExitPictureInPicture();
           },
           base::Unretained(this))));
 }
@@ -314,5 +316,9 @@
   return close_image_button_->GetMirroredBounds();
 }
 
+LocationIconView* PictureInPictureBrowserFrameView::GetLocationIconView() {
+  return location_icon_view_;
+}
+
 BEGIN_METADATA(PictureInPictureBrowserFrameView, BrowserNonClientFrameView)
 END_METADATA
diff --git a/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.h b/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.h
index b6c6ac1d9..dfd4529 100644
--- a/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.h
+++ b/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.h
@@ -79,6 +79,8 @@
   gfx::Rect GetBackToTabControlsBounds() const;
   gfx::Rect GetCloseControlsBounds() const;
 
+  LocationIconView* GetLocationIconView();
+
  private:
   // A model required to use LocationIconView.
   std::unique_ptr<LocationBarModel> location_bar_model_;
diff --git a/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/OWNERS b/chrome/browser/ui/webui/ash/arc_graphics_tracing/OWNERS
similarity index 100%
rename from chrome/browser/ui/webui/chromeos/arc_graphics_tracing/OWNERS
rename to chrome/browser/ui/webui/ash/arc_graphics_tracing/OWNERS
diff --git a/chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing.h b/chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing.h
new file mode 100644
index 0000000..d661c44
--- /dev/null
+++ b/chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing.h
@@ -0,0 +1,19 @@
+// 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 CHROME_BROWSER_UI_WEBUI_ASH_ARC_GRAPHICS_TRACING_ARC_GRAPHICS_TRACING_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_ARC_GRAPHICS_TRACING_ARC_GRAPHICS_TRACING_H_
+
+namespace ash {
+
+enum class ArcGraphicsTracingMode {
+  // Full tracing mode.
+  kFull,
+  // Overview tracing mode with ability to compare different runs.
+  kOverview,
+};
+
+}  // namespace ash
+
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_ARC_GRAPHICS_TRACING_ARC_GRAPHICS_TRACING_H_
diff --git a/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.cc b/chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_handler.cc
similarity index 99%
rename from chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.cc
rename to chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_handler.cc
index 4ae91e3b..8e5aa41 100644
--- a/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.cc
+++ b/chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_handler.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 "chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.h"
+#include "chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_handler.h"
 
 #include <map>
 
@@ -49,7 +49,7 @@
 #include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/image/image_skia_rep.h"
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 
@@ -651,4 +651,4 @@
                      weak_ptr_factory_.GetWeakPtr()));
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.h b/chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_handler.h
similarity index 91%
rename from chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.h
rename to chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_handler.h
index cfc6bea4..2942bc7 100644
--- a/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.h
+++ b/chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_handler.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 CHROME_BROWSER_UI_WEBUI_CHROMEOS_ARC_GRAPHICS_TRACING_ARC_GRAPHICS_TRACING_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_ARC_GRAPHICS_TRACING_ARC_GRAPHICS_TRACING_HANDLER_H_
+#ifndef CHROME_BROWSER_UI_WEBUI_ASH_ARC_GRAPHICS_TRACING_ARC_GRAPHICS_TRACING_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_ARC_GRAPHICS_TRACING_ARC_GRAPHICS_TRACING_HANDLER_H_
 
 #include <memory>
 #include <string>
@@ -14,7 +14,7 @@
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "base/values.h"
-#include "chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing.h"
+#include "chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing.h"
 #include "components/exo/surface_observer.h"
 #include "content/public/browser/web_ui_message_handler.h"
 #include "ui/aura/window_observer.h"
@@ -37,7 +37,7 @@
 class WMHelper;
 }  // namespace exo
 
-namespace chromeos {
+namespace ash {
 
 class ArcGraphicsTracingHandler : public content::WebUIMessageHandler,
                                   public wm::ActivationChangeObserver,
@@ -151,6 +151,6 @@
   base::WeakPtrFactory<ArcGraphicsTracingHandler> weak_ptr_factory_{this};
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
-#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_ARC_GRAPHICS_TRACING_ARC_GRAPHICS_TRACING_HANDLER_H_
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_ARC_GRAPHICS_TRACING_ARC_GRAPHICS_TRACING_HANDLER_H_
diff --git a/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler_unittest.cc b/chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_handler_unittest.cc
similarity index 92%
rename from chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler_unittest.cc
rename to chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_handler_unittest.cc
index 241204e..9b4db69 100644
--- a/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler_unittest.cc
+++ b/chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_handler_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.h"
+#include "chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_handler.h"
 #include "base/files/file_path.h"
 #include "base/time/time_override.h"
 #include "chrome/browser/ash/file_manager/path_util.h"
@@ -10,7 +10,7 @@
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 
@@ -52,4 +52,4 @@
 
 }  // namespace
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_ui.cc b/chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_ui.cc
similarity index 94%
rename from chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_ui.cc
rename to chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_ui.cc
index d0ca260..4ade81874 100644
--- a/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_ui.cc
+++ b/chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_ui.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 "chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_ui.h"
+#include "chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_ui.h"
 
 #include <memory>
 #include <string>
@@ -10,7 +10,7 @@
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler.h"
+#include "chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_handler.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/browser_resources.h"
 #include "content/public/browser/web_ui.h"
@@ -75,7 +75,7 @@
 
 }  // anonymous namespace
 
-namespace chromeos {
+namespace ash {
 
 template <>
 ArcGraphicsTracingUI<ArcGraphicsTracingMode::kFull>::ArcGraphicsTracingUI(
@@ -97,4 +97,4 @@
                                 CreateOverviewDataSource());
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_ui.h b/chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_ui.h
similarity index 60%
rename from chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_ui.h
rename to chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_ui.h
index f9fa3f7..52db39c 100644
--- a/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_ui.h
+++ b/chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_ui.h
@@ -2,17 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_WEBUI_CHROMEOS_ARC_GRAPHICS_TRACING_ARC_GRAPHICS_TRACING_UI_H_
-#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_ARC_GRAPHICS_TRACING_ARC_GRAPHICS_TRACING_UI_H_
+#ifndef CHROME_BROWSER_UI_WEBUI_ASH_ARC_GRAPHICS_TRACING_ARC_GRAPHICS_TRACING_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_ARC_GRAPHICS_TRACING_ARC_GRAPHICS_TRACING_UI_H_
 
-#include "chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing.h"
+#include "chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing.h"
 #include "content/public/browser/web_ui_controller.h"
 
 namespace content {
 class WebUI;
 }
 
-namespace chromeos {
+namespace ash {
 
 // WebUI controller for arc graphics/overview tracing.
 template <ArcGraphicsTracingMode mode>
@@ -24,6 +24,6 @@
   ArcGraphicsTracingUI& operator=(const ArcGraphicsTracingUI&) = delete;
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
-#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_ARC_GRAPHICS_TRACING_ARC_GRAPHICS_TRACING_UI_H_
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_ARC_GRAPHICS_TRACING_ARC_GRAPHICS_TRACING_UI_H_
diff --git a/chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_handler.cc b/chrome/browser/ui/webui/ash/arc_power_control/arc_power_control_handler.cc
similarity index 98%
rename from chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_handler.cc
rename to chrome/browser/ui/webui/ash/arc_power_control/arc_power_control_handler.cc
index f9b580af..e0daa1f 100644
--- a/chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_handler.cc
+++ b/chrome/browser/ui/webui/ash/arc_power_control/arc_power_control_handler.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 "chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_handler.h"
+#include "chrome/browser/ui/webui/ash/arc_power_control/arc_power_control_handler.h"
 
 #include "ash/components/arc/mojom/power.mojom.h"
 #include "ash/components/arc/session/arc_bridge_service.h"
@@ -21,7 +21,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 
@@ -377,4 +377,4 @@
                          base::Value(status));
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_handler.h b/chrome/browser/ui/webui/ash/arc_power_control/arc_power_control_handler.h
similarity index 90%
rename from chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_handler.h
rename to chrome/browser/ui/webui/ash/arc_power_control/arc_power_control_handler.h
index 2068e28b..f92e9d5 100644
--- a/chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_handler.h
+++ b/chrome/browser/ui/webui/ash/arc_power_control/arc_power_control_handler.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 CHROME_BROWSER_UI_WEBUI_CHROMEOS_ARC_POWER_CONTROL_ARC_POWER_CONTROL_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_ARC_POWER_CONTROL_ARC_POWER_CONTROL_HANDLER_H_
+#ifndef CHROME_BROWSER_UI_WEBUI_ASH_ARC_POWER_CONTROL_ARC_POWER_CONTROL_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_ARC_POWER_CONTROL_ARC_POWER_CONTROL_HANDLER_H_
 
 #include <memory>
 #include <string>
@@ -26,7 +26,7 @@
 class ArcSystemStatCollector;
 }  // namespace arc
 
-namespace chromeos {
+namespace ash {
 
 class ArcPowerControlHandler : public content::WebUIMessageHandler,
                                public arc::ArcPowerBridge::Observer,
@@ -92,6 +92,6 @@
   base::WeakPtrFactory<ArcPowerControlHandler> weak_ptr_factory_{this};
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
-#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_ARC_POWER_CONTROL_ARC_POWER_CONTROL_HANDLER_H_
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_ARC_POWER_CONTROL_ARC_POWER_CONTROL_HANDLER_H_
diff --git a/chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_ui.cc b/chrome/browser/ui/webui/ash/arc_power_control/arc_power_control_ui.cc
similarity index 91%
rename from chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_ui.cc
rename to chrome/browser/ui/webui/ash/arc_power_control/arc_power_control_ui.cc
index 151bffd..8382ae6 100644
--- a/chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_ui.cc
+++ b/chrome/browser/ui/webui/ash/arc_power_control/arc_power_control_ui.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 "chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_ui.h"
+#include "chrome/browser/ui/webui/ash/arc_power_control/arc_power_control_ui.h"
 
 #include <memory>
 #include <string>
@@ -10,7 +10,7 @@
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_handler.h"
+#include "chrome/browser/ui/webui/ash/arc_power_control/arc_power_control_handler.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/browser_resources.h"
 #include "content/public/browser/web_ui.h"
@@ -51,7 +51,7 @@
 
 }  // anonymous namespace
 
-namespace chromeos {
+namespace ash {
 
 ArcPowerControlUI::ArcPowerControlUI(content::WebUI* web_ui)
     : WebUIController(web_ui) {
@@ -60,4 +60,4 @@
                                 CreatePowerControlDataSource());
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_ui.h b/chrome/browser/ui/webui/ash/arc_power_control/arc_power_control_ui.h
similarity index 65%
rename from chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_ui.h
rename to chrome/browser/ui/webui/ash/arc_power_control/arc_power_control_ui.h
index a2d18e2..35a51422 100644
--- a/chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_ui.h
+++ b/chrome/browser/ui/webui/ash/arc_power_control/arc_power_control_ui.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 CHROME_BROWSER_UI_WEBUI_CHROMEOS_ARC_POWER_CONTROL_ARC_POWER_CONTROL_UI_H_
-#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_ARC_POWER_CONTROL_ARC_POWER_CONTROL_UI_H_
+#ifndef CHROME_BROWSER_UI_WEBUI_ASH_ARC_POWER_CONTROL_ARC_POWER_CONTROL_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_ARC_POWER_CONTROL_ARC_POWER_CONTROL_UI_H_
 
 #include "content/public/browser/web_ui_controller.h"
 
@@ -11,7 +11,7 @@
 class WebUI;
 }
 
-namespace chromeos {
+namespace ash {
 
 // WebUI controller for ARC power control.
 class ArcPowerControlUI : public content::WebUIController {
@@ -23,6 +23,6 @@
   ArcPowerControlUI& operator=(ArcPowerControlUI const&) = delete;
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
-#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_ARC_POWER_CONTROL_ARC_POWER_CONTROL_UI_H_
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_ARC_POWER_CONTROL_ARC_POWER_CONTROL_UI_H_
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index 04426ca..63869ad 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -249,8 +249,8 @@
 #include "chrome/browser/ui/webui/ash/account_manager/account_manager_error_ui.h"
 #include "chrome/browser/ui/webui/ash/account_manager/account_migration_welcome_ui.h"
 #include "chrome/browser/ui/webui/ash/add_supervision/add_supervision_ui.h"
-#include "chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_ui.h"
-#include "chrome/browser/ui/webui/chromeos/arc_power_control/arc_power_control_ui.h"
+#include "chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_ui.h"
+#include "chrome/browser/ui/webui/ash/arc_power_control/arc_power_control_ui.h"
 #include "chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.h"
 #include "chrome/browser/ui/webui/chromeos/audio/audio_ui.h"
 #include "chrome/browser/ui/webui/chromeos/bluetooth_pairing_dialog.h"
@@ -1086,15 +1086,15 @@
     return &NewWebUI<NearbyInternalsUI>;
   if (arc::IsArcAllowedForProfile(profile)) {
     if (url.host_piece() == chrome::kChromeUIArcGraphicsTracingHost) {
-      return &NewWebUI<chromeos::ArcGraphicsTracingUI<
-          chromeos::ArcGraphicsTracingMode::kFull>>;
+      return &NewWebUI<
+          ash::ArcGraphicsTracingUI<ash::ArcGraphicsTracingMode::kFull>>;
     }
     if (url.host_piece() == chrome::kChromeUIArcOverviewTracingHost) {
-      return &NewWebUI<chromeos::ArcGraphicsTracingUI<
-          chromeos::ArcGraphicsTracingMode::kOverview>>;
+      return &NewWebUI<
+          ash::ArcGraphicsTracingUI<ash::ArcGraphicsTracingMode::kOverview>>;
     }
     if (url.host_piece() == chrome::kChromeUIArcPowerControlHost) {
-      return &NewWebUI<chromeos::ArcPowerControlUI>;
+      return &NewWebUI<ash::ArcPowerControlUI>;
     }
   }
   if (url.host_piece() == chrome::kChromeUIEmojiPickerHost) {
diff --git a/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing.h b/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing.h
deleted file mode 100644
index 3f51e96..0000000
--- a/chrome/browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing.h
+++ /dev/null
@@ -1,19 +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 CHROME_BROWSER_UI_WEBUI_CHROMEOS_ARC_GRAPHICS_TRACING_ARC_GRAPHICS_TRACING_H_
-#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_ARC_GRAPHICS_TRACING_ARC_GRAPHICS_TRACING_H_
-
-namespace chromeos {
-
-enum class ArcGraphicsTracingMode {
-  // Full tracing mode.
-  kFull,
-  // Overview tracing mode with ability to compare different runs.
-  kOverview,
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_ARC_GRAPHICS_TRACING_ARC_GRAPHICS_TRACING_H_
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index f205759..d085dc6 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1661968802-7fabd97a725c06d3cc8b8c2be552d9fd363a9701.profdata
+chrome-linux-main-1661990255-a6f8a3a3876f160dae6a36c550300e8c582cc55d.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 2afc43e..a9de2dd 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1661968802-123a4a0ae7178ec59a25ea651ad83d4d0da7e32b.profdata
+chrome-mac-arm-main-1661990255-cbf0e7ac0633ed4442db30af30b81a945766e24d.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index a37c4741..2f21a46e 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1661968802-868b197e7c2389c2ce8042456c87de363ddad15a.profdata
+chrome-mac-main-1661990255-3afc45d42fd3f07d113492600a0ac324bf419efe.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index c84f02d..492bf678 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1661968802-bca74dcdaa153b05426f872862487fc43df1a352.profdata
+chrome-win32-main-1661990255-791bf470576c4b920bb985f881222f7144c94148.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 526e891..410898a 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1661978644-881d44b986ef9257013ccc11b116f332aab5d147.profdata
+chrome-win64-main-1661990255-176dcf7eaca6cf768604447c442829d62c508d25.profdata
diff --git a/chrome/services/media_gallery_util/media_parser_android_unittest.cc b/chrome/services/media_gallery_util/media_parser_android_unittest.cc
index 41940ca..5cb92263 100644
--- a/chrome/services/media_gallery_util/media_parser_android_unittest.cc
+++ b/chrome/services/media_gallery_util/media_parser_android_unittest.cc
@@ -155,7 +155,7 @@
   EXPECT_TRUE(frame->IsMappable());
   EXPECT_FALSE(frame->HasTextures());
   EXPECT_EQ(frame->storage_type(),
-            media::VideoFrame::StorageType::STORAGE_MOJO_SHARED_BUFFER);
+            media::VideoFrame::StorageType::STORAGE_OWNED_MEMORY);
 }
 
 // Test to verify a decoded video frame can be extracted for vp8 codec with
@@ -173,7 +173,7 @@
   EXPECT_TRUE(frame->IsMappable());
   EXPECT_FALSE(frame->HasTextures());
   EXPECT_EQ(frame->storage_type(),
-            media::VideoFrame::StorageType::STORAGE_MOJO_SHARED_BUFFER);
+            media::VideoFrame::StorageType::STORAGE_OWNED_MEMORY);
 }
 
 // Test to verify frame extraction will fail on invalid video file.
diff --git a/chrome/services/media_gallery_util/video_thumbnail_parser.cc b/chrome/services/media_gallery_util/video_thumbnail_parser.cc
index ded82110..8039ca9a 100644
--- a/chrome/services/media_gallery_util/video_thumbnail_parser.cc
+++ b/chrome/services/media_gallery_util/video_thumbnail_parser.cc
@@ -17,7 +17,6 @@
 #include "media/filters/android/video_frame_extractor.h"
 #include "media/filters/vpx_video_decoder.h"
 #include "media/media_buildflags.h"
-#include "media/mojo/common/mojo_shared_buffer_video_frame.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace {
@@ -38,8 +37,7 @@
 
   std::move(video_frame_callback)
       .Run(chrome::mojom::ExtractVideoFrameResult::New(
-          chrome::mojom::VideoFrameData::NewDecodedFrame(
-              media::MojoSharedBufferVideoFrame::CreateFromYUVFrame(*frame)),
+          chrome::mojom::VideoFrameData::NewDecodedFrame(std::move(frame)),
           config));
 }
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index a39dd802..78e4e71 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3958,6 +3958,7 @@
         "../browser/ui/ash/sharesheet/sharesheet_bubble_view_browsertest.cc",
         "../browser/ui/ash/shelf/app_service/app_service_app_window_browsertest.cc",
         "../browser/ui/ash/shelf/app_service/app_service_shelf_context_menu_browsertest.cc",
+        "../browser/ui/ash/shelf/app_service/web_app_shelf_browsertest.cc",
         "../browser/ui/ash/shelf/app_shortcut_shelf_item_controller_browsertest.cc",
         "../browser/ui/ash/shelf/arc_app_shelf_browsertest.cc",
         "../browser/ui/ash/shelf/browser_app_shelf_controller_browsertest.cc",
@@ -7345,7 +7346,7 @@
       "../browser/ui/quick_answers/ui/quick_answers_view_unittest.cc",
       "../browser/ui/views/crostini/crostini_app_restart_dialog_unittest.cc",
       "../browser/ui/webui/ash/add_supervision/add_supervision_handler_utils_unittest.cc",
-      "../browser/ui/webui/chromeos/arc_graphics_tracing/arc_graphics_tracing_handler_unittest.cc",
+      "../browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_handler_unittest.cc",
       "../browser/ui/webui/chromeos/edu_account_login_handler_unittest.cc",
       "../browser/ui/webui/chromeos/login/fake_update_required_screen_handler.cc",
       "../browser/ui/webui/chromeos/login/fake_update_required_screen_handler.h",
diff --git a/chrome/test/data/chromeos/file_manager/old_file.trashinfo b/chrome/test/data/chromeos/file_manager/old_file.trashinfo
new file mode 100644
index 0000000..f060f32fd
--- /dev/null
+++ b/chrome/test/data/chromeos/file_manager/old_file.trashinfo
@@ -0,0 +1,3 @@
+[Trash Info]
+Path=/foo.txt
+DeletionDate=2020-08-31T03:34:22.978Z
diff --git a/chrome/test/data/extensions/api_test/debugger_create_target_to_untrusted_webui/background.js b/chrome/test/data/extensions/api_test/debugger_create_target_to_untrusted_webui/background.js
new file mode 100644
index 0000000..1052724
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/debugger_create_target_to_untrusted_webui/background.js
@@ -0,0 +1,24 @@
+// Copyright 2022 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.
+
+const protocolVersion = '1.3';
+
+chrome.test.runTests([async function testCreateTargetToUntrustedWebUIUrl() {
+  const {openTab} = await import('/_test_resources/test_util/tabs_util.js');
+  const tab = await openTab('about:blank');
+  const debuggee = {tabId: tab.id};
+  await new Promise(
+      resolve => chrome.debugger.attach(debuggee, protocolVersion, resolve));
+
+  await new Promise(
+      resolve => chrome.debugger.sendCommand(
+          debuggee, 'Target.createTarget', {url: 'chrome-untrusted://terminal'},
+          resolve));
+  chrome.test.assertLastError(JSON.stringify({
+    code: -32000,
+    message: 'Refusing to create a target with the specified URL'
+  }));
+
+  chrome.test.succeed();
+}]);
diff --git a/chrome/test/data/extensions/api_test/debugger_create_target_to_untrusted_webui/manifest.json b/chrome/test/data/extensions/api_test/debugger_create_target_to_untrusted_webui/manifest.json
new file mode 100644
index 0000000..92192669
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/debugger_create_target_to_untrusted_webui/manifest.json
@@ -0,0 +1,11 @@
+{
+  "name": "Debugger API test for CDP-initiated Target.createTarget to WebUI URLs",
+  "version": "1.0",
+  "manifest_version": 2,
+  "background": {
+    "scripts": ["background.js"]
+  },
+  "permissions": [
+    "debugger"
+  ]
+}
diff --git a/chrome/test/data/extensions/api_test/debugger_navigate_to_untrusted_webui_url/background.js b/chrome/test/data/extensions/api_test/debugger_navigate_to_untrusted_webui_url/background.js
new file mode 100644
index 0000000..3b8f4bc
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/debugger_navigate_to_untrusted_webui_url/background.js
@@ -0,0 +1,24 @@
+// Copyright 2022 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.
+
+const protocolVersion = '1.3';
+
+chrome.test.runTests([async function testNavigationToUntrustedWebUIUrl() {
+  const {openTab} = await import('/_test_resources/test_util/tabs_util.js');
+  const tab = await openTab('about:blank');
+  const debuggee = {tabId: tab.id};
+  await new Promise(
+      resolve => chrome.debugger.attach(debuggee, protocolVersion, resolve));
+
+  await new Promise(
+      resolve => chrome.debugger.sendCommand(
+          debuggee, 'Page.navigate', {url: 'chrome-untrusted://terminal'},
+          resolve));
+  chrome.test.assertLastError(JSON.stringify({
+    code: -32000,
+    message: 'Navigating to a URL with a privileged scheme is not allowed'
+  }));
+
+  chrome.test.succeed();
+}]);
diff --git a/chrome/test/data/extensions/api_test/debugger_navigate_to_untrusted_webui_url/manifest.json b/chrome/test/data/extensions/api_test/debugger_navigate_to_untrusted_webui_url/manifest.json
new file mode 100644
index 0000000..05db294
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/debugger_navigate_to_untrusted_webui_url/manifest.json
@@ -0,0 +1,11 @@
+{
+  "name": "Debugger API test for CDP-initiated navigation to forbidden URLs",
+  "version": "1.0",
+  "manifest_version": 2,
+  "background": {
+    "scripts": ["background.js"]
+  },
+  "permissions": [
+    "debugger"
+  ]
+}
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/onboarding_enter_rsu_wp_disable_code_page_test.js b/chrome/test/data/webui/chromeos/shimless_rma/onboarding_enter_rsu_wp_disable_code_page_test.js
index bd17ebc..6263925 100644
--- a/chrome/test/data/webui/chromeos/shimless_rma/onboarding_enter_rsu_wp_disable_code_page_test.js
+++ b/chrome/test/data/webui/chromeos/shimless_rma/onboarding_enter_rsu_wp_disable_code_page_test.js
@@ -122,9 +122,7 @@
   test('EnterRsuWpDisableCodePageOpenChallengeDialog', async () => {
     await initializeEnterRsuWpDisableCodePage('', '');
 
-    component.shadowRoot.querySelector('#rsuCodeDialogLink')
-        .shadowRoot.querySelector('a')
-        .click();
+    component.shadowRoot.querySelector('#rsuCodeDialogLink').click();
     assertTrue(component.shadowRoot.querySelector('#rsuChallengeDialog').open);
   });
 
@@ -141,9 +139,7 @@
     await initializeEnterRsuWpDisableCodePage('', '');
 
     component.allButtonsDisabled = true;
-    component.shadowRoot.querySelector('#rsuCodeDialogLink')
-        .shadowRoot.querySelector('a')
-        .click();
+    component.shadowRoot.querySelector('#rsuCodeDialogLink').click();
     assertFalse(component.shadowRoot.querySelector('#rsuChallengeDialog').open);
   });
 
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/BUILD.gn b/chrome/test/data/webui/chromeos/shortcut_customization/BUILD.gn
index 6f4bfc26..50ce7f3 100644
--- a/chrome/test/data/webui/chromeos/shortcut_customization/BUILD.gn
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/BUILD.gn
@@ -19,15 +19,15 @@
                     target_gen_dir),
   ]
   in_files = [
-    "accelerator_edit_dialog_test.js",
-    "accelerator_edit_view_test.js",
-    "accelerator_lookup_manager_test.js",
-    "accelerator_row_test.js",
-    "accelerator_subsection_test.js",
-    "accelerator_view_test.js",
-    "fake_shortcut_provider_test.js",
-    "shortcut_customization_test.js",
-    "shortcut_customization_test_util.js",
+    "accelerator_edit_dialog_test.ts",
+    "accelerator_edit_view_test.ts",
+    "accelerator_lookup_manager_test.ts",
+    "accelerator_row_test.ts",
+    "accelerator_subsection_test.ts",
+    "accelerator_view_test.ts",
+    "fake_shortcut_provider_test.ts",
+    "shortcut_customization_test.ts",
+    "shortcut_customization_test_util.ts",
   ]
   deps = [ "//ash/webui/shortcut_customization_ui/resources:build_ts" ]
   extra_deps = [ "../..:generate_definitions" ]
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_dialog_test.js b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_dialog_test.js
deleted file mode 100644
index faae6c8..0000000
--- a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_dialog_test.js
+++ /dev/null
@@ -1,146 +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.
-
-import 'chrome://shortcut-customization/accelerator_edit_dialog.js';
-import 'chrome://webui-test/mojo_webui_test_support.js';
-
-import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {AcceleratorEditDialogElement} from 'chrome://shortcut-customization/accelerator_edit_dialog.js';
-import {Modifier} from 'chrome://shortcut-customization/shortcut_types.js';
-import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
-
-import {createUserAccelerator} from './shortcut_customization_test_util.js';
-
-suite('acceleratorEditDialogTest', function() {
-  /** @type {?AcceleratorEditDialogElement} */
-  let viewElement = null;
-
-  setup(() => {
-    viewElement = /** @type {!AcceleratorEditDialogElement} */ (
-        document.createElement('accelerator-edit-dialog'));
-    document.body.appendChild(viewElement);
-  });
-
-  teardown(() => {
-    viewElement.remove();
-    viewElement = null;
-  });
-
-  test('LoadsBasicDialog', async () => {
-    /** @type {!AcceleratorInfo} */
-    const acceleratorInfo1 = createUserAccelerator(
-        Modifier.CONTROL | Modifier.SHIFT,
-        /*key=*/ 71,
-        /*keyDisplay=*/ 'g');
-
-    /** @type {!AcceleratorInfo} */
-    const acceleratorInfo2 = createUserAccelerator(
-        Modifier.CONTROL,
-        /*key=*/ 67,
-        /*keyDisplay=*/ 'c');
-
-    const accelerators = [acceleratorInfo1, acceleratorInfo2];
-
-    const description = 'test shortcut';
-
-    viewElement.acceleratorInfos = accelerators;
-    viewElement.description = description;
-    await flush();
-    const dialog = viewElement.shadowRoot.querySelector('cr-dialog');
-    assertTrue(dialog.open);
-    const acceleratorElements =
-        dialog.querySelectorAll('accelerator-edit-view');
-    assertEquals(2, acceleratorElements.length);
-    assertEquals(
-        description, dialog.querySelector('#dialogTitle').textContent.trim());
-
-    const accelView1 =
-        acceleratorElements[0].shadowRoot.querySelector('accelerator-view');
-    const keys1 = accelView1.shadowRoot.querySelectorAll('input-key');
-    // SHIFT + CONTROL + g
-    assertEquals(3, keys1.length);
-    assertEquals(
-        'shift', keys1[0].shadowRoot.querySelector('#key').textContent.trim());
-    assertEquals(
-        'ctrl', keys1[1].shadowRoot.querySelector('#key').textContent.trim());
-    assertEquals(
-        'g', keys1[2].shadowRoot.querySelector('#key').textContent.trim());
-
-    const accelView2 =
-        acceleratorElements[1].shadowRoot.querySelector('accelerator-view');
-    const keys2 = accelView2.shadowRoot.querySelectorAll('input-key');
-    // CONTROL + c
-    assertEquals(2, keys2.length);
-    assertEquals(
-        'ctrl', keys2[0].shadowRoot.querySelector('#key').textContent.trim());
-    assertEquals(
-        'c', keys2[1].shadowRoot.querySelector('#key').textContent.trim());
-
-    // Clicking on "Done" button will close the dialog.
-    const button = dialog.querySelector('#doneButton');
-    button.click();
-    assertFalse(dialog.open);
-  });
-
-  test('AddShortcut', async () => {
-    /** @type {!AcceleratorInfo} */
-    const acceleratorInfo1 = createUserAccelerator(
-        Modifier.CONTROL | Modifier.SHIFT,
-        /*key=*/ 71,
-        /*keyDisplay=*/ 'g');
-
-    /** @type {!AcceleratorInfo} */
-    const acceleratorInfo2 = createUserAccelerator(
-        Modifier.CONTROL | Modifier.SHIFT,
-        /*key=*/ 67,
-        /*keyDisplay=*/ 'c');
-
-    const acceleratorInfos = [acceleratorInfo1, acceleratorInfo2];
-    const description = 'test shortcut';
-
-    viewElement.acceleratorInfos = acceleratorInfos;
-    viewElement.description = description;
-    await flush();
-    const dialog = viewElement.shadowRoot.querySelector('cr-dialog');
-    assertTrue(dialog.open);
-
-    // The "Add Shortcut" button should be visible and the pending accelerator
-    // should not be visible.
-    const buttonContainer = dialog.querySelector('#addAcceleratorContainer');
-    assertFalse(buttonContainer.hidden);
-    let pendingAccelerator = dialog.querySelector('#pendingAccelerator');
-    assertFalse(!!pendingAccelerator);
-
-    // Clicking on the "Add Shortcut" button should hide the button and show
-    // the pending shortcut.
-    const addButton = dialog.querySelector('#addAcceleratorButton');
-    addButton.click();
-    await flush();
-    assertTrue(buttonContainer.hidden);
-    // Expected the dialog's "done" button to be disabled when adding a new
-    // accelerator.
-    const doneButton = dialog.querySelector('#doneButton');
-    assertTrue(doneButton.disabled);
-    const restoreButton = dialog.querySelector('#restoreDefault');
-    assertTrue(restoreButton.hidden);
-
-    // Re-query the stamped element.
-    pendingAccelerator = dialog.querySelector('#pendingAccelerator');
-    assertTrue(!!pendingAccelerator);
-
-    // Click on the cancel button, expect the "Add Shortcut" button to be
-    // visible and the pending accelerator to be hidden.
-    pendingAccelerator.shadowRoot.querySelector('#cancelButton').click();
-    await flush();
-
-    // "done" button should now be enabled.
-    assertFalse(doneButton.disabled);
-    assertFalse(restoreButton.hidden);
-
-    assertFalse(buttonContainer.hidden);
-    // Re-query the stamped element.
-    pendingAccelerator = dialog.querySelector('#pendingAccelerator');
-    assertFalse(!!pendingAccelerator);
-  });
-});
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_dialog_test.ts b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_dialog_test.ts
new file mode 100644
index 0000000..af0f1fb
--- /dev/null
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_dialog_test.ts
@@ -0,0 +1,157 @@
+// 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 'chrome://shortcut-customization/accelerator_edit_dialog.js';
+import 'chrome://webui-test/mojo_webui_test_support.js';
+import 'chrome://shortcut-customization/accelerator_edit_dialog.js';
+
+import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.js';
+import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js';
+import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {AcceleratorEditDialogElement} from 'chrome://shortcut-customization/accelerator_edit_dialog.js';
+import {AcceleratorEditViewElement} from 'chrome://shortcut-customization/accelerator_edit_view.js';
+import {AcceleratorInfo, Modifier} from 'chrome://shortcut-customization/shortcut_types.js';
+import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
+
+import {createUserAccelerator} from './shortcut_customization_test_util.js';
+
+suite('acceleratorEditDialogTest', function() {
+  let viewElement: AcceleratorEditDialogElement|null = null;
+
+  setup(() => {
+    viewElement = document.createElement('accelerator-edit-dialog');
+    document.body.appendChild(viewElement);
+  });
+
+  teardown(() => {
+    viewElement!.remove();
+    viewElement = null;
+  });
+
+  test('LoadsBasicDialog', async () => {
+    const acceleratorInfo1: AcceleratorInfo = createUserAccelerator(
+        Modifier.CONTROL | Modifier.SHIFT,
+        /*key=*/ 71,
+        /*keyDisplay=*/ 'g');
+
+    const acceleratorInfo2: AcceleratorInfo = createUserAccelerator(
+        Modifier.CONTROL,
+        /*key=*/ 67,
+        /*keyDisplay=*/ 'c');
+
+    const accelerators = [acceleratorInfo1, acceleratorInfo2];
+
+    const description = 'test shortcut';
+
+    viewElement!.acceleratorInfos = accelerators;
+    viewElement!.description = description;
+    await flush();
+    const dialog =
+        viewElement!.shadowRoot!.querySelector('cr-dialog') as CrDialogElement;
+    assertTrue(dialog.open);
+    const acceleratorElements =
+        dialog.querySelectorAll('accelerator-edit-view');
+    assertEquals(2, acceleratorElements.length);
+    assertEquals(
+        description,
+        dialog!.querySelector('#dialogTitle')!.textContent!.trim());
+
+    const accelView1 =
+        acceleratorElements[0]!.shadowRoot!.querySelector('accelerator-view');
+    const keys1 = accelView1!.shadowRoot!.querySelectorAll('input-key');
+    // SHIFT + CONTROL + g
+    assertEquals(3, keys1.length);
+    assertEquals(
+        'shift',
+        keys1[0]!.shadowRoot!.querySelector('#key')!.textContent!.trim());
+    assertEquals(
+        'ctrl',
+        keys1[1]!.shadowRoot!.querySelector('#key')!.textContent!.trim());
+    assertEquals(
+        'g', keys1[2]!.shadowRoot!.querySelector('#key')!.textContent!.trim());
+
+    const accelView2 =
+        acceleratorElements[1]!.shadowRoot!.querySelector('accelerator-view');
+    const keys2 = accelView2!.shadowRoot!.querySelectorAll('input-key');
+    // CONTROL + c
+    assertEquals(2, keys2.length);
+    assertEquals(
+        'ctrl',
+        keys2[0]!.shadowRoot!.querySelector('#key')!.textContent!.trim());
+    assertEquals(
+        'c', keys2[1]!.shadowRoot!.querySelector('#key')!.textContent!.trim());
+
+    // Clicking on "Done" button will close the dialog.
+    const button = dialog!.querySelector('#doneButton') as CrButtonElement;
+    button.click();
+    assertFalse(dialog.open);
+  });
+
+  test('AddShortcut', async () => {
+    const acceleratorInfo1: AcceleratorInfo = createUserAccelerator(
+        Modifier.CONTROL | Modifier.SHIFT,
+        /*key=*/ 71,
+        /*keyDisplay=*/ 'g');
+
+    const acceleratorInfo2: AcceleratorInfo = createUserAccelerator(
+        Modifier.CONTROL | Modifier.SHIFT,
+        /*key=*/ 67,
+        /*keyDisplay=*/ 'c');
+
+    const acceleratorInfos = [acceleratorInfo1, acceleratorInfo2];
+    const description = 'test shortcut';
+
+    viewElement!.acceleratorInfos = acceleratorInfos;
+    viewElement!.description = description;
+    await flush();
+    const dialog = viewElement!.shadowRoot!.querySelector('cr-dialog');
+    assertTrue(!!dialog);
+    assertTrue(dialog.open);
+
+    // The "Add Shortcut" button should be visible and the pending accelerator
+    // should not be visible.
+    const buttonContainer =
+        dialog!.querySelector('#addAcceleratorContainer') as HTMLDivElement;
+    assertTrue(!!buttonContainer);
+    assertFalse(buttonContainer!.hidden);
+    let pendingAccelerator: AcceleratorEditViewElement|null =
+        dialog!.querySelector('#pendingAccelerator');
+    assertFalse(!!pendingAccelerator);
+
+    // Clicking on the "Add Shortcut" button should hide the button and show
+    // the pending shortcut.
+    const addButton =
+        dialog!.querySelector('#addAcceleratorButton') as CrButtonElement;
+    addButton!.click();
+    await flush();
+    assertTrue(buttonContainer!.hidden);
+    // Expected the dialog's "done" button to be disabled when adding a new
+    // accelerator.
+    const doneButton = dialog!.querySelector('#doneButton') as CrButtonElement;
+    assertTrue(doneButton!.disabled);
+    const restoreButton =
+        dialog!.querySelector('#restoreDefault') as CrButtonElement;
+    assertTrue(restoreButton!.hidden);
+
+    // Re-query the stamped element.
+    pendingAccelerator = dialog!.querySelector('#pendingAccelerator');
+    assertTrue(!!pendingAccelerator);
+
+    // Click on the cancel button, expect the "Add Shortcut" button to be
+    // visible and the pending accelerator to be hidden.
+    const cancelButton = pendingAccelerator!.shadowRoot!.querySelector(
+                             '#cancelButton') as CrButtonElement;
+    cancelButton.click();
+    await flush();
+
+    // "done" button should now be enabled.
+    assertFalse(doneButton!.disabled);
+    assertFalse(restoreButton!.hidden);
+
+    assertFalse(buttonContainer!.hidden);
+    // Re-query the stamped element.
+    pendingAccelerator = dialog!.querySelector('#pendingAccelerator');
+    assertFalse(!!pendingAccelerator);
+  });
+});
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_view_test.js b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_view_test.js
deleted file mode 100644
index aec32752..0000000
--- a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_view_test.js
+++ /dev/null
@@ -1,157 +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.
-
-import 'chrome://shortcut-customization/accelerator_edit_view.js';
-import 'chrome://webui-test/mojo_webui_test_support.js';
-
-import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {AcceleratorEditViewElement} from 'chrome://shortcut-customization/accelerator_edit_view.js';
-import {AcceleratorLookupManager} from 'chrome://shortcut-customization/accelerator_lookup_manager.js';
-import {fakeAcceleratorConfig, fakeLayoutInfo} from 'chrome://shortcut-customization/fake_data.js';
-import {AcceleratorSource, Modifier} from 'chrome://shortcut-customization/shortcut_types.js';
-import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
-import {flushTasks} from 'chrome://webui-test/test_util.js';
-
-import {createDefaultAccelerator, createUserAccelerator} from './shortcut_customization_test_util.js';
-
-suite('acceleratorEditViewTest', function() {
-  /** @type {?AcceleratorEditViewElement} */
-  let editViewElement = null;
-
-  /** @type {?AcceleratorLookupManager} */
-  let manager = null;
-
-  setup(() => {
-    manager = AcceleratorLookupManager.getInstance();
-    manager.setAcceleratorLookup(fakeAcceleratorConfig);
-    manager.setAcceleratorLayoutLookup(fakeLayoutInfo);
-
-    editViewElement = /** @type {!AcceleratorEditViewElement} */ (
-        document.createElement('accelerator-edit-view'));
-    document.body.appendChild(editViewElement);
-  });
-
-  teardown(() => {
-    manager.reset();
-    editViewElement.remove();
-    editViewElement = null;
-  });
-
-  test('LoadsBasicEditView', async () => {
-    /** @type {!AcceleratorInfo} */
-    const acceleratorInfo = createUserAccelerator(
-        Modifier.CONTROL | Modifier.SHIFT,
-        /*key=*/ 71,
-        /*keyDisplay=*/ 'g');
-
-    editViewElement.acceleratorInfo = acceleratorInfo;
-    await flush();
-
-    // Check that the edit buttons are visible.
-    assertFalse(
-        editViewElement.shadowRoot.querySelector('#editButtonsContainer')
-            .hidden);
-    assertTrue(
-        editViewElement.shadowRoot.querySelector('#cancelButtonContainer')
-            .hidden);
-
-    // Click on the edit button.
-    editViewElement.shadowRoot.querySelector('#editButton').click();
-
-    // Only the Cancel button should now be visible.
-    assertTrue(editViewElement.shadowRoot.querySelector('#editButtonsContainer')
-                   .hidden);
-    assertFalse(
-        editViewElement.shadowRoot.querySelector('#cancelButtonContainer')
-            .hidden);
-
-    // Click on the Cancel button and expect the edit buttons to be available.
-    editViewElement.shadowRoot.querySelector('#cancelButton').click();
-    assertFalse(
-        editViewElement.shadowRoot.querySelector('#editButtonsContainer')
-            .hidden);
-    assertTrue(
-        editViewElement.shadowRoot.querySelector('#cancelButtonContainer')
-            .hidden);
-  });
-
-  test('LockedAccelerator', async () => {
-    /** @type {!AcceleratorInfo} */
-    const acceleratorInfo = createUserAccelerator(
-        Modifier.CONTROL | Modifier.SHIFT,
-        /*key=*/ 71,
-        /*keyDisplay=*/ 'g',
-        /*locked=*/ true);
-
-    editViewElement.acceleratorInfo = acceleratorInfo;
-    await flush();
-
-    // Check that the edit buttons are not visible.
-    assertFalse(
-        !!editViewElement.shadowRoot.querySelector('#editButtonsContainer'));
-    assertFalse(
-        !!editViewElement.shadowRoot.querySelector('#cancelButtonContainer'));
-    // Lock icon should be visible.
-    assertFalse(
-        editViewElement.shadowRoot.querySelector('#lockContainer').hidden);
-  });
-
-  test('DetectShortcutConflict', async () => {
-    /** @type {!AcceleratorInfo} */
-    const acceleratorInfo = createDefaultAccelerator(
-        Modifier.ALT,
-        /*key=*/ 221,
-        /*keyDisplay=*/ ']');
-
-    editViewElement.acceleratorInfo = acceleratorInfo;
-    editViewElement.source = AcceleratorSource.ASH;
-    editViewElement.action = 1;
-    await flushTasks();
-
-    // Check that the edit buttons are visible.
-    assertFalse(
-        editViewElement.shadowRoot.querySelector('#editButtonsContainer')
-            .hidden);
-    assertTrue(
-        editViewElement.shadowRoot.querySelector('#cancelButtonContainer')
-            .hidden);
-
-    // Assert that no error has occurred.
-    assertFalse(editViewElement.hasError);
-
-    // Click on the edit button.
-    editViewElement.shadowRoot.querySelector('#editButton').click();
-
-    // Press 'Snap Window left' key, expect an error due since it is a
-    // pre-existing shortcut.
-    const viewElement =
-        editViewElement.shadowRoot.querySelector('#acceleratorItem');
-    viewElement.dispatchEvent(new KeyboardEvent('keydown', {
-      key: '[',
-      keyCode: '219',
-      code: 'Key[',
-      ctrlKey: false,
-      altKey: true,
-      shiftKey: false,
-      metaKey: false,
-    }));
-
-    await flushTasks();
-    assertTrue(editViewElement.hasError);
-
-    // Press another shortcut, expect no error.
-    viewElement.dispatchEvent(new KeyboardEvent('keydown', {
-      key: 'e',
-      keyCode: '69',
-      code: 'KeyE',
-      ctrlKey: true,
-      altKey: true,
-      shiftKey: false,
-      metaKey: false,
-    }));
-
-    await flushTasks();
-    assertFalse(editViewElement.hasError);
-  });
-});
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_view_test.ts b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_view_test.ts
new file mode 100644
index 0000000..b5a7c31
--- /dev/null
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_view_test.ts
@@ -0,0 +1,144 @@
+// 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 'chrome://shortcut-customization/accelerator_edit_view.js';
+import 'chrome://webui-test/mojo_webui_test_support.js';
+
+import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {AcceleratorEditViewElement} from 'chrome://shortcut-customization/accelerator_edit_view.js';
+import {AcceleratorLookupManager} from 'chrome://shortcut-customization/accelerator_lookup_manager.js';
+import {fakeAcceleratorConfig, fakeLayoutInfo} from 'chrome://shortcut-customization/fake_data.js';
+import {AcceleratorSource, Modifier} from 'chrome://shortcut-customization/shortcut_types.js';
+import {assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
+import {flushTasks, isVisible} from 'chrome://webui-test/test_util.js';
+
+import {createDefaultAccelerator, createUserAccelerator} from './shortcut_customization_test_util.js';
+
+suite('acceleratorEditViewTest', function() {
+  let editViewElement: AcceleratorEditViewElement|null = null;
+  let manager: AcceleratorLookupManager|null = null;
+
+  setup(() => {
+    manager = AcceleratorLookupManager.getInstance();
+    manager.setAcceleratorLookup(fakeAcceleratorConfig);
+    manager.setAcceleratorLayoutLookup(fakeLayoutInfo);
+
+    editViewElement = document.createElement('accelerator-edit-view');
+    document.body.appendChild(editViewElement);
+  });
+
+  teardown(() => {
+    if (manager) {
+      manager.reset();
+    }
+    editViewElement!.remove();
+    editViewElement = null;
+  });
+
+  function getElementById(id: string): HTMLElement {
+    assertTrue(!!editViewElement);
+    const element = editViewElement.shadowRoot!.getElementById(id);
+    assertTrue(!!element);
+    return element as HTMLElement;
+  }
+
+  test('LoadsBasicEditView', async () => {
+    const acceleratorInfo = createUserAccelerator(
+        Modifier.CONTROL | Modifier.SHIFT,
+        /*key=*/ 71,
+        /*keyDisplay=*/ 'g');
+
+    editViewElement!.acceleratorInfo = acceleratorInfo;
+    await flush();
+
+    // Check that the edit buttons are visible.
+    assertTrue(isVisible(getElementById('editButtonsContainer')));
+    assertFalse(isVisible(getElementById('cancelButtonContainer')));
+
+
+    // Click on the edit button.
+    getElementById('editButton')!.click();
+
+    // Only the Cancel button should now be visible.
+    assertFalse(isVisible(getElementById('editButtonsContainer')));
+    assertTrue(isVisible(getElementById('cancelButtonContainer')));
+
+
+    // Click on the Cancel button and expect the edit buttons to be available.
+    getElementById('cancelButton')!.click();
+    assertTrue(isVisible(getElementById('editButtonsContainer')));
+    assertFalse(isVisible(getElementById('cancelButtonContainer')));
+  });
+
+  test('LockedAccelerator', async () => {
+    const acceleratorInfo = createUserAccelerator(
+        Modifier.CONTROL | Modifier.SHIFT,
+        /*key=*/ 71,
+        /*keyDisplay=*/ 'g',
+        /*locked=*/ true);
+
+    editViewElement!.acceleratorInfo = acceleratorInfo;
+    await flush();
+
+    // Check that the edit buttons are not visible.
+    assertFalse(
+        !!editViewElement!.shadowRoot!.querySelector('#editButtonsContainer'));
+    assertFalse(
+        !!editViewElement!.shadowRoot!.querySelector('#cancelButtonContainer'));
+    // Lock icon should be visible.
+    assertTrue(isVisible(getElementById('lockContainer')));
+  });
+
+  test('DetectShortcutConflict', async () => {
+    const acceleratorInfo = createDefaultAccelerator(
+        Modifier.ALT,
+        /*key=*/ 221,
+        /*keyDisplay=*/ ']');
+
+    editViewElement!.acceleratorInfo = acceleratorInfo;
+    editViewElement!.source = AcceleratorSource.ASH;
+    editViewElement!.action = 1;
+    await flushTasks();
+
+    // Check that the edit buttons are visible.
+    assertTrue(isVisible(getElementById('editButtonsContainer')));
+    assertFalse(isVisible(getElementById('cancelButtonContainer')));
+
+    // Assert that no error has occurred.
+    assertFalse(editViewElement!.hasError);
+
+    // Click on the edit button.
+    getElementById('editButton')!.click();
+
+    // Press 'Snap Window left' key, expect an error due since it is a
+    // pre-existing shortcut.
+    const viewElement = getElementById('acceleratorItem');
+    viewElement!.dispatchEvent(new KeyboardEvent('keydown', {
+      key: '[',
+      keyCode: 219,
+      code: 'Key[',
+      ctrlKey: false,
+      altKey: true,
+      shiftKey: false,
+      metaKey: false,
+    }));
+
+    await flushTasks();
+    assertTrue(editViewElement!.hasError);
+
+    // Press another shortcut, expect no error.
+    viewElement!.dispatchEvent(new KeyboardEvent('keydown', {
+      key: 'e',
+      keyCode: 69,
+      code: 'KeyE',
+      ctrlKey: true,
+      altKey: true,
+      shiftKey: false,
+      metaKey: false,
+    }));
+
+    await flushTasks();
+    assertFalse(editViewElement!.hasError);
+  });
+});
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_lookup_manager_test.js b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_lookup_manager_test.js
deleted file mode 100644
index b86adfa..0000000
--- a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_lookup_manager_test.js
+++ /dev/null
@@ -1,349 +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.
-
-import 'chrome://webui-test/mojo_webui_test_support.js';
-
-import {AcceleratorLookupManager} from 'chrome://shortcut-customization/accelerator_lookup_manager.js';
-import {fakeAcceleratorConfig, fakeLayoutInfo} from 'chrome://shortcut-customization/fake_data.js';
-import {FakeShortcutProvider} from 'chrome://shortcut-customization/fake_shortcut_provider.js';
-import {AcceleratorSource, AcceleratorState, Modifier} from 'chrome://shortcut-customization/shortcut_types.js';
-import {assertDeepEquals, assertEquals} from 'chrome://webui-test/chai_assert.js';
-import {flushTasks} from 'chrome://webui-test/test_util.js';
-
-suite('acceleratorLookupManagerTest', function() {
-  /** @type {?FakeShortcutProvider} */
-  let provider = null;
-
-  /** @type {?AcceleratorLookupManager} */
-  let manager = null;
-
-  setup(() => {
-    provider = new FakeShortcutProvider();
-    manager = AcceleratorLookupManager.getInstance();
-  });
-
-  teardown(() => {
-    manager.reset();
-    provider = null;
-  });
-
-  /**
-   * @param {AcceleratorSource} source
-   * @param {number} action
-   * @param {!AcceleratorKeys} oldKeys
-   * @param {!AcceleratorKeys} newKeys
-   */
-  function replaceAndVerify(source, action, oldKeys, newKeys) {
-    const uuid = manager.getAcceleratorFromKeys(JSON.stringify(oldKeys));
-    manager.replaceAccelerator(source, action, oldKeys, newKeys);
-
-    // Verify that the old accelerator is no longer part of the reverse
-    // lookup.
-    assertEquals(
-        undefined, manager.getAcceleratorFromKeys(JSON.stringify(oldKeys)));
-    // Verify the replacement accelerator is in the reverse lookup.
-    assertEquals(uuid, manager.getAcceleratorFromKeys(JSON.stringify(newKeys)));
-  }
-
-  /**
-   * @param {AcceleratorSource} source
-   * @param {number} action
-   * @param {!AcceleratorKeys} newKeys
-   */
-  function addAndVerify(source, action, newKeys) {
-    manager.addAccelerator(source, action, newKeys);
-
-    // Verify that the new accelerator is in the reverse lookup.
-    assertEquals(
-        `${source}-${action}`,
-        manager.getAcceleratorFromKeys(JSON.stringify(newKeys)));
-  }
-
-  test('AcceleratorLookupDefaultFake', () => {
-    // TODO(jimmyxgong): Remove this test once real data is ready.
-    provider.setFakeAcceleratorConfig(fakeAcceleratorConfig);
-    return provider.getAllAcceleratorConfig().then((result) => {
-      assertDeepEquals(fakeAcceleratorConfig, result);
-
-      manager.setAcceleratorLookup(result);
-
-      for (const [source, accelMap] of fakeAcceleratorConfig) {
-        for (const [action, accelInfos] of accelMap) {
-          const actualAccels = manager.getAccelerators(source, action);
-          assertDeepEquals(accelInfos, actualAccels);
-        }
-      }
-    });
-  });
-
-  test('GetLayoutInfoDefaultFake', () => {
-    // TODO(jimmyxgong): Remove this test once real data is ready.
-    provider.setFakeLayoutInfo(fakeLayoutInfo);
-    return provider.getLayoutInfo().then((result) => {
-      assertDeepEquals(fakeLayoutInfo, result);
-
-      manager.setAcceleratorLayoutLookup(result);
-
-      // 2 layout infos for ChromeOS (Window Management, Virtual Desks).
-      assertEquals(2, manager.getSubcategories(/*ChromeOS=*/ 0).size);
-      // 1 layout infos for Browser (Tabs).
-      assertEquals(1, manager.getSubcategories(/*Browser=*/ 1).size);
-    });
-  });
-
-  test('ReplaceBasicAccelerator', () => {
-    provider.setFakeAcceleratorConfig(fakeAcceleratorConfig);
-    return provider.getAllAcceleratorConfig().then((result) => {
-      assertDeepEquals(fakeAcceleratorConfig, result);
-
-      manager.setAcceleratorLookup(result);
-
-      // Get Snap Window Right accelerator.
-      const expectedAction = 1;
-      const ashMap = fakeAcceleratorConfig.get(AcceleratorSource.ASH);
-      const snapWindowRightAccels = ashMap.get(expectedAction);
-      // Modifier.Alt + key::221 (']')
-      const oldAccel = snapWindowRightAccels[0].accelerator;
-
-      const expectedNewAccel = /** @type {!AcceleratorKeys} */ ({
-        modifiers: Modifier.CONTROL,
-        key: 79,
-        keyDisplay: 'o',
-      });
-
-      // Sanity check that new accel is not in the reverse lookup.
-      assertEquals(
-          undefined,
-          manager.getAcceleratorFromKeys(JSON.stringify(expectedNewAccel)));
-
-      replaceAndVerify(
-          AcceleratorSource.ASH, expectedAction, oldAccel, expectedNewAccel);
-
-      // Check that the accelerator got updated in the lookup.
-      let lookup =
-          manager.getAccelerators(AcceleratorSource.ASH, expectedAction);
-      // Replacing a default shortcut should not remove the default. Expect a
-      // new accelerator to be added instead.
-      assertEquals(2, lookup.length);
-      assertEquals(
-          JSON.stringify(expectedNewAccel),
-          JSON.stringify(lookup[1].accelerator));
-
-      // Replace the new accelerator with the "ALT + ]" default accelerator.
-      const expectedNewDefaultAccel = /** @type {!AcceleratorKeys} */ ({
-        modifiers: Modifier.ALT,
-        key: 221,
-        keyDisplay: ']',
-      });
-
-      // Sanity check that new accel is not in the reverse lookup.
-      assertEquals(
-          undefined,
-          manager.getAcceleratorFromKeys(
-              JSON.stringify(expectedNewDefaultAccel)));
-      replaceAndVerify(
-          AcceleratorSource.ASH, expectedAction, expectedNewAccel,
-          expectedNewDefaultAccel);
-
-      // Check that the accelerator got updated in the lookup.
-      lookup = manager.getAccelerators(AcceleratorSource.ASH, expectedAction);
-      // Expect only one accelerator since the previous accelerator has been
-      // removed but the default accelerator has been re-enabled.
-      assertEquals(1, lookup.length);
-      assertEquals(
-          JSON.stringify(expectedNewDefaultAccel),
-          JSON.stringify(lookup[0].accelerator));
-    });
-  });
-
-  test('ReplacePreexistingAccelerator', () => {
-    provider.setFakeAcceleratorConfig(fakeAcceleratorConfig);
-    return provider.getAllAcceleratorConfig().then((result) => {
-      assertDeepEquals(fakeAcceleratorConfig, result);
-
-      manager.setAcceleratorLookup(result);
-
-      // Get Snap Window Right accelerator, the action that will be overridden.
-      const snapWindowRightAction = 1;
-      const ashMap = fakeAcceleratorConfig.get(AcceleratorSource.ASH);
-      const snapWindowRightAccels = ashMap.get(snapWindowRightAction);
-      // Modifier.Alt + key::221 (']')
-      const overridenAccel = snapWindowRightAccels[0].accelerator;
-
-      // Replace New Desk shortcut with Alt+']'.
-      const newDeskAction = 2;
-      const oldNewDeskAccel = ashMap.get(newDeskAction)[0].accelerator;
-
-      replaceAndVerify(
-          AcceleratorSource.ASH, newDeskAction, oldNewDeskAccel,
-          overridenAccel);
-
-      // Verify that the New Desk shortcut now has the ALT + ']' accelerator.
-      const newDeskLookup =
-          manager.getAccelerators(AcceleratorSource.ASH, newDeskAction);
-      assertEquals(2, newDeskLookup.length);
-      assertEquals(
-          JSON.stringify(overridenAccel),
-          JSON.stringify(newDeskLookup[1].accelerator));
-
-      // There should still be 1 accelerator for snapWindowRight, but the
-      // default should be disabled.
-      const snapWindowRightLookup =
-          manager.getAccelerators(AcceleratorSource.ASH, snapWindowRightAction);
-      assertEquals(1, snapWindowRightLookup.length);
-      assertEquals(
-          AcceleratorState.DISABLED_BY_USER, snapWindowRightLookup[0].state);
-    });
-  });
-
-  test('AddBasicAccelerator', () => {
-    provider.setFakeAcceleratorConfig(fakeAcceleratorConfig);
-    return provider.getAllAcceleratorConfig().then((result) => {
-      assertDeepEquals(fakeAcceleratorConfig, result);
-
-      manager.setAcceleratorLookup(result);
-
-      // Get Snap Window Right accelerator from kAsh[1].
-      const expectedAction = 1;
-
-      const expectedNewAccel = /** @type {!AcceleratorKeys} */ ({
-        modifiers: Modifier.CONTROL,
-        key: 79,
-        keyDisplay: 'o',
-      });
-
-      // Sanity check that new accel is not in the reverse lookup.
-      assertEquals(
-          undefined,
-          manager.getAcceleratorFromKeys(JSON.stringify(expectedNewAccel)));
-
-      addAndVerify(AcceleratorSource.ASH, expectedAction, expectedNewAccel);
-
-      // Check that the accelerator got updated in the lookup.
-      const lookup =
-          manager.getAccelerators(AcceleratorSource.ASH, expectedAction);
-      assertEquals(2, lookup.length);
-      assertEquals(
-          JSON.stringify(expectedNewAccel),
-          JSON.stringify(lookup[1].accelerator));
-    });
-  });
-
-  test('AddExistingAccelerator', () => {
-    provider.setFakeAcceleratorConfig(fakeAcceleratorConfig);
-    return provider.getAllAcceleratorConfig().then((result) => {
-      assertDeepEquals(fakeAcceleratorConfig, result);
-
-      manager.setAcceleratorLookup(result);
-
-      // Get Snap Window Right accelerator, the action that will be overridden.
-      const snapWindowRightAction = 1;
-      const ashMap = fakeAcceleratorConfig.get(AcceleratorSource.ASH);
-      const snapWindowRightAccels = ashMap.get(snapWindowRightAction);
-      // Modifier.Alt + key::221 (']')
-      const overridenAccel = snapWindowRightAccels[0].accelerator;
-
-      // Replace New Desk shortcut with Alt+']'.
-      const newDeskAction = 2;
-
-      addAndVerify(AcceleratorSource.ASH, newDeskAction, overridenAccel);
-
-      // Verify that the New Desk shortcut now has the ALT + ']' accelerator.
-      const newDeskLookup =
-          manager.getAccelerators(AcceleratorSource.ASH, newDeskAction);
-      assertEquals(2, newDeskLookup.length);
-      assertEquals(
-          JSON.stringify(overridenAccel),
-          JSON.stringify(newDeskLookup[1].accelerator));
-
-      // Replacing a default accelerator should not remove it but rather disable
-      // it.
-      const snapWindowRightLookup =
-          manager.getAccelerators(AcceleratorSource.ASH, snapWindowRightAction);
-      assertEquals(1, snapWindowRightLookup.length);
-      assertEquals(
-          AcceleratorState.DISABLED_BY_USER, snapWindowRightLookup[0].state);
-    });
-  });
-
-  test('RemoveDefaultAccelerator', () => {
-    provider.setFakeAcceleratorConfig(fakeAcceleratorConfig);
-    return provider.getAllAcceleratorConfig().then((result) => {
-      assertDeepEquals(fakeAcceleratorConfig, result);
-
-      manager.setAcceleratorLookup(result);
-
-      // Get Snap Window Right accelerator from kAsh[1].
-      const expectedAction = 1;
-
-      // Initially there is only one accelerator for Snap Window Right.
-      const lookup =
-          manager.getAccelerators(AcceleratorSource.ASH, expectedAction);
-      assertEquals(1, lookup.length);
-
-      // Remove the accelerator.
-      const removedAccelerator = lookup[0].accelerator;
-      manager.removeAccelerator(
-          AcceleratorSource.ASH, expectedAction, removedAccelerator);
-
-      // Removing a default accelerator only disables it.
-      assertEquals(1, lookup.length);
-      assertEquals(AcceleratorState.DISABLED_BY_USER, lookup[0].state);
-
-      // Removed accelerator should not appear in the reverse lookup.
-      assertEquals(
-          undefined,
-          manager.getAcceleratorFromKeys(JSON.stringify(removedAccelerator)));
-    });
-  });
-
-  test('AddAndRemoveAccelerator', () => {
-    provider.setFakeAcceleratorConfig(fakeAcceleratorConfig);
-    return provider.getAllAcceleratorConfig().then((result) => {
-      assertDeepEquals(fakeAcceleratorConfig, result);
-
-      manager.setAcceleratorLookup(result);
-
-      // Get Snap Window Right accelerator from kAsh[1].
-      const expectedAction = 1;
-
-      // Initially there is only one accelerator for Snap Window Right.
-      const lookup =
-          manager.getAccelerators(AcceleratorSource.ASH, expectedAction);
-      assertEquals(1, lookup.length);
-
-      const expectedNewAccel = /** @type {!AcceleratorKeys} */ ({
-        modifiers: Modifier.CONTROL,
-        key: 79,
-        keyDisplay: 'o',
-      });
-
-      // Sanity check that new accel is not in the reverse lookup.
-      assertEquals(
-          undefined,
-          manager.getAcceleratorFromKeys(JSON.stringify(expectedNewAccel)));
-
-      addAndVerify(AcceleratorSource.ASH, expectedAction, expectedNewAccel);
-
-      // Check that the accelerator got updated in the lookup.
-      assertEquals(2, lookup.length);
-      assertEquals(
-          JSON.stringify(expectedNewAccel),
-          JSON.stringify(lookup[1].accelerator));
-
-      // Remove the accelerator.
-      const removedAccelerator = lookup[1].accelerator;
-      manager.removeAccelerator(
-          AcceleratorSource.ASH, expectedAction, removedAccelerator);
-
-      // Expect only 1 accelerator.
-      assertEquals(1, lookup.length);
-
-      // Removed accelerator should not appear in the reverse lookup.
-      assertEquals(
-          undefined,
-          manager.getAcceleratorFromKeys(JSON.stringify(removedAccelerator)));
-    });
-  });
-});
\ No newline at end of file
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_lookup_manager_test.ts b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_lookup_manager_test.ts
new file mode 100644
index 0000000..6b72f51
--- /dev/null
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_lookup_manager_test.ts
@@ -0,0 +1,364 @@
+// 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 'chrome://webui-test/mojo_webui_test_support.js';
+
+import {AcceleratorLookupManager} from 'chrome://shortcut-customization/accelerator_lookup_manager.js';
+import {fakeAcceleratorConfig, fakeLayoutInfo} from 'chrome://shortcut-customization/fake_data.js';
+import {FakeShortcutProvider} from 'chrome://shortcut-customization/fake_shortcut_provider.js';
+import {AcceleratorInfo, AcceleratorKeys, AcceleratorSource, AcceleratorState, Modifier} from 'chrome://shortcut-customization/shortcut_types.js';
+import {assertDeepEquals, assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
+
+suite('acceleratorLookupManagerTest', function() {
+  let provider: FakeShortcutProvider|null = null;
+
+  let manager: AcceleratorLookupManager|null = null;
+
+  setup(() => {
+    provider = new FakeShortcutProvider();
+    manager = AcceleratorLookupManager.getInstance();
+  });
+
+  teardown(() => {
+    if (manager) {
+      manager.reset();
+    }
+    provider = null;
+  });
+
+  function getManager(): AcceleratorLookupManager {
+    assertTrue(!!manager);
+    return manager;
+  }
+
+  function getProvider(): FakeShortcutProvider {
+    assertTrue(!!provider);
+    return provider;
+  }
+
+  function replaceAndVerify(
+      source: AcceleratorSource, action: number, oldKeys: AcceleratorKeys,
+      newKeys: AcceleratorKeys) {
+    const uuid = getManager().getAcceleratorFromKeys(JSON.stringify(oldKeys));
+    getManager().replaceAccelerator(source, action, oldKeys, newKeys);
+
+    // Verify that the old accelerator is no longer part of the reverse
+    // lookup.
+    assertEquals(
+        undefined,
+        getManager().getAcceleratorFromKeys(JSON.stringify(oldKeys)));
+    // Verify the replacement accelerator is in the reverse lookup.
+    assertEquals(
+        uuid, getManager().getAcceleratorFromKeys(JSON.stringify(newKeys)));
+  }
+
+  function addAndVerify(
+      source: AcceleratorSource, action: number, newKeys: AcceleratorKeys) {
+    getManager().addAccelerator(source, action, newKeys);
+
+    // Verify that the new accelerator is in the reverse lookup.
+    assertEquals(
+        `${source}-${action}`,
+        getManager().getAcceleratorFromKeys(JSON.stringify(newKeys)));
+  }
+
+  test('AcceleratorLookupDefaultFake', () => {
+    // TODO(jimmyxgong): Remove this test once real data is ready.
+    getProvider().setFakeAcceleratorConfig(fakeAcceleratorConfig);
+    return getProvider().getAllAcceleratorConfig().then((result) => {
+      assertDeepEquals(fakeAcceleratorConfig, result);
+
+      getManager().setAcceleratorLookup(result);
+
+      for (const [source, accelMap] of fakeAcceleratorConfig) {
+        for (const [action, accelInfos] of accelMap) {
+          const actualAccels = getManager().getAccelerators(source, action);
+          assertDeepEquals(accelInfos, actualAccels);
+        }
+      }
+    });
+  });
+
+  test('GetLayoutInfoDefaultFake', () => {
+    // TODO(jimmyxgong): Remove this test once real data is ready.
+    getProvider().setFakeLayoutInfo(fakeLayoutInfo);
+    return getProvider().getLayoutInfo().then((result) => {
+      assertDeepEquals(fakeLayoutInfo, result);
+
+      getManager().setAcceleratorLayoutLookup(result);
+
+      // 2 layout infos for ChromeOS (Window Management, Virtual Desks).
+      assertEquals(2, getManager().getSubcategories(/*ChromeOS=*/ 0)!.size);
+      // 1 layout infos for Browser (Tabs).
+      assertEquals(1, getManager().getSubcategories(/*Browser=*/ 1)!.size);
+    });
+  });
+
+  test('ReplaceBasicAccelerator', () => {
+    getProvider().setFakeAcceleratorConfig(fakeAcceleratorConfig);
+    return getProvider().getAllAcceleratorConfig().then((result) => {
+      assertDeepEquals(fakeAcceleratorConfig, result);
+
+      getManager().setAcceleratorLookup(result);
+
+      // Get Snap Window Right accelerator.
+      const expectedAction = 1;
+      const ashMap = fakeAcceleratorConfig.get(AcceleratorSource.ASH);
+      const snapWindowRightAccels = ashMap!.get(expectedAction);
+      assertTrue(!!snapWindowRightAccels);
+      // Modifier.Alt + key::221 (']')
+      const oldAccel = snapWindowRightAccels[0]!.accelerator;
+
+      const expectedNewAccel = /** @type {!AcceleratorKeys} */ ({
+        modifiers: Modifier.CONTROL,
+        key: 79,
+        keyDisplay: 'o',
+      });
+
+      // Sanity check that new accel is not in the reverse lookup.
+      assertEquals(
+          undefined,
+          getManager().getAcceleratorFromKeys(
+              JSON.stringify(expectedNewAccel)));
+
+      replaceAndVerify(
+          AcceleratorSource.ASH, expectedAction, oldAccel, expectedNewAccel);
+
+      // Check that the accelerator got updated in the lookup.
+      let lookup =
+          getManager().getAccelerators(AcceleratorSource.ASH, expectedAction);
+      // Replacing a default shortcut should not remove the default. Expect a
+      // new accelerator to be added instead.
+      assertEquals(2, lookup.length);
+      assertEquals(
+          JSON.stringify(expectedNewAccel),
+          JSON.stringify(lookup[1]!.accelerator));
+
+      // Replace the new accelerator with the "ALT + ]" default accelerator.
+      const expectedNewDefaultAccel = /** @type {!AcceleratorKeys} */ ({
+        modifiers: Modifier.ALT,
+        key: 221,
+        keyDisplay: ']',
+      });
+
+      // Sanity check that new accel is not in the reverse lookup.
+      assertEquals(
+          undefined,
+          getManager().getAcceleratorFromKeys(
+              JSON.stringify(expectedNewDefaultAccel)));
+      replaceAndVerify(
+          AcceleratorSource.ASH, expectedAction, expectedNewAccel,
+          expectedNewDefaultAccel);
+
+      // Check that the accelerator got updated in the lookup.
+      lookup =
+          getManager().getAccelerators(AcceleratorSource.ASH, expectedAction);
+      // Expect only one accelerator since the previous accelerator has been
+      // removed but the default accelerator has been re-enabled.
+      assertEquals(1, lookup.length);
+      assertEquals(
+          JSON.stringify(expectedNewDefaultAccel),
+          JSON.stringify(lookup[0]!.accelerator));
+    });
+  });
+
+  test('ReplacePreexistingAccelerator', () => {
+    getProvider().setFakeAcceleratorConfig(fakeAcceleratorConfig);
+    return getProvider().getAllAcceleratorConfig().then((result) => {
+      assertDeepEquals(fakeAcceleratorConfig, result);
+
+      getManager().setAcceleratorLookup(result);
+
+      // Get Snap Window Right accelerator, the action that will be overridden.
+      const snapWindowRightAction = 1;
+      const ashMap = fakeAcceleratorConfig!.get(AcceleratorSource.ASH) as
+          Map<number, AcceleratorInfo[]>;
+      const snapWindowRightAccels =
+          ashMap!.get(snapWindowRightAction) as AcceleratorInfo[];
+      // Modifier.Alt + key::221 (']')
+      const overridenAccel = snapWindowRightAccels[0]!.accelerator;
+
+      // Replace New Desk shortcut with Alt+']'.
+      const newDeskAction = 2;
+      const oldNewDeskAccels = ashMap!.get(newDeskAction) as AcceleratorInfo[];
+      const oldNewDeskAccel = oldNewDeskAccels[0]!.accelerator;
+
+      replaceAndVerify(
+          AcceleratorSource.ASH, newDeskAction, oldNewDeskAccel,
+          overridenAccel);
+
+      // Verify that the New Desk shortcut now has the ALT + ']' accelerator.
+      const newDeskLookup =
+          getManager().getAccelerators(AcceleratorSource.ASH, newDeskAction);
+      assertEquals(2, newDeskLookup.length);
+      assertEquals(
+          JSON.stringify(overridenAccel),
+          JSON.stringify(newDeskLookup[1]!.accelerator));
+
+      // There should still be 1 accelerator for snapWindowRight, but the
+      // default should be disabled.
+      const snapWindowRightLookup = getManager().getAccelerators(
+          AcceleratorSource.ASH, snapWindowRightAction);
+      assertEquals(1, snapWindowRightLookup.length);
+      assertEquals(
+          AcceleratorState.DISABLED_BY_USER, snapWindowRightLookup[0]!.state);
+    });
+  });
+
+  test('AddBasicAccelerator', () => {
+    getProvider().setFakeAcceleratorConfig(fakeAcceleratorConfig);
+    return getProvider().getAllAcceleratorConfig().then((result) => {
+      assertDeepEquals(fakeAcceleratorConfig, result);
+
+      getManager().setAcceleratorLookup(result);
+
+      // Get Snap Window Right accelerator from kAsh[1]!.
+      const expectedAction = 1;
+
+      const expectedNewAccel = /** @type {!AcceleratorKeys} */ ({
+        modifiers: Modifier.CONTROL,
+        key: 79,
+        keyDisplay: 'o',
+      });
+
+      // Sanity check that new accel is not in the reverse lookup.
+      assertEquals(
+          undefined,
+          getManager().getAcceleratorFromKeys(
+              JSON.stringify(expectedNewAccel)));
+
+      addAndVerify(AcceleratorSource.ASH, expectedAction, expectedNewAccel);
+
+      // Check that the accelerator got updated in the lookup.
+      const lookup =
+          getManager().getAccelerators(AcceleratorSource.ASH, expectedAction);
+      assertEquals(2, lookup.length);
+      assertEquals(
+          JSON.stringify(expectedNewAccel),
+          JSON.stringify(lookup[1]!.accelerator));
+    });
+  });
+
+  test('AddExistingAccelerator', () => {
+    getProvider().setFakeAcceleratorConfig(fakeAcceleratorConfig);
+    return getProvider().getAllAcceleratorConfig().then((result) => {
+      assertDeepEquals(fakeAcceleratorConfig, result);
+
+      getManager().setAcceleratorLookup(result);
+
+      // Get Snap Window Right accelerator, the action that will be overridden.
+      const snapWindowRightAction = 1;
+      const ashMap = fakeAcceleratorConfig!.get(AcceleratorSource.ASH) as
+          Map<number, AcceleratorInfo[]>;
+      const snapWindowRightAccels =
+          ashMap!.get(snapWindowRightAction) as AcceleratorInfo[];
+      // Modifier.Alt + key::221 (']')
+      const overridenAccel = snapWindowRightAccels[0]!.accelerator;
+
+      // Replace New Desk shortcut with Alt+']'.
+      const newDeskAction = 2;
+
+      addAndVerify(AcceleratorSource.ASH, newDeskAction, overridenAccel);
+
+      // Verify that the New Desk shortcut now has the ALT + ']' accelerator.
+      const newDeskLookup =
+          getManager().getAccelerators(AcceleratorSource.ASH, newDeskAction);
+      assertEquals(2, newDeskLookup.length);
+      assertEquals(
+          JSON.stringify(overridenAccel),
+          JSON.stringify(newDeskLookup[1]!.accelerator));
+
+      // Replacing a default accelerator should not remove it but rather disable
+      // it.
+      const snapWindowRightLookup = getManager().getAccelerators(
+          AcceleratorSource.ASH, snapWindowRightAction);
+      assertEquals(1, snapWindowRightLookup.length);
+      assertEquals(
+          AcceleratorState.DISABLED_BY_USER, snapWindowRightLookup[0]!.state);
+    });
+  });
+
+  test('RemoveDefaultAccelerator', () => {
+    getProvider().setFakeAcceleratorConfig(fakeAcceleratorConfig);
+    return getProvider().getAllAcceleratorConfig().then((result) => {
+      assertDeepEquals(fakeAcceleratorConfig, result);
+
+      getManager().setAcceleratorLookup(result);
+
+      // Get Snap Window Right accelerator from kAsh[1].
+      const expectedAction = 1;
+
+      // Initially there is only one accelerator for Snap Window Right.
+      const lookup =
+          getManager().getAccelerators(AcceleratorSource.ASH, expectedAction);
+      assertEquals(1, lookup.length);
+
+      // Remove the accelerator.
+      const removedAccelerator = lookup[0]!.accelerator;
+      getManager().removeAccelerator(
+          AcceleratorSource.ASH, expectedAction, removedAccelerator);
+
+      // Removing a default accelerator only disables it.
+      assertEquals(1, lookup.length);
+      assertEquals(AcceleratorState.DISABLED_BY_USER, lookup[0]!.state);
+
+      // Removed accelerator should not appear in the reverse lookup.
+      assertEquals(
+          undefined,
+          getManager().getAcceleratorFromKeys(
+              JSON.stringify(removedAccelerator)));
+    });
+  });
+
+  test('AddAndRemoveAccelerator', () => {
+    getProvider().setFakeAcceleratorConfig(fakeAcceleratorConfig);
+    return getProvider().getAllAcceleratorConfig().then((result) => {
+      assertDeepEquals(fakeAcceleratorConfig, result);
+
+      getManager().setAcceleratorLookup(result);
+
+      // Get Snap Window Right accelerator from kAsh[1]!.
+      const expectedAction = 1;
+
+      // Initially there is only one accelerator for Snap Window Right.
+      const lookup =
+          getManager().getAccelerators(AcceleratorSource.ASH, expectedAction);
+      assertEquals(1, lookup.length);
+
+      const expectedNewAccel = /** @type {!AcceleratorKeys} */ ({
+        modifiers: Modifier.CONTROL,
+        key: 79,
+        keyDisplay: 'o',
+      });
+
+      // Sanity check that new accel is not in the reverse lookup.
+      assertEquals(
+          undefined,
+          getManager().getAcceleratorFromKeys(
+              JSON.stringify(expectedNewAccel)));
+
+      addAndVerify(AcceleratorSource.ASH, expectedAction, expectedNewAccel);
+
+      // Check that the accelerator got updated in the lookup.
+      assertEquals(2, lookup.length);
+      assertEquals(
+          JSON.stringify(expectedNewAccel),
+          JSON.stringify(lookup[1]!.accelerator));
+
+      // Remove the accelerator.
+      const removedAccelerator = lookup[1]!.accelerator;
+      getManager().removeAccelerator(
+          AcceleratorSource.ASH, expectedAction, removedAccelerator);
+
+      // Expect only 1 accelerator.
+      assertEquals(1, lookup.length);
+
+      // Removed accelerator should not appear in the reverse lookup.
+      assertEquals(
+          undefined,
+          getManager().getAcceleratorFromKeys(
+              JSON.stringify(removedAccelerator)));
+    });
+  });
+});
\ No newline at end of file
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_row_test.js b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_row_test.js
deleted file mode 100644
index debddd9..0000000
--- a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_row_test.js
+++ /dev/null
@@ -1,102 +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.
-
-import 'chrome://shortcut-customization/accelerator_row.js';
-import 'chrome://webui-test/mojo_webui_test_support.js';
-
-import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {AcceleratorRowElement} from 'chrome://shortcut-customization/accelerator_row.js';
-import {AcceleratorSource, AcceleratorState, AcceleratorType, Modifier} from 'chrome://shortcut-customization/shortcut_types.js';
-import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
-import {flushTasks} from 'chrome://webui-test/test_util.js';
-
-import {createUserAccelerator} from './shortcut_customization_test_util.js';
-
-suite('acceleratorRowTest', function() {
-  /** @type {?AcceleratorRowElement} */
-  let rowElement = null;
-
-  setup(() => {
-    rowElement = /** @type {!AcceleratorRowElement} */ (
-        document.createElement('accelerator-row'));
-    document.body.appendChild(rowElement);
-  });
-
-  teardown(() => {
-    rowElement.remove();
-    rowElement = null;
-  });
-
-  test('LoadsBasicRow', async () => {
-    const acceleratorInfo1 = createUserAccelerator(
-        Modifier.CONTROL | Modifier.SHIFT,
-        /*key=*/ 71,
-        /*keyDisplay=*/ 'g');
-
-    /** @type {!AcceleratorInfo} */
-    const acceleratorInfo2 = createUserAccelerator(
-        Modifier.CONTROL,
-        /*key=*/ 67,
-        /*keyDisplay=*/ 'c');
-
-    const accelerators = [acceleratorInfo1, acceleratorInfo2];
-    const description = 'test shortcut';
-
-    rowElement.acceleratorInfos = accelerators;
-    rowElement.description = description;
-    await flush();
-    const acceleratorElements =
-        rowElement.shadowRoot.querySelectorAll('accelerator-view');
-    assertEquals(2, acceleratorElements.length);
-    assertEquals(
-        description,
-        rowElement.shadowRoot.querySelector('#descriptionText')
-            .textContent.trim());
-
-    const keys1 =
-        acceleratorElements[0].shadowRoot.querySelectorAll('input-key');
-    // SHIFT + CONTROL + g
-    assertEquals(3, keys1.length);
-    assertEquals(
-        'shift', keys1[0].shadowRoot.querySelector('#key').textContent.trim());
-    assertEquals(
-        'ctrl', keys1[1].shadowRoot.querySelector('#key').textContent.trim());
-    assertEquals(
-        'g', keys1[2].shadowRoot.querySelector('#key').textContent.trim());
-
-    const keys2 =
-        acceleratorElements[1].shadowRoot.querySelectorAll('input-key');
-    // CONTROL + c
-    assertEquals(2, keys2.length);
-    assertEquals(
-        'ctrl', keys2[0].shadowRoot.querySelector('#key').textContent.trim());
-    assertEquals(
-        'c', keys2[1].shadowRoot.querySelector('#key').textContent.trim());
-  });
-
-  test('LockIcon', async () => {
-    const acceleratorInfo1 = createUserAccelerator(
-        Modifier.CONTROL | Modifier.SHIFT,
-        /*key=*/ 71,
-        /*keyDisplay=*/ 'g');
-
-    const accelerators = [acceleratorInfo1];
-    const description = 'test shortcut';
-
-    rowElement.acceleratorInfos = accelerators;
-    rowElement.description = description;
-    rowElement.source = AcceleratorSource.BROWSER;
-    await flushTasks();
-
-    // Expected the lock icon to appear if the source is kBrowser.
-    assertFalse(
-        rowElement.shadowRoot.querySelector('#lockIconContainer').hidden);
-
-    // Update source to be kAsh, lock icon should no longer appear.
-    rowElement.source = AcceleratorSource.ASH;
-    await flushTasks();
-    assertTrue(
-        rowElement.shadowRoot.querySelector('#lockIconContainer').hidden);
-  });
-});
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_row_test.ts b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_row_test.ts
new file mode 100644
index 0000000..09e6b732
--- /dev/null
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_row_test.ts
@@ -0,0 +1,112 @@
+// 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 'chrome://shortcut-customization/accelerator_row.js';
+import 'chrome://webui-test/mojo_webui_test_support.js';
+
+import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {AcceleratorRowElement} from 'chrome://shortcut-customization/accelerator_row.js';
+import {InputKeyElement} from 'chrome://shortcut-customization/input_key.js';
+import {AcceleratorSource, Modifier} from 'chrome://shortcut-customization/shortcut_types.js';
+import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
+import {flushTasks} from 'chrome://webui-test/test_util.js';
+
+import {createUserAccelerator} from './shortcut_customization_test_util.js';
+
+suite('acceleratorRowTest', function() {
+  let rowElement: AcceleratorRowElement|null = null;
+
+  setup(() => {
+    rowElement = document.createElement('accelerator-row');
+    document.body.appendChild(rowElement);
+  });
+
+  teardown(() => {
+    if (rowElement) {
+      rowElement.remove();
+    }
+    rowElement = null;
+  });
+
+  //   function getInputKey() {
+
+  //   }
+
+  test('LoadsBasicRow', async () => {
+    const acceleratorInfo1 = createUserAccelerator(
+        Modifier.CONTROL | Modifier.SHIFT,
+        /*key=*/ 71,
+        /*keyDisplay=*/ 'g');
+
+    const acceleratorInfo2 = createUserAccelerator(
+        Modifier.CONTROL,
+        /*key=*/ 67,
+        /*keyDisplay=*/ 'c');
+
+    const accelerators = [acceleratorInfo1, acceleratorInfo2];
+    const description = 'test shortcut';
+
+    rowElement!.acceleratorInfos = accelerators;
+    rowElement!.description = description;
+    await flush();
+    const acceleratorElements =
+        rowElement!.shadowRoot!.querySelectorAll('accelerator-view');
+    assertEquals(2, acceleratorElements.length);
+    assertEquals(
+        description,
+        rowElement!.shadowRoot!.querySelector(
+                                   '#descriptionText')!.textContent!.trim());
+
+    const keys1: NodeListOf<InputKeyElement> =
+        acceleratorElements[0]!.shadowRoot!.querySelectorAll('input-key');
+    // SHIFT + CONTROL + g
+    assertEquals(3, keys1.length);
+    assertEquals(
+        'shift',
+        keys1[0]!.shadowRoot!.querySelector('#key')!.textContent!.trim());
+    assertEquals(
+        'ctrl',
+        keys1[1]!.shadowRoot!.querySelector('#key')!.textContent!.trim());
+    assertEquals(
+        'g', keys1[2]!.shadowRoot!.querySelector('#key')!.textContent!.trim());
+
+    const keys2 =
+        acceleratorElements[1]!.shadowRoot!.querySelectorAll('input-key');
+    // CONTROL + c
+    assertEquals(2, keys2.length);
+    assertEquals(
+        'ctrl',
+        keys2[0]!.shadowRoot!.querySelector('#key')!.textContent!.trim());
+    assertEquals(
+        'c', keys2[1]!.shadowRoot!.querySelector('#key')!.textContent!.trim());
+  });
+
+  test('LockIcon', async () => {
+    const acceleratorInfo1 = createUserAccelerator(
+        Modifier.CONTROL | Modifier.SHIFT,
+        /*key=*/ 71,
+        /*keyDisplay=*/ 'g');
+
+    const accelerators = [acceleratorInfo1];
+    const description = 'test shortcut';
+
+    rowElement!.acceleratorInfos = accelerators;
+    rowElement!.description = description;
+    rowElement!.source = AcceleratorSource.BROWSER;
+    await flushTasks();
+
+    // Expected the lock icon to appear if the source is kBrowser.
+    let lockItemContainer = rowElement!.shadowRoot!.querySelector(
+                                '#lockIconContainer') as HTMLDivElement;
+    assertFalse(lockItemContainer.hidden);
+
+    // Update source to be kAsh, lock icon should no longer appear.
+    rowElement!.source = AcceleratorSource.ASH;
+    await flushTasks();
+    lockItemContainer = rowElement!.shadowRoot!.querySelector(
+                            '#lockIconContainer') as HTMLDivElement;
+
+    assertTrue(lockItemContainer.hidden);
+  });
+});
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_subsection_test.js b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_subsection_test.ts
similarity index 64%
rename from chrome/test/data/webui/chromeos/shortcut_customization/accelerator_subsection_test.js
rename to chrome/test/data/webui/chromeos/shortcut_customization/accelerator_subsection_test.ts
index 4288035..797010c 100644
--- a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_subsection_test.js
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_subsection_test.ts
@@ -9,45 +9,42 @@
 import {AcceleratorLookupManager} from 'chrome://shortcut-customization/accelerator_lookup_manager.js';
 import {AcceleratorSubsectionElement} from 'chrome://shortcut-customization/accelerator_subsection.js';
 import {fakeAcceleratorConfig, fakeLayoutInfo} from 'chrome://shortcut-customization/fake_data.js';
-import {Modifier} from 'chrome://shortcut-customization/shortcut_types.js';
+import {AcceleratorSource, Modifier} from 'chrome://shortcut-customization/shortcut_types.js';
 import {assertEquals} from 'chrome://webui-test/chai_assert.js';
 import {flushTasks} from 'chrome://webui-test/test_util.js';
 
 import {createUserAccelerator} from './shortcut_customization_test_util.js';
 
 suite('acceleratorSubsectionTest', function() {
-  /** @type {?AcceleratorSubsectionElement} */
-  let sectionElement = null;
+  let sectionElement: AcceleratorSubsectionElement|null = null;
 
-  /** @type {?AcceleratorLookupManager} */
-  let manager = null;
+  let manager: AcceleratorLookupManager|null = null;
 
   setup(() => {
     manager = AcceleratorLookupManager.getInstance();
-    manager.setAcceleratorLookup(fakeAcceleratorConfig);
-    manager.setAcceleratorLayoutLookup(fakeLayoutInfo);
+    manager!.setAcceleratorLookup(fakeAcceleratorConfig);
+    manager!.setAcceleratorLayoutLookup(fakeLayoutInfo);
 
-    sectionElement = /** @type {!AcceleratorSubsectionElement} */ (
-        document.createElement('accelerator-subsection'));
+    sectionElement = document.createElement('accelerator-subsection');
     document.body.appendChild(sectionElement);
   });
 
   teardown(() => {
-    manager.reset();
-    sectionElement.remove();
+    if (manager) {
+      manager!.reset();
+    }
+    sectionElement!.remove();
     sectionElement = null;
   });
 
   // TODO(jimmyxgong): Update this test after retrieving accelerators is
   // implemented for a subsection.
   test('LoadsBasicSection', async () => {
-    /** @type {!AcceleratorInfo} */
     const acceleratorInfo1 = createUserAccelerator(
         Modifier.CONTROL | Modifier.SHIFT,
         /*key=*/ 71,
         /*keyDisplay=*/ 'g');
 
-    /** @type {!AcceleratorInfo} */
     const acceleratorInfo2 = createUserAccelerator(
         Modifier.CONTROL | Modifier.SHIFT,
         /*key=*/ 67,
@@ -57,36 +54,39 @@
     const description = 'test shortcut';
     const title = 'test title';
 
-    sectionElement.title = title;
-    sectionElement.acceleratorContainer = [{
+    sectionElement!.title = title;
+    sectionElement!.acceleratorContainer = [{
       description: description,
       acceleratorInfos: accelerators,
+      source: AcceleratorSource.ASH,
+      action: 0,
     }];
 
     await flush();
     assertEquals(
         title,
-        sectionElement.shadowRoot.querySelector('#title').textContent.trim());
+        sectionElement!.shadowRoot!.querySelector(
+                                       '#title')!.textContent!.trim());
   });
 
   test('LoadCategoryAndConfirmDescriptions', async () => {
     const expectedTitle = 'test title';
-    sectionElement.title = expectedTitle;
-    sectionElement.category = /*Chromeos*/ 0;
-    sectionElement.subcategory = /*Window Management*/ 0;
+    sectionElement!.title = expectedTitle;
+    sectionElement!.category = /*Chromeos*/ 0;
+    sectionElement!.subcategory = /*Window Management*/ 0;
 
     await flushTasks();
 
     const rowListElement =
-        sectionElement.shadowRoot.querySelectorAll('accelerator-row');
+        sectionElement!.shadowRoot!.querySelectorAll('accelerator-row');
 
     // First accelerator-row corresponds to 'Snap Window Left'.
     assertEquals(
-        manager.getAcceleratorName(/*source=*/ 0, /*action=*/ 0),
-        rowListElement[0].description);
+        manager!.getAcceleratorName(/*source=*/ 0, /*action=*/ 0)!,
+        rowListElement[0]!.description);
     // Second accelerator-row corresponds to 'Snap Window Right'.
     assertEquals(
-        manager.getAcceleratorName(/*source=*/ 0, /*action=*/ 1),
-        rowListElement[1].description);
+        manager!.getAcceleratorName(/*source=*/ 0, /*action=*/ 1)!,
+        rowListElement[1]!.description);
   });
 });
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_view_test.js b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_view_test.js
deleted file mode 100644
index 9c537d88..0000000
--- a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_view_test.js
+++ /dev/null
@@ -1,113 +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.
-
-import 'chrome://shortcut-customization/accelerator_view.js';
-import 'chrome://webui-test/mojo_webui_test_support.js';
-
-import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {AcceleratorLookupManager} from 'chrome://shortcut-customization/accelerator_lookup_manager.js';
-import {AcceleratorViewElement, ViewState} from 'chrome://shortcut-customization/accelerator_view.js';
-import {fakeAcceleratorConfig, fakeLayoutInfo} from 'chrome://shortcut-customization/fake_data.js';
-import {AcceleratorSource, AcceleratorState, AcceleratorType, Modifier} from 'chrome://shortcut-customization/shortcut_types.js';
-import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
-
-import {createDefaultAccelerator, createUserAccelerator} from './shortcut_customization_test_util.js';
-
-suite('acceleratorViewTest', function() {
-  /** @type {?AcceleratorViewElement} */
-  let viewElement = null;
-
-  /** @type {?AcceleratorLookupManager} */
-  let manager = null;
-
-  setup(() => {
-    manager = AcceleratorLookupManager.getInstance();
-    manager.setAcceleratorLookup(fakeAcceleratorConfig);
-    manager.setAcceleratorLayoutLookup(fakeLayoutInfo);
-
-    viewElement = /** @type {!AcceleratorViewElement} */ (
-        document.createElement('accelerator-view'));
-    document.body.appendChild(viewElement);
-  });
-
-  teardown(() => {
-    manager.reset();
-
-    viewElement.remove();
-    viewElement = null;
-  });
-
-  test('LoadsBasicAccelerator', async () => {
-    /** @type {!AcceleratorInfo} */
-    const acceleratorInfo = createUserAccelerator(
-        Modifier.CONTROL | Modifier.SHIFT,
-        /*key=*/ 71,
-        /*keyDisplay=*/ 'g');
-
-
-    viewElement.acceleratorInfo = acceleratorInfo;
-    await flush();
-    const keys = viewElement.shadowRoot.querySelectorAll('input-key');
-    // Three keys: shift, control, g
-    assertEquals(3, keys.length);
-
-    assertEquals(
-        'shift', keys[0].shadowRoot.querySelector('#key').textContent.trim());
-    assertEquals(
-        'ctrl', keys[1].shadowRoot.querySelector('#key').textContent.trim());
-    assertEquals(
-        'g', keys[2].shadowRoot.querySelector('#key').textContent.trim());
-  });
-
-  test('EditableAccelerator', async () => {
-    /** @type {!AcceleratorInfo} */
-    const acceleratorInfo = createDefaultAccelerator(
-        Modifier.ALT,
-        /*key=*/ 221,
-        /*keyDisplay=*/ ']');
-
-    viewElement.acceleratorInfo = acceleratorInfo;
-    viewElement.source = AcceleratorSource.ASH;
-    viewElement.action = 1;
-    await flush();
-    // Enable the edit view.
-    viewElement.viewState = ViewState.EDIT;
-
-    await flush();
-
-    const ctrlKey = viewElement.shadowRoot.querySelector('#ctrlKey');
-    const altKey = viewElement.shadowRoot.querySelector('#altKey');
-    const shiftKey = viewElement.shadowRoot.querySelector('#shiftKey');
-    const metaKey = viewElement.shadowRoot.querySelector('#searchKey');
-    const pendingKey = viewElement.shadowRoot.querySelector('#pendingKey');
-
-    // By default, no keys should be registered.
-    assertEquals('not-selected', ctrlKey.keyState);
-    assertEquals('not-selected', altKey.keyState);
-    assertEquals('not-selected', shiftKey.keyState);
-    assertEquals('not-selected', metaKey.keyState);
-    assertEquals('not-selected', pendingKey.keyState);
-    assertEquals('key', pendingKey.key);
-
-    // Simulate Ctrl + Alt + e.
-    viewElement.dispatchEvent(new KeyboardEvent('keydown', {
-      key: 'e',
-      keyCode: '69',
-      code: 'KeyE',
-      ctrlKey: true,
-      altKey: true,
-      shiftKey: false,
-      metaKey: false,
-    }));
-
-    await flush();
-
-    assertEquals('modifier-selected', ctrlKey.keyState);
-    assertEquals('modifier-selected', altKey.keyState);
-    assertEquals('not-selected', shiftKey.keyState);
-    assertEquals('not-selected', metaKey.keyState);
-    assertEquals('alpha-numeric-selected', pendingKey.keyState);
-    assertEquals('e', pendingKey.key);
-  });
-});
\ No newline at end of file
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_view_test.ts b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_view_test.ts
new file mode 100644
index 0000000..a8bf1b2
--- /dev/null
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_view_test.ts
@@ -0,0 +1,119 @@
+// 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 'chrome://shortcut-customization/accelerator_view.js';
+import 'chrome://webui-test/mojo_webui_test_support.js';
+
+import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {AcceleratorLookupManager} from 'chrome://shortcut-customization/accelerator_lookup_manager.js';
+import {AcceleratorViewElement, ViewState} from 'chrome://shortcut-customization/accelerator_view.js';
+import {fakeAcceleratorConfig, fakeLayoutInfo} from 'chrome://shortcut-customization/fake_data.js';
+import {InputKeyElement, KeyInputState} from 'chrome://shortcut-customization/input_key.js';
+import {AcceleratorSource, Modifier} from 'chrome://shortcut-customization/shortcut_types.js';
+import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
+
+import {createDefaultAccelerator, createUserAccelerator} from './shortcut_customization_test_util.js';
+
+suite('acceleratorViewTest', function() {
+  let viewElement: AcceleratorViewElement|null = null;
+
+  let manager: AcceleratorLookupManager|null = null;
+
+  setup(() => {
+    manager = AcceleratorLookupManager.getInstance();
+    manager.setAcceleratorLookup(fakeAcceleratorConfig);
+    manager.setAcceleratorLayoutLookup(fakeLayoutInfo);
+
+    viewElement = document.createElement('accelerator-view');
+    document.body.appendChild(viewElement);
+  });
+
+  teardown(() => {
+    if (manager) {
+      manager.reset();
+    }
+
+    viewElement!.remove();
+    viewElement = null;
+  });
+
+  function getInputKey(selector: string): InputKeyElement {
+    const element = viewElement!.shadowRoot!.querySelector(selector);
+    assertTrue(!!element);
+    return element as InputKeyElement;
+  }
+
+  test('LoadsBasicAccelerator', async () => {
+    const acceleratorInfo = createUserAccelerator(
+        Modifier.CONTROL | Modifier.SHIFT,
+        /*key=*/ 71,
+        /*keyDisplay=*/ 'g');
+
+
+    viewElement!.acceleratorInfo = acceleratorInfo;
+    await flush();
+    const keys = viewElement!.shadowRoot!.querySelectorAll('input-key');
+    // Three keys: shift, control, g
+    assertEquals(3, keys.length);
+
+    assertEquals(
+        'shift',
+        keys[0]!.shadowRoot!.querySelector('#key')!.textContent!.trim());
+    assertEquals(
+        'ctrl',
+        keys[1]!.shadowRoot!.querySelector('#key')!.textContent!.trim());
+    assertEquals(
+        'g', keys[2]!.shadowRoot!.querySelector('#key')!.textContent!.trim());
+  });
+
+  test('EditableAccelerator', async () => {
+    const acceleratorInfo = createDefaultAccelerator(
+        Modifier.ALT,
+        /*key=*/ 221,
+        /*keyDisplay=*/ ']');
+
+    viewElement!.acceleratorInfo = acceleratorInfo;
+    viewElement!.source = AcceleratorSource.ASH;
+    viewElement!.action = 1;
+    await flush();
+    // Enable the edit view.
+    viewElement!.viewState = ViewState.EDIT;
+
+    await flush();
+
+    const ctrlKey = getInputKey('#ctrlKey');
+    const altKey = getInputKey('#altKey');
+    const shiftKey = getInputKey('#shiftKey');
+    const metaKey = getInputKey('#searchKey');
+    const pendingKey = getInputKey('#pendingKey');
+
+    // By default, no keys should be registered.
+    assertEquals(KeyInputState.NOT_SELECTED, ctrlKey.keyState);
+    assertEquals(KeyInputState.NOT_SELECTED, altKey.keyState);
+    assertEquals(KeyInputState.NOT_SELECTED, shiftKey.keyState);
+    assertEquals(KeyInputState.NOT_SELECTED, metaKey.keyState);
+    assertEquals(KeyInputState.NOT_SELECTED, pendingKey.keyState);
+    assertEquals('key', pendingKey.key);
+
+    // Simulate Ctrl + Alt + e.
+    viewElement!.dispatchEvent(new KeyboardEvent('keydown', {
+      key: 'e',
+      keyCode: 69,
+      code: 'KeyE',
+      ctrlKey: true,
+      altKey: true,
+      shiftKey: false,
+      metaKey: false,
+    }));
+
+    await flush();
+
+    assertEquals('modifier-selected', ctrlKey.keyState);
+    assertEquals('modifier-selected', altKey.keyState);
+    assertEquals('not-selected', shiftKey.keyState);
+    assertEquals('not-selected', metaKey.keyState);
+    assertEquals('alpha-numeric-selected', pendingKey.keyState);
+    assertEquals('e', pendingKey.key);
+  });
+});
\ No newline at end of file
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/fake_shortcut_provider_test.js b/chrome/test/data/webui/chromeos/shortcut_customization/fake_shortcut_provider_test.js
deleted file mode 100644
index 0d83aea..0000000
--- a/chrome/test/data/webui/chromeos/shortcut_customization/fake_shortcut_provider_test.js
+++ /dev/null
@@ -1,136 +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.
-
-import 'chrome://webui-test/mojo_webui_test_support.js';
-
-import {fakeAcceleratorConfig, fakeLayoutInfo} from 'chrome://shortcut-customization/fake_data.js';
-import {FakeShortcutProvider} from 'chrome://shortcut-customization/fake_shortcut_provider.js';
-import {AcceleratorConfigResult, AcceleratorSource, Modifier} from 'chrome://shortcut-customization/shortcut_types.js';
-import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
-
-suite('fakeShortcutProviderTest', function() {
-  /** @type {?FakeShortcutProvider} */
-  let provider = null;
-
-  setup(() => {
-    provider = new FakeShortcutProvider();
-  });
-
-  teardown(() => {
-    provider = null;
-  });
-
-  test('GetAllAcceleratorConfigEmpty', () => {
-    /** @type {!AcceleratorConfig} */
-    const expected = new Map();
-    provider.setFakeAcceleratorConfig(expected);
-    return provider.getAllAcceleratorConfig().then((result) => {
-      assertDeepEquals(expected, result);
-    });
-  });
-
-  test('GetAllAcceleratorConfigDefaultFake', () => {
-    // TODO(zentaro): Remove this test once real data is ready.
-    const expected = new Map();
-    provider.setFakeAcceleratorConfig(fakeAcceleratorConfig);
-    return provider.getAllAcceleratorConfig().then((result) => {
-      assertDeepEquals(fakeAcceleratorConfig, result);
-    });
-  });
-
-  test('GetLayoutInfoEmpty', () => {
-    /** @type {!LayoutInfoList} */
-    const expected = [];
-    provider.setFakeLayoutInfo(expected);
-    return provider.getLayoutInfo().then((result) => {
-      assertDeepEquals(expected, result);
-    });
-  });
-
-  test('GetLayoutInfoDefaultFake', () => {
-    // TODO(zentaro): Remove this test once real data is ready.
-    provider.setFakeLayoutInfo(fakeLayoutInfo);
-    return provider.getLayoutInfo().then((result) => {
-      assertDeepEquals(fakeLayoutInfo, result);
-    });
-  });
-
-  test('IsMutableDefaultFake', () => {
-    // TODO(jimmyxgong): Remove this test once real data is ready.
-    // AcceleratorSource.ASH is a mutable source.
-    return provider.isMutable(AcceleratorSource.ASH).then((result) => {
-      assertTrue(result);
-      // AcceleratorSource.BROWSER is not a mutable source
-      return provider.isMutable(AcceleratorSource.BROWSER).then((result) => {
-        assertFalse(result);
-      });
-    });
-  });
-
-  test('AddUserAcceleratorFake', () => {
-    // TODO(jimmyxgong): Remove this test once real data is ready.
-    const acceleratorKeys = /** @type {!AcceleratorKeys} */ ({
-      modifiers: Modifier.SHIFT,
-      key: 79,
-      keyDisplay: 'o',
-    });
-    return provider
-        .addUserAccelerator(
-            AcceleratorSource.ASH, /**action=*/ 0, acceleratorKeys)
-        .then((result) => {
-          assertEquals(AcceleratorConfigResult.SUCCESS, result);
-        });
-  });
-
-  test('ReplaceAcceleratorFake', () => {
-    // TODO(jimmyxgong): Remove this test once real data is ready.
-    const oldAcceleratorKeys = /** @type {!AcceleratorKeys} */ ({
-      modifiers: Modifier.SHIFT,
-      key: 79,
-      keyDisplay: 'o',
-    });
-
-    const newAcceleratorKeys = /** @type {!AcceleratorKeys} */ ({
-      modifiers: Modifier.SHIFT,
-      key: 80,
-      keyDisplay: 'p',
-    });
-
-    return provider
-        .replaceAccelerator(
-            AcceleratorSource.ASH, /**action=*/ 0, oldAcceleratorKeys,
-            newAcceleratorKeys)
-        .then((result) => {
-          assertEquals(AcceleratorConfigResult.SUCCESS, result);
-        });
-  });
-
-  test('RemoveAcceleratorFake', () => {
-    // TODO(jimmyxgong): Remove this test once real data is ready.
-    const accel = /** @type {!AcceleratorKeys} */ ({
-      modifiers: Modifier.SHIFT,
-      key: 79,
-      keyDisplay: 'o',
-    });
-
-    return provider
-        .removeAccelerator(AcceleratorSource.ASH, /**action=*/ 0, accel)
-        .then((result) => {
-          assertEquals(AcceleratorConfigResult.SUCCESS, result);
-        });
-  });
-
-  test('RestoreAllDefaultsFake', () => {
-    return provider.restoreAllDefaults().then((result) => {
-      assertEquals(AcceleratorConfigResult.SUCCESS, result);
-    });
-  });
-
-  test('RestoreActionDefaultsFake', () => {
-    return provider.restoreActionDefaults(AcceleratorSource.ASH, 0)
-        .then((result) => {
-          assertEquals(AcceleratorConfigResult.SUCCESS, result);
-        });
-  });
-});
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/fake_shortcut_provider_test.ts b/chrome/test/data/webui/chromeos/shortcut_customization/fake_shortcut_provider_test.ts
new file mode 100644
index 0000000..d2b98cb
--- /dev/null
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/fake_shortcut_provider_test.ts
@@ -0,0 +1,105 @@
+// 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 'chrome://webui-test/mojo_webui_test_support.js';
+
+import {fakeAcceleratorConfig, fakeLayoutInfo} from 'chrome://shortcut-customization/fake_data.js';
+import {FakeShortcutProvider} from 'chrome://shortcut-customization/fake_shortcut_provider.js';
+import {AcceleratorConfigResult, AcceleratorSource, LayoutInfoList} from 'chrome://shortcut-customization/shortcut_types.js';
+import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
+
+suite('fakeShortcutProviderTest', function() {
+  let provider: FakeShortcutProvider|null = null;
+
+  setup(() => {
+    provider = new FakeShortcutProvider();
+  });
+
+  teardown(() => {
+    provider = null;
+  });
+
+  function getProvider(): FakeShortcutProvider {
+    assertTrue(!!provider);
+    return provider as FakeShortcutProvider;
+  }
+  test('GetAllAcceleratorConfigEmpty', () => {
+    const expected = new Map();
+    getProvider().setFakeAcceleratorConfig(expected);
+    return getProvider().getAllAcceleratorConfig().then((result) => {
+      assertDeepEquals(expected, result);
+    });
+  });
+
+  test('GetAllAcceleratorConfigDefaultFake', () => {
+    // TODO(zentaro): Remove this test once real data is ready.
+    getProvider().setFakeAcceleratorConfig(fakeAcceleratorConfig);
+    return getProvider().getAllAcceleratorConfig().then((result) => {
+      assertDeepEquals(fakeAcceleratorConfig, result);
+    });
+  });
+
+  test('GetLayoutInfoEmpty', () => {
+    const expected: LayoutInfoList = [];
+    getProvider().setFakeLayoutInfo(expected);
+    return getProvider().getLayoutInfo().then((result) => {
+      assertDeepEquals(expected, result);
+    });
+  });
+
+  test('GetLayoutInfoDefaultFake', () => {
+    // TODO(zentaro): Remove this test once real data is ready.
+    getProvider().setFakeLayoutInfo(fakeLayoutInfo);
+    return getProvider().getLayoutInfo().then((result) => {
+      assertDeepEquals(fakeLayoutInfo, result);
+    });
+  });
+
+  test('IsMutableDefaultFake', () => {
+    // TODO(jimmyxgong): Remove this test once real data is ready.
+    // AcceleratorSource.ASH is a mutable source.
+    return getProvider().isMutable(AcceleratorSource.ASH).then((result) => {
+      assertTrue(result);
+      // AcceleratorSource.BROWSER is not a mutable source
+      return getProvider()
+          .isMutable(AcceleratorSource.BROWSER)
+          .then((result) => {
+            assertFalse(result);
+          });
+    });
+  });
+
+  test('AddUserAcceleratorFake', () => {
+    // TODO(jimmyxgong): Remove this test once real data is ready.
+    return getProvider().addUserAccelerator().then((result) => {
+      assertEquals(AcceleratorConfigResult.SUCCESS, result);
+    });
+  });
+
+  test('ReplaceAcceleratorFake', () => {
+    // TODO(jimmyxgong): Remove this test once real data is ready.
+    return getProvider().replaceAccelerator().then((result) => {
+      assertEquals(AcceleratorConfigResult.SUCCESS, result);
+    });
+  });
+
+  test('RemoveAcceleratorFake', () => {
+    // TODO(jimmyxgong): Remove this test once real data is ready.
+    return getProvider().removeAccelerator().then((result) => {
+      assertEquals(AcceleratorConfigResult.SUCCESS, result);
+    });
+  });
+
+  test('RestoreAllDefaultsFake', () => {
+    return getProvider().restoreAllDefaults().then((result) => {
+      assertEquals(AcceleratorConfigResult.SUCCESS, result);
+    });
+  });
+
+  test('RestoreActionDefaultsFake', () => {
+    return getProvider().restoreActionDefaults().then((result) => {
+      assertEquals(AcceleratorConfigResult.SUCCESS, result);
+    });
+  });
+});
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.js b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.js
deleted file mode 100644
index bb93cc36..0000000
--- a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.js
+++ /dev/null
@@ -1,371 +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.
-
-import 'chrome://shortcut-customization/shortcut_customization_app.js';
-import 'chrome://webui-test/mojo_webui_test_support.js';
-
-import {AcceleratorLookupManager} from 'chrome://shortcut-customization/accelerator_lookup_manager.js';
-import {AcceleratorSubsectionElement} from 'chrome://shortcut-customization/accelerator_subsection.js';
-import {fakeAcceleratorConfig, fakeLayoutInfo, fakeSubCategories} from 'chrome://shortcut-customization/fake_data.js';
-import {getShortcutProvider, setShortcutProviderForTesting} from 'chrome://shortcut-customization/mojo_interface_provider.js';
-import {ShortcutCustomizationAppElement} from 'chrome://shortcut-customization/shortcut_customization_app.js';
-import {Modifier} from 'chrome://shortcut-customization/shortcut_types.js';
-import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
-import {flushTasks} from 'chrome://webui-test/test_util.js';
-
-import {createUserAccelerator} from './shortcut_customization_test_util.js';
-
-suite('shortcutCustomizationAppTest', function() {
-  /** @type {?ShortcutCustomizationAppElement} */
-  let page = null;
-
-  /** @type {?AcceleratorLookupManager} */
-  let manager = null;
-
-  setup(() => {
-    manager = AcceleratorLookupManager.getInstance();
-
-    page = /** @type {!ShortcutCustomizationAppElement} */ (
-        document.createElement('shortcut-customization-app'));
-    document.body.appendChild(page);
-  });
-
-  teardown(() => {
-    manager.reset();
-    page.remove();
-    page = null;
-  });
-
-  /**
-   * @param {string} subpageId
-   * @return {!Array<!AcceleratorSubsectionElement>}
-   */
-  function getSubsections(subpageId) {
-    const navPanel = page.shadowRoot.querySelector('navigation-view-panel');
-    const navBody = navPanel.shadowRoot.querySelector('#navigationBody');
-    const subPage = navBody.querySelector(`#${subpageId}`);
-    return subPage.shadowRoot.querySelectorAll('accelerator-subsection');
-  }
-
-  /**
-   * @param {number} subsectionIndex
-   */
-  async function openDialogForAcceleratorInSubsection(subsectionIndex) {
-    // The edit dialog should not be stamped and visible.
-    const editDialog = page.shadowRoot.querySelector('#editDialog');
-    assertFalse(!!editDialog);
-
-    const subSections = getSubsections('chromeos-page-id');
-    const accelerators =
-        subSections[subsectionIndex].shadowRoot.querySelectorAll(
-            'accelerator-row');
-
-    // Click on the first accelerator, expect the edit dialog to open.
-    accelerators[0].click();
-    await flushTasks();
-  }
-
-  test('LoadFakeChromeOSPage', async () => {
-    await flushTasks();
-
-    const subSections = getSubsections('chromeos-page-id');
-    const expectedLayouts = manager.getSubcategories(/**ChromeOS*/ 0);
-    // Two subsections for ChromeOS (Window Management + Virtual Desks).
-    assertEquals(expectedLayouts.size, subSections.length);
-
-    const keyIterator = expectedLayouts.keys();
-    // Assert subsection title (Window management) matches expected value from
-    // fake lookup.
-    const windowManagementValue = keyIterator.next().value;
-    assertEquals(
-        fakeSubCategories.get(windowManagementValue), subSections[0].title);
-    // Asert 2 accelerators are loaded for Window Management.
-    assertEquals(
-        expectedLayouts.get(windowManagementValue).length,
-        subSections[0].acceleratorContainer.length);
-
-    // Assert subsection title (Virtual Desks) matches expected value from
-    // fake lookup.
-    const virtualDesksValue = keyIterator.next().value;
-    assertEquals(
-        fakeSubCategories.get(virtualDesksValue), subSections[1].title);
-    // Asert 2 accelerators are loaded for Virtual Desks.
-    assertEquals(
-        expectedLayouts.get(virtualDesksValue).length,
-        subSections[1].acceleratorContainer.length);
-  });
-
-  test('LoadFakeBrowserPage', async () => {
-    await flushTasks();
-
-    const navPanel = page.shadowRoot.querySelector('navigation-view-panel');
-    const navSelector = navPanel.shadowRoot.querySelector('#navigationSelector')
-                            .querySelector('navigation-selector');
-    const navMenuItems =
-        navSelector.shadowRoot.querySelector('#navigationSelectorMenu')
-            .querySelectorAll('.navigation-item');
-    // Index[1] represents the Browser subpage.
-    navMenuItems[1].click();
-
-    await flushTasks();
-
-    const subSections = getSubsections('browser-page-id');
-    const expectedLayouts = manager.getSubcategories(/**Browser*/ 1);
-    // One subsection for the Browser (Tabs).
-    assertEquals(expectedLayouts.size, subSections.length);
-
-    const keyIterator = expectedLayouts.keys().next();
-    // Assert subsection names match name lookup (Tabs).
-    assertEquals(
-        fakeSubCategories.get(keyIterator.value), subSections[0].title);
-    // Assert only 1 accelerator is within Tabs.
-    assertEquals(
-        expectedLayouts.get(keyIterator.value).length,
-        subSections[0].acceleratorContainer.length);
-  });
-
-  test('OpenDialogFromAccelerator', async () => {
-    await flushTasks();
-
-    // The edit dialog should not be stamped and visible.
-    let editDialog = page.shadowRoot.querySelector('#editDialog');
-    assertFalse(!!editDialog);
-
-    const subSections = getSubsections('chromeos-page-id');
-    const accelerators =
-        subSections[0].shadowRoot.querySelectorAll('accelerator-row');
-    // Only two accelerators rows for "Window Management".
-    assertEquals(2, accelerators.length);
-    // Click on the first accelerator, expect the edit dialog to open.
-    accelerators[0].click();
-    await flushTasks();
-    editDialog = page.shadowRoot.querySelector('#editDialog');
-    assertTrue(!!editDialog);
-  });
-
-  test('DialogOpensOnEvent', async () => {
-    await flushTasks();
-
-    // The edit dialog should not be stamped and visible.
-    let editDialog = page.shadowRoot.querySelector('#editDialog');
-    assertFalse(!!editDialog);
-
-    const nav = page.shadowRoot.querySelector('navigation-view-panel');
-
-    /** @type {!AcceleratorInfo} */
-    const acceleratorInfo = createUserAccelerator(
-        Modifier.SHIFT,
-        /*key=*/ 67,
-        /*keyDisplay=*/ 'c');
-
-    // Simulate the trigger event to display the dialog.
-    nav.dispatchEvent(new CustomEvent('show-edit-dialog', {
-      bubbles: true,
-      composed: true,
-      detail: /**@type {!Object}*/ (
-          {description: 'test', accelerators: [acceleratorInfo]}),
-    }));
-    await flushTasks();
-
-    // Requery dialog.
-    editDialog = page.shadowRoot.querySelector('#editDialog');
-    assertTrue(!!editDialog);
-
-    // Close the dialog.
-    const dialog = editDialog.shadowRoot.querySelector('#editDialog');
-    dialog.close();
-    await flushTasks();
-
-    assertFalse(dialog.open);
-  });
-
-  test('ReplaceAccelerator', async () => {
-    await flushTasks();
-
-    // Open dialog for first accelerator in View Desk subsection.
-    await openDialogForAcceleratorInSubsection(/*View Desk*/ 1);
-    const editDialog = page.shadowRoot.querySelector('#editDialog');
-    assertTrue(!!editDialog);
-
-    // Grab the first accelerator from Virtual Desks subsection.
-    let editView = editDialog.shadowRoot.querySelector('cr-dialog')
-                       .querySelectorAll('accelerator-edit-view')[0];
-
-    // Click on edit button.
-    editView.shadowRoot.querySelector('#editButton').click();
-
-    await flushTasks();
-
-    let accelViewElement =
-        editView.shadowRoot.querySelector('#acceleratorItem');
-
-    // Assert no error has occurred prior to pressing a shortcut.
-    assertFalse(editView.hasError);
-
-    // Alt + ']' is a conflict, expect the error message to appear.
-    accelViewElement.dispatchEvent(new KeyboardEvent('keydown', {
-      key: ']',
-      keyCode: '221',
-      code: 'Key]',
-      ctrlKey: false,
-      altKey: true,
-      shiftKey: false,
-      metaKey: false,
-    }));
-
-    await flushTasks();
-
-    assertTrue(editView.hasError);
-
-    // Press the shortcut again, this time it will replace the preexsting
-    // accelerator.
-    accelViewElement.dispatchEvent(new KeyboardEvent('keydown', {
-      key: ']',
-      keyCode: '221',
-      code: 'Key]',
-      ctrlKey: false,
-      altKey: true,
-      shiftKey: false,
-      metaKey: false,
-    }));
-
-    await flushTasks();
-
-    // Requery the view element.
-    editView = editDialog.shadowRoot.querySelector('cr-dialog')
-                   .querySelectorAll('accelerator-edit-view')[0];
-    accelViewElement = editView.shadowRoot.querySelector('#acceleratorItem');
-
-    // Assert that the accelerator was updated with the new shortcut (Alt + ']')
-    const actualAccelerator = accelViewElement.acceleratorInfo.accelerator;
-    assertEquals(Modifier.ALT, actualAccelerator.modifiers);
-    assertEquals(221, actualAccelerator.key);
-    assertEquals(']', actualAccelerator.keyDisplay);
-  });
-
-  test('AddAccelerator', async () => {
-    await flushTasks();
-
-    // Open dialog for first accelerator in View Desk subsection.
-    await openDialogForAcceleratorInSubsection(/*View Desk*/ 1);
-    const editDialog = page.shadowRoot.querySelector('#editDialog');
-    assertTrue(!!editDialog);
-
-    // Grab the first accelerator from Virtual Desks subsection.
-    let dialogAccels = editDialog.shadowRoot.querySelector('cr-dialog')
-                           .querySelectorAll('accelerator-edit-view');
-    // Expect only 1 accelerator initially.
-    assertEquals(1, dialogAccels.length);
-
-    // Click on add button.
-    editDialog.shadowRoot.querySelector('#addAcceleratorButton').click();
-
-    await flushTasks();
-
-    const editElement =
-        editDialog.shadowRoot.querySelector('#pendingAccelerator');
-
-    // Assert no error has occurred prior to pressing a shortcut.
-    assertFalse(editElement.hasError);
-
-    const viewElement =
-        editElement.shadowRoot.querySelector('#acceleratorItem');
-
-    // Alt + ']' is a conflict, expect the error message to appear.
-    viewElement.dispatchEvent(new KeyboardEvent('keydown', {
-      key: ']',
-      keyCode: '221',
-      code: 'Key]',
-      ctrlKey: false,
-      altKey: true,
-      shiftKey: false,
-      metaKey: false,
-    }));
-
-    await flushTasks();
-
-    assertTrue(editElement.hasError);
-
-    // Press the shortcut again, this time it will add and remove the preexsting
-    // accelerator.
-    viewElement.dispatchEvent(new KeyboardEvent('keydown', {
-      key: ']',
-      keyCode: '221',
-      code: 'Key]',
-      ctrlKey: false,
-      altKey: true,
-      shiftKey: false,
-      metaKey: false,
-    }));
-
-    await flushTasks();
-
-    // Requery all accelerators.
-    dialogAccels = editDialog.shadowRoot.querySelector('cr-dialog')
-                       .querySelectorAll('accelerator-edit-view');
-    // Expect 2 accelerators now.
-    assertEquals(2, dialogAccels.length);
-    const newAccel = dialogAccels[1];
-
-    const actualAccelerator =
-        newAccel.shadowRoot.querySelector('#acceleratorItem')
-            .acceleratorInfo.accelerator;
-    assertEquals(Modifier.ALT, actualAccelerator.modifiers);
-    assertEquals(221, actualAccelerator.key);
-    assertEquals(']', actualAccelerator.keyDisplay);
-  });
-
-  test('RemoveAccelerator', async () => {
-    await flushTasks();
-
-    // Open dialog for first accelerator in View Desk subsection.
-    await openDialogForAcceleratorInSubsection(/*View Desk*/ 1);
-    const editDialog = page.shadowRoot.querySelector('#editDialog');
-    assertTrue(!!editDialog);
-
-    // Grab the first accelerator from Virtual Desks subsection.
-    let acceleratorList = editDialog.shadowRoot.querySelector('cr-dialog')
-                              .querySelectorAll('accelerator-edit-view');
-    assertEquals(1, acceleratorList.length);
-    const editView = acceleratorList[0];
-
-    // Click on remove button.
-    editView.shadowRoot.querySelector('#deleteButton').click();
-
-    await flushTasks();
-
-    // Requery the accelerator elements.
-    acceleratorList = editDialog.shadowRoot.querySelector('cr-dialog')
-                          .querySelectorAll('accelerator-edit-view');
-
-    // Expect that the accelerator has now been removed.
-    assertEquals(0, acceleratorList.length);
-  });
-
-  test('RestoreAllButton', async () => {
-    await flushTasks();
-
-    let restoreDialog = page.shadowRoot.querySelector('#restoreDialog');
-    // Expect the dialog to not appear initially.
-    assertFalse(!!restoreDialog);
-
-    // Click on the Restore all button.
-    const restoreButton = page.shadowRoot.querySelector('#restoreAllButton');
-    restoreButton.click();
-
-    await flushTasks();
-
-    // Requery the dialog.
-    restoreDialog = page.shadowRoot.querySelector('#restoreDialog');
-    assertTrue(restoreDialog.open);
-
-    // Click on Cancel button.
-    restoreDialog.querySelector('#cancelButton').click();
-
-    await flushTasks();
-
-    restoreDialog = page.shadowRoot.querySelector('#restoreDialog');
-    assertFalse(!!restoreDialog);
-  });
-});
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.ts b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.ts
new file mode 100644
index 0000000..773db64
--- /dev/null
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.ts
@@ -0,0 +1,406 @@
+// 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 'chrome://shortcut-customization/shortcut_customization_app.js';
+import 'chrome://webui-test/mojo_webui_test_support.js';
+
+import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.js';
+import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js';
+import {AcceleratorEditViewElement} from 'chrome://shortcut-customization/accelerator_edit_view.js';
+import {AcceleratorLookupManager} from 'chrome://shortcut-customization/accelerator_lookup_manager.js';
+import {AcceleratorRowElement} from 'chrome://shortcut-customization/accelerator_row.js';
+import {AcceleratorSubsectionElement} from 'chrome://shortcut-customization/accelerator_subsection.js';
+import {AcceleratorViewElement} from 'chrome://shortcut-customization/accelerator_view.js';
+import {fakeSubCategories} from 'chrome://shortcut-customization/fake_data.js';
+import {ShortcutCustomizationAppElement} from 'chrome://shortcut-customization/shortcut_customization_app.js';
+import {AcceleratorInfo, AcceleratorKeys, LayoutInfoList, Modifier} from 'chrome://shortcut-customization/shortcut_types.js';
+import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
+import {flushTasks} from 'chrome://webui-test/test_util.js';
+
+import {createUserAccelerator} from './shortcut_customization_test_util.js';
+
+suite('shortcutCustomizationAppTest', function() {
+  let page: ShortcutCustomizationAppElement|null = null;
+
+  let manager: AcceleratorLookupManager|null = null;
+
+  setup(() => {
+    manager = AcceleratorLookupManager.getInstance();
+
+    page = document.createElement('shortcut-customization-app');
+    document.body.appendChild(page);
+  });
+
+  teardown(() => {
+    if (manager) {
+      manager.reset();
+    }
+    if (page) {
+      page.remove();
+    }
+    page = null;
+  });
+
+  function getManager(): AcceleratorLookupManager {
+    assertTrue(!!manager);
+    return manager as AcceleratorLookupManager;
+  }
+
+  function getPage(): ShortcutCustomizationAppElement {
+    assertTrue(!!page);
+    return page as ShortcutCustomizationAppElement;
+  }
+
+  function getDialog(selector: string) {
+    return getPage().shadowRoot!.querySelector(selector) as CrDialogElement;
+  }
+
+  function getSubsections(subpageId: string):
+      NodeListOf<AcceleratorSubsectionElement> {
+    const navPanel =
+        getPage().shadowRoot!.querySelector('navigation-view-panel');
+    const navBody = navPanel!!.shadowRoot!.querySelector('#navigationBody');
+    const subPage = navBody!.querySelector(`#${subpageId}`);
+    return subPage!.shadowRoot!.querySelectorAll('accelerator-subsection');
+  }
+
+  async function openDialogForAcceleratorInSubsection(subsectionIndex: number) {
+    // The edit dialog should not be stamped and visible.
+    const editDialog = getPage().shadowRoot!.querySelector('#editDialog');
+    assertFalse(!!editDialog);
+
+    const subSections = getSubsections('chromeos-page-id');
+    const accelerators =
+        subSections[subsectionIndex]!.shadowRoot!.querySelectorAll(
+            'accelerator-row') as NodeListOf<AcceleratorRowElement>;
+
+    // Click on the first accelerator, expect the edit dialog to open.
+    accelerators[0]!.click();
+    await flushTasks();
+  }
+
+  test('LoadFakeChromeOSPage', async () => {
+    await flushTasks();
+
+    const subSections = getSubsections('chromeos-page-id');
+    const expectedLayouts = getManager().getSubcategories(/**ChromeOS*/ 0);
+    // Two subsections for ChromeOS (Window Management + Virtual Desks).
+    assertEquals(expectedLayouts!.size, subSections!.length);
+
+    const keyIterator = expectedLayouts!.keys();
+    // Assert subsection title (Window management) matches expected value from
+    // fake lookup.
+    const windowManagementValue = keyIterator.next().value;
+    assertEquals(
+        (fakeSubCategories.get(windowManagementValue) as string),
+        subSections[0]!.title);
+    // Asert 2 accelerators are loaded for Window Management.
+    assertEquals(
+        (expectedLayouts!.get(windowManagementValue) as LayoutInfoList).length,
+        subSections[0]!.acceleratorContainer!.length);
+
+    // Assert subsection title (Virtual Desks) matches expected value from
+    // fake lookup.
+    const virtualDesksValue = keyIterator.next().value;
+    assertEquals(
+        fakeSubCategories.get(virtualDesksValue), subSections[1]!.title);
+    // Asert 2 accelerators are loaded for Virtual Desks.
+    assertEquals(
+        (expectedLayouts!.get(virtualDesksValue) as LayoutInfoList).length,
+        subSections[1]!.acceleratorContainer!.length);
+  });
+
+  test('LoadFakeBrowserPage', async () => {
+    await flushTasks();
+
+    const navPanel =
+        getPage().shadowRoot!.querySelector('navigation-view-panel');
+    const navSelector =
+        navPanel!.shadowRoot!.querySelector('#navigationSelector')!
+            .querySelector('navigation-selector');
+    const navMenuItems =
+        navSelector!.shadowRoot!.querySelector('#navigationSelectorMenu')!
+            .querySelectorAll('.navigation-item') as NodeListOf<HTMLDivElement>;
+    // Index[1] represents the Browser subgetPage().
+    navMenuItems[1]!.click();
+
+    await flushTasks();
+
+    const subSections = getSubsections('browser-page-id');
+    const expectedLayouts = getManager().getSubcategories(/**Browser*/ 1);
+    // One subsection for the Browser (Tabs).
+    assertEquals(expectedLayouts!.size, subSections!.length);
+
+    const keyIterator = expectedLayouts!.keys().next();
+    // Assert subsection names match name lookup (Tabs).
+    assertEquals(
+        fakeSubCategories.get(keyIterator.value), subSections[0]!.title);
+    // Assert only 1 accelerator is within Tabs.
+    assertEquals(
+        (expectedLayouts!.get(keyIterator.value) as LayoutInfoList).length,
+        subSections[0]!.acceleratorContainer.length);
+  });
+
+  test('OpenDialogFromAccelerator', async () => {
+    await flushTasks();
+
+    // The edit dialog should not be stamped and visible.
+    let editDialog = getPage().shadowRoot!.querySelector('#editDialog');
+    assertFalse(!!editDialog);
+
+    const subSections = getSubsections('chromeos-page-id');
+    const accelerators =
+        subSections[0]!.shadowRoot!.querySelectorAll('accelerator-row');
+    // Only two accelerators rows for "Window Management".
+    assertEquals(2, accelerators.length);
+    // Click on the first accelerator, expect the edit dialog to open.
+    accelerators[0]!.click();
+    await flushTasks();
+    editDialog = getPage().shadowRoot!.querySelector('#editDialog');
+    assertTrue(!!editDialog);
+  });
+
+  test('DialogOpensOnEvent', async () => {
+    await flushTasks();
+
+    // The edit dialog should not be stamped and visible.
+    let editDialog = getPage().shadowRoot!.querySelector('#editDialog');
+    assertFalse(!!editDialog);
+
+    const nav = getPage().shadowRoot!.querySelector('navigation-view-panel');
+
+    const acceleratorInfo = createUserAccelerator(
+        Modifier.SHIFT,
+        /*key=*/ 67,
+        /*keyDisplay=*/ 'c');
+
+    // Simulate the trigger event to display the dialog.
+    nav!.dispatchEvent(new CustomEvent('show-edit-dialog', {
+      bubbles: true,
+      composed: true,
+      detail: {description: 'test', accelerators: [acceleratorInfo]},
+    }));
+    await flushTasks();
+
+    // Requery dialog.
+    editDialog = getPage().shadowRoot!.querySelector('#editDialog');
+    assertTrue(!!editDialog);
+
+    // Close the dialog.
+    const dialog =
+        editDialog!.shadowRoot!.querySelector('#editDialog') as CrDialogElement;
+    dialog.close();
+    await flushTasks();
+
+    assertFalse(dialog.open);
+  });
+
+  test('ReplaceAccelerator', async () => {
+    await flushTasks();
+
+    // Open dialog for first accelerator in View Desk subsection.
+    await openDialogForAcceleratorInSubsection(/*View Desk*/ 1);
+    const editDialog = getPage().shadowRoot!.querySelector('#editDialog');
+    assertTrue(!!editDialog);
+
+    // Grab the first accelerator from Virtual Desks subsection.
+    let editView =
+        editDialog!.shadowRoot!.querySelector('cr-dialog')!.querySelectorAll(
+            'accelerator-edit-view')[0] as AcceleratorEditViewElement;
+
+    // Click on edit button.
+    (editView!.shadowRoot!.querySelector('#editButton') as CrButtonElement)
+        .click();
+
+    await flushTasks();
+
+    let accelViewElement =
+        editView.shadowRoot!.querySelector('#acceleratorItem');
+
+    // Assert no error has occurred prior to pressing a shortcut.
+    assertFalse(editView.hasError);
+
+    // Alt + ']' is a conflict, expect the error message to appear.
+    accelViewElement!.dispatchEvent(new KeyboardEvent('keydown', {
+      key: ']',
+      keyCode: 221,
+      code: 'Key]',
+      ctrlKey: false,
+      altKey: true,
+      shiftKey: false,
+      metaKey: false,
+    }));
+
+    await flushTasks();
+
+    assertTrue(editView.hasError);
+
+    // Press the shortcut again, this time it will replace the preexsting
+    // accelerator.
+    accelViewElement!.dispatchEvent(new KeyboardEvent('keydown', {
+      key: ']',
+      keyCode: 221,
+      code: 'Key]',
+      ctrlKey: false,
+      altKey: true,
+      shiftKey: false,
+      metaKey: false,
+    }));
+
+    await flushTasks();
+
+    // Requery the view element.
+    editView =
+        editDialog!.shadowRoot!.querySelector('cr-dialog')!.querySelectorAll(
+            'accelerator-edit-view')[0] as AcceleratorEditViewElement;
+    accelViewElement = editView.shadowRoot!.querySelector('#acceleratorItem');
+
+    // Assert that the accelerator was updated with the new shortcut (Alt + ']')
+    const acceleratorInfo =
+        (accelViewElement as AcceleratorViewElement).acceleratorInfo as
+        AcceleratorInfo;
+    const actualAccelerator = acceleratorInfo.accelerator as AcceleratorKeys;
+    assertEquals(Modifier.ALT, actualAccelerator!.modifiers);
+    assertEquals(221, actualAccelerator!.key);
+    assertEquals(']', actualAccelerator!.keyDisplay);
+  });
+
+  test('AddAccelerator', async () => {
+    await flushTasks();
+
+    // Open dialog for first accelerator in View Desk subsection.
+    await openDialogForAcceleratorInSubsection(/*View Desk*/ 1);
+    const editDialog = getPage().shadowRoot!.querySelector('#editDialog');
+    assertTrue(!!editDialog);
+
+    // Grab the first accelerator from Virtual Desks subsection.
+    let dialogAccels =
+        editDialog!.shadowRoot!.querySelector('cr-dialog')!.querySelectorAll(
+            'accelerator-edit-view');
+    // Expect only 1 accelerator initially.
+    assertEquals(1, dialogAccels!.length);
+
+    // Click on add button.
+    (editDialog!.shadowRoot!.querySelector('#addAcceleratorButton') as
+     CrButtonElement)
+        .click();
+
+    await flushTasks();
+
+    const editElement =
+        editDialog!.shadowRoot!.querySelector('#pendingAccelerator') as
+        AcceleratorEditViewElement;
+
+    // Assert no error has occurred prior to pressing a shortcut.
+    assertFalse(editElement.hasError);
+
+    const viewElement =
+        editElement!.shadowRoot!.querySelector('#acceleratorItem');
+
+    // Alt + ']' is a conflict, expect the error message to appear.
+    viewElement!.dispatchEvent(new KeyboardEvent('keydown', {
+      key: ']',
+      keyCode: 221,
+      code: 'Key]',
+      ctrlKey: false,
+      altKey: true,
+      shiftKey: false,
+      metaKey: false,
+    }));
+
+    await flushTasks();
+
+    assertTrue(editElement.hasError);
+
+    // Press the shortcut again, this time it will add and remove the preexsting
+    // accelerator.
+    viewElement!.dispatchEvent(new KeyboardEvent('keydown', {
+      key: ']',
+      keyCode: 221,
+      code: 'Key]',
+      ctrlKey: false,
+      altKey: true,
+      shiftKey: false,
+      metaKey: false,
+    }));
+
+    await flushTasks();
+
+    // Requery all accelerators.
+    dialogAccels =
+        editDialog!.shadowRoot!.querySelector('cr-dialog')!.querySelectorAll(
+            'accelerator-edit-view');
+    // Expect 2 accelerators now.
+    assertEquals(2, dialogAccels!.length);
+    const newAccel = dialogAccels[1];
+
+    const actualAccelerator =
+        (newAccel!.shadowRoot!.querySelector('#acceleratorItem') as
+         AcceleratorViewElement)
+            .acceleratorInfo!.accelerator;
+    assertEquals(Modifier.ALT, actualAccelerator!.modifiers);
+    assertEquals(221, actualAccelerator!.key);
+    assertEquals(']', actualAccelerator!.keyDisplay);
+  });
+
+  test('RemoveAccelerator', async () => {
+    await flushTasks();
+
+    // Open dialog for first accelerator in View Desk subsection.
+    await openDialogForAcceleratorInSubsection(/*View Desk*/ 1);
+    const editDialog = getDialog('#editDialog');
+    assertTrue(!!editDialog);
+
+    // Grab the first accelerator from Virtual Desks subsection.
+    let acceleratorList =
+        editDialog!.shadowRoot!.querySelector('cr-dialog')!.querySelectorAll(
+            'accelerator-edit-view');
+    assertEquals(1, acceleratorList!.length);
+    const editView = acceleratorList[0] as AcceleratorEditViewElement;
+
+    // Click on remove button.
+    const deleteButton =
+        editView!.shadowRoot!.querySelector('#deleteButton') as CrButtonElement;
+    deleteButton.click();
+
+    await flushTasks();
+
+    // Requery the accelerator elements.
+    acceleratorList =
+        editDialog!.shadowRoot!.querySelector('cr-dialog')!.querySelectorAll(
+            'accelerator-edit-view');
+
+    // Expect that the accelerator has now been removed.
+    assertEquals(0, acceleratorList!.length);
+  });
+
+  test('RestoreAllButton', async () => {
+    await flushTasks();
+
+    let restoreDialog = getDialog('#restoreDialog');
+    // Expect the dialog to not appear initially.
+    assertFalse(!!restoreDialog);
+
+    // Click on the Restore all button.
+    const restoreButton = getPage().shadowRoot!.querySelector(
+                              '#restoreAllButton') as CrButtonElement;
+    restoreButton!.click();
+
+    await flushTasks();
+
+    // Requery the dialog.
+    restoreDialog = getDialog('#restoreDialog');
+    assertTrue(restoreDialog!.open);
+
+    // Click on Cancel button.
+    const cancelButton =
+        restoreDialog!.querySelector('#cancelButton') as CrButtonElement;
+    cancelButton.click();
+
+    await flushTasks();
+
+    restoreDialog = getDialog('#restoreDialog');
+    assertFalse(!!restoreDialog);
+  });
+});
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test_util.js b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test_util.js
deleted file mode 100644
index 41219014..0000000
--- a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test_util.js
+++ /dev/null
@@ -1,47 +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.
-
-import {AcceleratorState, AcceleratorType} from 'chrome://shortcut-customization/shortcut_types.js';
-
-/**
- * @param {number} modifier
- * @param {number} keycode
- * @param {string} keyDisplay
- * @param {?boolean} locked
- * @return {!AcceleratorInfo}
- */
-export function createDefaultAccelerator(
-    modifier, keycode, keyDisplay, locked = false) {
-  return /** @type {!AcceleratorInfo} */ ({
-    accelerator: /** @type {!AcceleratorKeys} */ ({
-      modifiers: modifier,
-      key: keycode,
-      keyDisplay: keyDisplay,
-    }),
-    type: AcceleratorType.DEFAULT,
-    state: AcceleratorState.ENABLED,
-    locked: locked,
-  });
-}
-
-/**
- * @param {number} modifier
- * @param {number} keycode
- * @param {string} keyDisplay
- * @param {?boolean} locked
- * @return {!AcceleratorInfo}
- */
-export function createUserAccelerator(
-    modifier, keycode, keyDisplay, locked = false) {
-  return /** @type {!AcceleratorInfo} */ ({
-    accelerator: /** @type {!AcceleratorKeys} */ ({
-      modifiers: modifier,
-      key: keycode,
-      keyDisplay: keyDisplay,
-    }),
-    type: AcceleratorType.USER_DEFINED,
-    state: AcceleratorState.ENABLED,
-    locked: locked,
-  });
-}
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test_util.ts b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test_util.ts
new file mode 100644
index 0000000..03dae00
--- /dev/null
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test_util.ts
@@ -0,0 +1,35 @@
+// 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 {AcceleratorInfo, AcceleratorState, AcceleratorType} from 'chrome://shortcut-customization/shortcut_types.js';
+
+export function createDefaultAccelerator(
+    modifier: number, keycode: number, keyDisplay: string,
+    locked = false): AcceleratorInfo {
+  return {
+    accelerator: {
+      modifiers: modifier,
+      key: keycode,
+      keyDisplay: keyDisplay,
+    },
+    type: AcceleratorType.DEFAULT,
+    state: AcceleratorState.ENABLED,
+    locked: locked,
+  };
+}
+
+export function createUserAccelerator(
+    modifier: number, keycode: number, keyDisplay: string,
+    locked = false): AcceleratorInfo {
+  return {
+    accelerator: {
+      modifiers: modifier,
+      key: keycode,
+      keyDisplay: keyDisplay,
+    },
+    type: AcceleratorType.USER_DEFINED,
+    state: AcceleratorState.ENABLED,
+    locked: locked,
+  };
+}
diff --git a/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_v3_browsertest.js b/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_v3_browsertest.js
index 7717c74..57ae1368 100644
--- a/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_v3_browsertest.js
+++ b/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_v3_browsertest.js
@@ -108,7 +108,6 @@
     get featureList() {
       return {
         enabled: [
-          'chromeos::features::kCellularUseAttachApn',
           'chromeos::features::kSimLockPolicy',
           'ash::features::kBluetoothRevamp',
         ],
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn
index 7c851806..3feb0d6 100644
--- a/chromeos/BUILD.gn
+++ b/chromeos/BUILD.gn
@@ -121,7 +121,6 @@
       "//chromeos/crosapi/cpp:unit_tests",
       "//chromeos/crosapi/mojom:unit_tests",
       "//chromeos/dbus:unit_tests",
-      "//chromeos/language/language_packs:unit_tests",
       "//chromeos/login/login_state:unit_tests",
       "//chromeos/printing:unit_tests",
       "//chromeos/process_proxy:unit_tests",
diff --git a/chromeos/ash/components/BUILD.gn b/chromeos/ash/components/BUILD.gn
index ab78508..b42a8ce 100644
--- a/chromeos/ash/components/BUILD.gn
+++ b/chromeos/ash/components/BUILD.gn
@@ -22,6 +22,7 @@
     "//chromeos/ash/components/feature_usage:unit_tests",
     "//chromeos/ash/components/human_presence:unit_tests",
     "//chromeos/ash/components/install_attributes:unit_tests",
+    "//chromeos/ash/components/language/language_packs:unit_tests",
     "//chromeos/ash/components/local_search_service:unit_tests",
     "//chromeos/ash/components/local_search_service/public/mojom:unit_tests",
     "//chromeos/ash/components/memory:unit_tests",
diff --git a/chromeos/ash/components/dbus/shill/fake_shill_manager_client.cc b/chromeos/ash/components/dbus/shill/fake_shill_manager_client.cc
index 55c01ae..09da8d6 100644
--- a/chromeos/ash/components/dbus/shill/fake_shill_manager_client.cc
+++ b/chromeos/ash/components/dbus/shill/fake_shill_manager_client.cc
@@ -523,7 +523,7 @@
 void FakeShillManagerClient::CheckTetheringReadiness(
     StringCallback callback,
     ErrorCallback error_callback) {
-  switch (simulate_tethering_enable_result_) {
+  switch (simulate_check_tethering_readiness_result_) {
     case FakeShillSimulatedResult::kSuccess:
       base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE, base::BindOnce(std::move(callback),
diff --git a/chromeos/ash/components/human_presence/human_presence_configuration.cc b/chromeos/ash/components/human_presence/human_presence_configuration.cc
index c5d1e1a..bccdcf9f 100644
--- a/chromeos/ash/components/human_presence/human_presence_configuration.cc
+++ b/chromeos/ash/components/human_presence/human_presence_configuration.cc
@@ -19,7 +19,7 @@
 // Default minimum amount of time for which a positive snooper presence will be
 // reported.
 constexpr base::TimeDelta kSnoopingProtectionPositiveWindowDefault =
-    base::Seconds(4);
+    base::Seconds(3);
 
 // Default quick dim delay to configure power_manager.
 constexpr base::TimeDelta kQuickDimDelayDefault = base::Seconds(10);
@@ -54,13 +54,14 @@
 hps::FeatureConfig GetDefaultSnoopingProtectionConfig() {
   hps::FeatureConfig config;
 
-  // Just apply a threshold to the last-seen inference.
+  // Three consecutive positive/negative/unknown frames are required to change
+  // the second person presence state to reduce noise.
   auto& filter_config = *config.mutable_consecutive_results_filter_config();
-  filter_config.set_positive_count_threshold(1);
-  filter_config.set_negative_count_threshold(1);
-  filter_config.set_uncertain_count_threshold(1);
-  filter_config.set_positive_score_threshold(0);
-  filter_config.set_negative_score_threshold(0);
+  filter_config.set_positive_count_threshold(3);
+  filter_config.set_negative_count_threshold(3);
+  filter_config.set_uncertain_count_threshold(3);
+  filter_config.set_positive_score_threshold(20);
+  filter_config.set_negative_score_threshold(20);
 
   return config;
 }
diff --git a/chromeos/language/DIR_METADATA b/chromeos/ash/components/language/DIR_METADATA
similarity index 100%
rename from chromeos/language/DIR_METADATA
rename to chromeos/ash/components/language/DIR_METADATA
diff --git a/chromeos/language/OWNERS b/chromeos/ash/components/language/OWNERS
similarity index 100%
rename from chromeos/language/OWNERS
rename to chromeos/ash/components/language/OWNERS
diff --git a/chromeos/language/language_packs/BUILD.gn b/chromeos/ash/components/language/language_packs/BUILD.gn
similarity index 84%
rename from chromeos/language/language_packs/BUILD.gn
rename to chromeos/ash/components/language/language_packs/BUILD.gn
index 8879138..19171ef 100644
--- a/chromeos/language/language_packs/BUILD.gn
+++ b/chromeos/ash/components/language/language_packs/BUILD.gn
@@ -2,7 +2,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-assert(is_chromeos, "Non-ChromeOS builds cannot depend on //chromeos")
+import("//build/config/chromeos/ui_mode.gni")
+
+assert(is_chromeos_ash, "Non-ChromeOS builds cannot depend on //chromeos/ash")
 
 static_library("language_packs") {
   sources = [
@@ -13,9 +15,9 @@
   ]
   deps = [
     "//base",
+    "//chromeos/ash/components/language/public/mojom",
     "//chromeos/dbus/dlcservice:dlcservice",
     "//chromeos/dbus/dlcservice:dlcservice_proto",
-    "//chromeos/language/public/mojom",
   ]
 }
 
diff --git a/chromeos/language/language_packs/README.md b/chromeos/ash/components/language/language_packs/README.md
similarity index 100%
rename from chromeos/language/language_packs/README.md
rename to chromeos/ash/components/language/language_packs/README.md
diff --git a/chromeos/language/language_packs/language_pack_manager.cc b/chromeos/ash/components/language/language_packs/language_pack_manager.cc
similarity index 98%
rename from chromeos/language/language_packs/language_pack_manager.cc
rename to chromeos/ash/components/language/language_packs/language_pack_manager.cc
index a14a414..3a6743a5 100644
--- a/chromeos/language/language_packs/language_pack_manager.cc
+++ b/chromeos/ash/components/language/language_packs/language_pack_manager.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/language/language_packs/language_pack_manager.h"
+#include "chromeos/ash/components/language/language_packs/language_pack_manager.h"
 
 #include "base/bind.h"
 #include "base/callback.h"
diff --git a/chromeos/language/language_packs/language_pack_manager.h b/chromeos/ash/components/language/language_packs/language_pack_manager.h
similarity index 95%
rename from chromeos/language/language_packs/language_pack_manager.h
rename to chromeos/ash/components/language/language_packs/language_pack_manager.h
index c750df9..70bed7a 100644
--- a/chromeos/language/language_packs/language_pack_manager.h
+++ b/chromeos/ash/components/language/language_packs/language_pack_manager.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMEOS_LANGUAGE_LANGUAGE_PACKS_LANGUAGE_PACK_MANAGER_H_
-#define CHROMEOS_LANGUAGE_LANGUAGE_PACKS_LANGUAGE_PACK_MANAGER_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_LANGUAGE_LANGUAGE_PACKS_LANGUAGE_PACK_MANAGER_H_
+#define CHROMEOS_ASH_COMPONENTS_LANGUAGE_LANGUAGE_PACKS_LANGUAGE_PACK_MANAGER_H_
 
 #include <string>
 
@@ -173,4 +173,4 @@
 
 }  // namespace chromeos::language_packs
 
-#endif  // CHROMEOS_LANGUAGE_LANGUAGE_PACKS_LANGUAGE_PACK_MANAGER_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_LANGUAGE_LANGUAGE_PACKS_LANGUAGE_PACK_MANAGER_H_
diff --git a/chromeos/language/language_packs/language_pack_manager_unittest.cc b/chromeos/ash/components/language/language_packs/language_pack_manager_unittest.cc
similarity index 99%
rename from chromeos/language/language_packs/language_pack_manager_unittest.cc
rename to chromeos/ash/components/language/language_packs/language_pack_manager_unittest.cc
index d4072ea9..1e8a2e8 100644
--- a/chromeos/language/language_packs/language_pack_manager_unittest.cc
+++ b/chromeos/ash/components/language/language_packs/language_pack_manager_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/language/language_packs/language_pack_manager.h"
+#include "chromeos/ash/components/language/language_packs/language_pack_manager.h"
 
 #include "base/bind.h"
 #include "base/logging.h"
diff --git a/chromeos/language/language_packs/language_packs_impl.cc b/chromeos/ash/components/language/language_packs/language_packs_impl.cc
similarity index 98%
rename from chromeos/language/language_packs/language_packs_impl.cc
rename to chromeos/ash/components/language/language_packs/language_packs_impl.cc
index 8a07556..591f377 100644
--- a/chromeos/language/language_packs/language_packs_impl.cc
+++ b/chromeos/ash/components/language/language_packs/language_packs_impl.cc
@@ -5,7 +5,7 @@
 #include <string>
 
 #include "base/metrics/histogram_functions.h"
-#include "chromeos/language/language_packs/language_packs_impl.h"
+#include "chromeos/ash/components/language/language_packs/language_packs_impl.h"
 
 #include "base/no_destructor.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
diff --git a/chromeos/language/language_packs/language_packs_impl.h b/chromeos/ash/components/language/language_packs/language_packs_impl.h
similarity index 78%
rename from chromeos/language/language_packs/language_packs_impl.h
rename to chromeos/ash/components/language/language_packs/language_packs_impl.h
index d227f34..b547f38 100644
--- a/chromeos/language/language_packs/language_packs_impl.h
+++ b/chromeos/ash/components/language/language_packs/language_packs_impl.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMEOS_LANGUAGE_LANGUAGE_PACKS_LANGUAGE_PACKS_IMPL_H_
-#define CHROMEOS_LANGUAGE_LANGUAGE_PACKS_LANGUAGE_PACKS_IMPL_H_
+#ifndef CHROMEOS_ASH_COMPONENTS_LANGUAGE_LANGUAGE_PACKS_LANGUAGE_PACKS_IMPL_H_
+#define CHROMEOS_ASH_COMPONENTS_LANGUAGE_LANGUAGE_PACKS_LANGUAGE_PACKS_IMPL_H_
 
 #include <string>
 
-#include "chromeos/language/language_packs/language_pack_manager.h"
-#include "chromeos/language/public/mojom/language_packs.mojom.h"
+#include "chromeos/ash/components/language/language_packs/language_pack_manager.h"
+#include "chromeos/ash/components/language/public/mojom/language_packs.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
 
@@ -44,4 +44,4 @@
 
 }  // namespace chromeos::language_packs
 
-#endif  // CHROMEOS_LANGUAGE_LANGUAGE_PACKS_LANGUAGE_PACKS_IMPL_H_
+#endif  // CHROMEOS_ASH_COMPONENTS_LANGUAGE_LANGUAGE_PACKS_LANGUAGE_PACKS_IMPL_H_
diff --git a/chromeos/language/language_packs/metrics_unittest.cc b/chromeos/ash/components/language/language_packs/metrics_unittest.cc
similarity index 100%
rename from chromeos/language/language_packs/metrics_unittest.cc
rename to chromeos/ash/components/language/language_packs/metrics_unittest.cc
diff --git a/chromeos/language/public/mojom/BUILD.gn b/chromeos/ash/components/language/public/mojom/BUILD.gn
similarity index 71%
rename from chromeos/language/public/mojom/BUILD.gn
rename to chromeos/ash/components/language/public/mojom/BUILD.gn
index 80015af0..e183f69 100644
--- a/chromeos/language/public/mojom/BUILD.gn
+++ b/chromeos/ash/components/language/public/mojom/BUILD.gn
@@ -2,8 +2,11 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/chromeos/ui_mode.gni")
 import("//mojo/public/tools/bindings/mojom.gni")
 
+assert(is_chromeos_ash, "Non-ChromeOS builds cannot depend on //chromeos/ash")
+
 mojom("mojom") {
   sources = [ "language_packs.mojom" ]
   public_deps = [ "//mojo/public/mojom/base" ]
diff --git a/chromeos/language/public/mojom/OWNERS b/chromeos/ash/components/language/public/mojom/OWNERS
similarity index 100%
rename from chromeos/language/public/mojom/OWNERS
rename to chromeos/ash/components/language/public/mojom/OWNERS
diff --git a/chromeos/language/public/mojom/language_packs.mojom b/chromeos/ash/components/language/public/mojom/language_packs.mojom
similarity index 100%
rename from chromeos/language/public/mojom/language_packs.mojom
rename to chromeos/ash/components/language/public/mojom/language_packs.mojom
diff --git a/chromeos/ash/components/network/client_cert_resolver_unittest.cc b/chromeos/ash/components/network/client_cert_resolver_unittest.cc
index 542f6950..c1e25432 100644
--- a/chromeos/ash/components/network/client_cert_resolver_unittest.cc
+++ b/chromeos/ash/components/network/client_cert_resolver_unittest.cc
@@ -72,7 +72,8 @@
 // Returns a |OncParsedCertificates| which contains exactly one client
 // certificate with the contents of |client_cert_pkcs12_file| and the GUID
 // |guid|. Returns nullptr if the file could not be read.
-std::unique_ptr<onc::OncParsedCertificates> OncParsedCertificatesForPkcs12File(
+std::unique_ptr<chromeos::onc::OncParsedCertificates>
+OncParsedCertificatesForPkcs12File(
     const base::FilePath& client_cert_pkcs12_file,
     base::StringPiece guid) {
   std::string pkcs12_raw;
@@ -88,7 +89,8 @@
   onc_certificate.SetKey("PKCS12", base::Value(pkcs12_base64_encoded));
   base::Value onc_certificates(base::Value::Type::LIST);
   onc_certificates.Append(std::move(onc_certificate));
-  return std::make_unique<onc::OncParsedCertificates>(onc_certificates);
+  return std::make_unique<chromeos::onc::OncParsedCertificates>(
+      onc_certificates);
 }
 
 std::string GetString(const base::Value& dict, const char* key) {
diff --git a/chromeos/ash/components/network/hotspot_state_handler.cc b/chromeos/ash/components/network/hotspot_state_handler.cc
index 0a0ef21..8510976 100644
--- a/chromeos/ash/components/network/hotspot_state_handler.cc
+++ b/chromeos/ash/components/network/hotspot_state_handler.cc
@@ -28,11 +28,47 @@
   return active_clients->GetList().size();
 }
 
+bool CanFindTechnoloyInList(const std::string& technology,
+                            const base::Value::List& technology_list) {
+  return std::find(technology_list.begin(), technology_list.end(),
+                   base::Value(technology)) != technology_list.end();
+}
+
+// Convert the base::Value::List type of |allowed_security_modes_in_shill| to
+// the corresponding mojom enum and update the value to the
+// |allowed_security_modes|.
+void UpdateAllowedSecurityList(
+    std::vector<hotspot_config::mojom::WiFiSecurityMode>&
+        allowed_security_modes,
+    const base::Value::List& allowed_security_modes_in_shill) {
+  allowed_security_modes.clear();
+  for (const base::Value& allowed_security : allowed_security_modes_in_shill) {
+    allowed_security_modes.push_back(
+        ShillSecurityToMojom(allowed_security.GetString()));
+  }
+}
+
+bool IsDisallowedByPlatformCapabilities(
+    hotspot_config::mojom::HotspotAllowStatus allow_status) {
+  using HotspotAllowStatus = hotspot_config::mojom::HotspotAllowStatus;
+  return allow_status == HotspotAllowStatus::kDisallowedNoCellularUpstream ||
+         allow_status == HotspotAllowStatus::kDisallowedNoWiFiDownstream ||
+         allow_status == HotspotAllowStatus::kDisallowedNoWiFiSecurityModes;
+}
+
 }  // namespace
 
+HotspotStateHandler::HotspotCapabilities::HotspotCapabilities(
+    const hotspot_config::mojom::HotspotAllowStatus allow_status)
+    : allow_status(allow_status) {}
+
+HotspotStateHandler::HotspotCapabilities::~HotspotCapabilities() = default;
+
 HotspotStateHandler::HotspotStateHandler() = default;
 
 HotspotStateHandler::~HotspotStateHandler() {
+  ResetNetworkStateHandler();
+
   if (ShillManagerClient::Get()) {
     ShillManagerClient::Get()->RemovePropertyChangedObserver(this);
   }
@@ -41,7 +77,10 @@
   }
 }
 
-void HotspotStateHandler::Init() {
+void HotspotStateHandler::Init(NetworkStateHandler* network_state_handler) {
+  network_state_handler_ = network_state_handler;
+  network_state_handler_observer_.Observe(network_state_handler_);
+
   if (LoginState::IsInitialized()) {
     LoginState::Get()->AddObserver(this);
   }
@@ -76,6 +115,11 @@
   return active_client_count_;
 }
 
+const HotspotStateHandler::HotspotCapabilities&
+HotspotStateHandler::GetHotspotCapabilities() const {
+  return hotspot_capabilities_;
+}
+
 hotspot_config::mojom::HotspotConfigPtr HotspotStateHandler::GetHotspotConfig()
     const {
   if (!hotspot_config_)
@@ -174,6 +218,50 @@
                                             const base::Value& value) {
   if (key == shill::kTetheringStatusProperty)
     UpdateHotspotStatus(value);
+  else if (key == shill::kTetheringCapabilitiesProperty)
+    UpdateHotspotCapabilities(value);
+}
+
+// The hotspot capabilities is re-calculated when a cellular network connection
+// state is changed.
+void HotspotStateHandler::NetworkConnectionStateChanged(
+    const NetworkState* network) {
+  using HotspotAllowStatus = hotspot_config::mojom::HotspotAllowStatus;
+  // Only check the Cellular connectivity as the upstream technology
+  if (!network->Matches(NetworkTypePattern::Cellular())) {
+    return;
+  }
+
+  // Exit early if the platform capabilities doesn't support hotspot.
+  if (IsDisallowedByPlatformCapabilities(hotspot_capabilities_.allow_status)) {
+    return;
+  }
+
+  if (!network->IsConnectingOrConnected()) {
+    // The cellular network got disconnected.
+    SetHotspotCapablities(HotspotAllowStatus::kDisallowedNoMobileData);
+    return;
+  }
+
+  if (network->IsConnectedState()) {
+    ShillManagerClient::Get()->CheckTetheringReadiness(
+        base::BindOnce(&HotspotStateHandler::OnCheckReadinessSuccess,
+                       weak_ptr_factory_.GetWeakPtr()),
+        base::BindOnce(&HotspotStateHandler::OnCheckReadinessFailure,
+                       weak_ptr_factory_.GetWeakPtr()));
+  }
+}
+
+void HotspotStateHandler::OnShuttingDown() {
+  ResetNetworkStateHandler();
+}
+
+void HotspotStateHandler::ResetNetworkStateHandler() {
+  if (!network_state_handler_) {
+    return;
+  }
+  network_state_handler_observer_.Reset();
+  network_state_handler_ = nullptr;
 }
 
 void HotspotStateHandler::OnManagerProperties(
@@ -188,9 +276,18 @@
   if (!status) {
     NET_LOG(EVENT) << "HotspotStateHandler: No dict value for: "
                    << shill::kTetheringStatusProperty;
-    return;
+  } else {
+    UpdateHotspotStatus(*status);
   }
-  UpdateHotspotStatus(*status);
+
+  const base::Value* capabilities =
+      properties->FindDictKey(shill::kTetheringCapabilitiesProperty);
+  if (!capabilities) {
+    NET_LOG(EVENT) << "HotspotStateHandler: No dict value for: "
+                   << shill::kTetheringCapabilitiesProperty;
+  } else {
+    UpdateHotspotCapabilities(*capabilities);
+  }
 }
 
 void HotspotStateHandler::UpdateHotspotStatus(const base::Value& status) {
@@ -239,6 +336,99 @@
   NotifyHotspotStatusChanged();
 }
 
+void HotspotStateHandler::UpdateHotspotCapabilities(
+    const base::Value& capabilities) {
+  using HotspotAllowStatus = hotspot_config::mojom::HotspotAllowStatus;
+
+  const base::Value* upstream_technologies =
+      capabilities.FindListKey(shill::kTetheringCapUpstreamProperty);
+  if (!upstream_technologies) {
+    NET_LOG(ERROR) << "No list value for: "
+                   << shill::kTetheringCapUpstreamProperty << " in "
+                   << shill::kTetheringCapabilitiesProperty;
+    SetHotspotCapablities(HotspotAllowStatus::kDisallowedNoCellularUpstream);
+    return;
+  }
+
+  if (!CanFindTechnoloyInList(shill::kTypeCellular,
+                              upstream_technologies->GetList())) {
+    SetHotspotCapablities(HotspotAllowStatus::kDisallowedNoCellularUpstream);
+    return;
+  }
+
+  const base::Value* downstream_technologies =
+      capabilities.FindListKey(shill::kTetheringCapDownstreamProperty);
+  if (!downstream_technologies) {
+    NET_LOG(ERROR) << "No list value for: "
+                   << shill::kTetheringCapDownstreamProperty << " in "
+                   << shill::kTetheringCapabilitiesProperty;
+    SetHotspotCapablities(HotspotAllowStatus::kDisallowedNoWiFiDownstream);
+    return;
+  }
+
+  if (!CanFindTechnoloyInList(shill::kTypeWifi,
+                              downstream_technologies->GetList())) {
+    SetHotspotCapablities(HotspotAllowStatus::kDisallowedNoWiFiDownstream);
+    return;
+  }
+
+  // Update allowed security modes for WiFi downstream
+  const base::Value* allowed_security_modes_in_shill =
+      capabilities.FindListKey(shill::kTetheringCapSecurityProperty);
+  if (!allowed_security_modes_in_shill) {
+    NET_LOG(ERROR) << "No list value for: "
+                   << shill::kTetheringCapSecurityProperty << " in "
+                   << shill::kTetheringCapabilitiesProperty;
+    SetHotspotCapablities(HotspotAllowStatus::kDisallowedNoWiFiSecurityModes);
+    return;
+  }
+
+  UpdateAllowedSecurityList(hotspot_capabilities_.allowed_security_modes,
+                            allowed_security_modes_in_shill->GetList());
+  if (hotspot_capabilities_.allowed_security_modes.empty()) {
+    SetHotspotCapablities(HotspotAllowStatus::kDisallowedNoWiFiSecurityModes);
+    return;
+  }
+
+  // Check if there's a connected cellular network
+  const NetworkState* connected_cellular_network =
+      network_state_handler_->ConnectedNetworkByType(
+          NetworkTypePattern::Cellular());
+  if (!connected_cellular_network) {
+    SetHotspotCapablities(HotspotAllowStatus::kDisallowedNoMobileData);
+    return;
+  }
+
+  ShillManagerClient::Get()->CheckTetheringReadiness(
+      base::BindOnce(&HotspotStateHandler::OnCheckReadinessSuccess,
+                     weak_ptr_factory_.GetWeakPtr()),
+      base::BindOnce(&HotspotStateHandler::OnCheckReadinessFailure,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+void HotspotStateHandler::OnCheckReadinessSuccess(const std::string& result) {
+  using HotspotAllowStatus = hotspot_config::mojom::HotspotAllowStatus;
+
+  if (result == shill::kTetheringReadinessReady) {
+    SetHotspotCapablities(HotspotAllowStatus::kAllowed);
+    return;
+  }
+  if (result == shill::kTetheringReadinessNotAllowed) {
+    SetHotspotCapablities(HotspotAllowStatus::kDisallowedReadinessCheckFail);
+    return;
+  }
+  NET_LOG(ERROR) << "Unexpected check tethering readiness result: " << result;
+}
+
+void HotspotStateHandler::OnCheckReadinessFailure(
+    const std::string& error_name,
+    const std::string& error_message) {
+  NET_LOG(ERROR) << "Check tethering readiness failed, error name: "
+                 << error_name << ", message: " << error_message;
+  SetHotspotCapablities(
+      hotspot_config::mojom::HotspotAllowStatus::kDisallowedReadinessCheckFail);
+}
+
 void HotspotStateHandler::FallbackStateOnFailure() {
   using HotspotState = hotspot_config::mojom::HotspotState;
   if (hotspot_state_ == HotspotState::kEnabled ||
@@ -254,6 +444,19 @@
   NotifyHotspotStatusChanged();
 }
 
+void HotspotStateHandler::SetHotspotCapablities(
+    hotspot_config::mojom::HotspotAllowStatus new_allow_status) {
+  if (hotspot_capabilities_.allow_status == new_allow_status)
+    return;
+
+  hotspot_capabilities_.allow_status = new_allow_status;
+  NotifyHotspotCapabilitiesChanged();
+}
+
+void HotspotStateHandler::SetPolicyAllowHotspot(bool allow) {
+  // TODO (jiajunz)
+}
+
 void HotspotStateHandler::NotifyHotspotStatusChanged() {
   for (auto& observer : observer_list_)
     observer.OnHotspotStatusChanged();
@@ -264,4 +467,9 @@
     observer.OnHotspotStateFailed(error);
 }
 
+void HotspotStateHandler::NotifyHotspotCapabilitiesChanged() {
+  for (auto& observer : observer_list_)
+    observer.OnHotspotCapabilitiesChanged();
+}
+
 }  // namespace ash
\ No newline at end of file
diff --git a/chromeos/ash/components/network/hotspot_state_handler.h b/chromeos/ash/components/network/hotspot_state_handler.h
index fe680124..98692cb 100644
--- a/chromeos/ash/components/network/hotspot_state_handler.h
+++ b/chromeos/ash/components/network/hotspot_state_handler.h
@@ -6,24 +6,31 @@
 #define CHROMEOS_ASH_COMPONENTS_NETWORK_HOTSPOT_STATE_HANDLER_H_
 
 #include <memory>
+#include <vector>
 
 #include "base/component_export.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
+#include "base/scoped_observation.h"
 #include "base/values.h"
 #include "chromeos/ash/components/dbus/shill/shill_property_changed_observer.h"
+#include "chromeos/ash/components/network/network_state_handler.h"
+#include "chromeos/ash/components/network/network_state_handler_observer.h"
 #include "chromeos/login/login_state/login_state.h"
 #include "chromeos/services/hotspot_config/public/mojom/cros_hotspot_config.mojom.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace ash {
 
+class NetworkStateHandler;
+
 // This class caches hotspot related status and implements methods to get
 // current state, active client count, capabilities and configure the hotspot
 // configurations.
 class COMPONENT_EXPORT(CHROMEOS_NETWORK) HotspotStateHandler
     : public ShillPropertyChangedObserver,
-      public LoginState::Observer {
+      public LoginState::Observer,
+      public NetworkStateHandlerObserver {
  public:
   class Observer : public base::CheckedObserver {
    public:
@@ -34,6 +41,23 @@
     virtual void OnHotspotStatusChanged() = 0;
     // Invoked when hotspot state is failed.
     virtual void OnHotspotStateFailed(const std::string& error) = 0;
+    // Invoked when hotspot capabilities is changed.
+    virtual void OnHotspotCapabilitiesChanged() = 0;
+  };
+
+  // Represents the hotspot capabilities. Includes:
+  // 1. The allow status that is calculated from the combination Shill Tethering
+  // Capabilities and Shill Tethering Readiness check result and policy allow
+  // status.
+  // 2. List of allowed WiFi security modes for WiFi downstream.
+  struct HotspotCapabilities {
+    HotspotCapabilities(
+        const chromeos::hotspot_config::mojom::HotspotAllowStatus allow_status);
+    ~HotspotCapabilities();
+
+    chromeos::hotspot_config::mojom::HotspotAllowStatus allow_status;
+    std::vector<chromeos::hotspot_config::mojom::WiFiSecurityMode>
+        allowed_security_modes;
   };
 
   HotspotStateHandler();
@@ -41,14 +65,15 @@
   HotspotStateHandler& operator=(const HotspotStateHandler&) = delete;
   ~HotspotStateHandler() override;
 
-  void Init();
+  void Init(NetworkStateHandler* network_state_handler);
   // Return the latest hotspot state
   const chromeos::hotspot_config::mojom::HotspotState& GetHotspotState() const;
   // Return the latest hotspot active client count
   size_t GetHotspotActiveClientCount() const;
   // Return the current hotspot configuration
   chromeos::hotspot_config::mojom::HotspotConfigPtr GetHotspotConfig() const;
-
+  // Return the latest hotspot capabilities
+  const HotspotCapabilities& GetHotspotCapabilities() const;
   // Return callback for the SetHotspotConfig method. |success| indicates
   // whether the operation is success or not.
   using SetHotspotConfigCallback = base::OnceCallback<void(
@@ -60,6 +85,9 @@
       chromeos::hotspot_config::mojom::HotspotConfigPtr config,
       SetHotspotConfigCallback callback);
 
+  // Set whether Hotspot should be allowed/disallowed by policy.
+  void SetPolicyAllowHotspot(bool allow);
+
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
   bool HasObserver(Observer* observer) const;
@@ -72,6 +100,10 @@
   // LoginState::Observer
   void LoggedInStateChanged() override;
 
+  // NetworkStateHandlerObserver
+  void NetworkConnectionStateChanged(const NetworkState* network) override;
+  void OnShuttingDown() override;
+
   // Callback to handle the manager properties with hotspot related properties.
   void OnManagerProperties(absl::optional<base::Value> properties);
 
@@ -89,6 +121,9 @@
   // Notify observers that hotspot state was failure.
   void NotifyHotspotStateFailed(const std::string& error);
 
+  // Notify observer that hotspot capabilities was changed.
+  void NotifyHotspotCapabilitiesChanged();
+
   // Update the cached hotspot_config_ with the tethering configuration
   // from |manager_properties|, and then run the |callback|.
   void UpdateHotspotConfigAndRunCallback(
@@ -103,10 +138,36 @@
                                  const std::string& error_name,
                                  const std::string& error_message);
 
+  // Update the cached hotspot_capabilities_ from the tethering capabilities
+  // values from Shill. This function is called whenever the tethering
+  // capabilities value is changed in Shill.
+  void UpdateHotspotCapabilities(const base::Value& capabilities);
+
+  // Callback when the CheckTetheringReadiness operation succeeded.
+  void OnCheckReadinessSuccess(const std::string& result);
+
+  // Callback when the CheckTetheringReadiness operation failed.
+  void OnCheckReadinessFailure(const std::string& error_name,
+                               const std::string& error_message);
+
+  // Update the hotspot_capabilities_ with the given |new_allow_status|
+  // and then notify observers if it changes.
+  void SetHotspotCapablities(
+      chromeos::hotspot_config::mojom::HotspotAllowStatus new_allow_status);
+
+  void ResetNetworkStateHandler();
+
   chromeos::hotspot_config::mojom::HotspotState hotspot_state_ =
       chromeos::hotspot_config::mojom::HotspotState::kDisabled;
+  HotspotCapabilities hotspot_capabilities_{
+      chromeos::hotspot_config::mojom::HotspotAllowStatus::
+          kDisallowedNoCellularUpstream};
   absl::optional<base::Value> hotspot_config_ = absl::nullopt;
   size_t active_client_count_ = 0;
+
+  NetworkStateHandler* network_state_handler_ = nullptr;
+  base::ScopedObservation<NetworkStateHandler, NetworkStateHandlerObserver>
+      network_state_handler_observer_{this};
   base::ObserverList<Observer> observer_list_;
   base::WeakPtrFactory<HotspotStateHandler> weak_ptr_factory_{this};
 };
diff --git a/chromeos/ash/components/network/hotspot_state_handler_unittest.cc b/chromeos/ash/components/network/hotspot_state_handler_unittest.cc
index 0b27308..2d49b2d 100644
--- a/chromeos/ash/components/network/hotspot_state_handler_unittest.cc
+++ b/chromeos/ash/components/network/hotspot_state_handler_unittest.cc
@@ -11,6 +11,8 @@
 #include "base/values.h"
 #include "chromeos/ash/components/dbus/shill/shill_clients.h"
 #include "chromeos/ash/components/dbus/shill/shill_manager_client.h"
+#include "chromeos/ash/components/network/network_state_handler.h"
+#include "chromeos/ash/components/network/network_state_test_helper.h"
 #include "chromeos/services/hotspot_config/public/mojom/cros_hotspot_config.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
@@ -21,6 +23,9 @@
 
 const char kHotspotConfigSSID[] = "hotspot_SSID";
 const char kHotspotConfigPassphrase[] = "hotspot_passphrase";
+const char kCellularServicePath[] = "/service/cellular0";
+const char kCellularServiceGuid[] = "cellular_guid0";
+const char kCellularServiceName[] = "cellular_name0";
 
 chromeos::hotspot_config::mojom::HotspotConfigPtr GenerateTestConfig() {
   auto mojom_config = chromeos::hotspot_config::mojom::HotspotConfig::New();
@@ -48,9 +53,18 @@
     last_hotspot_failed_error_ = error;
   }
 
+  void OnHotspotCapabilitiesChanged() override {
+    hotspot_capabilities_changed_count_++;
+  }
+
   size_t hotspot_status_changed_count() {
     return hotspot_status_changed_count_;
   }
+
+  size_t hotspot_capabilities_changed_count() {
+    return hotspot_capabilities_changed_count_;
+  }
+
   size_t hotspot_state_failed_count() { return hotspot_state_failed_count_; }
 
   const std::string& last_hotspot_failed_error() {
@@ -60,6 +74,7 @@
  private:
   size_t hotspot_status_changed_count_ = 0u;
   size_t hotspot_state_failed_count_ = 0u;
+  size_t hotspot_capabilities_changed_count_ = 0u;
   std::string last_hotspot_failed_error_;
 };
 
@@ -67,10 +82,8 @@
  public:
   void SetUp() override {
     feature_list_.InitAndEnableFeature(features::kHotspot);
-    shill_clients::InitializeFakes();
     LoginState::Initialize();
     LoginState::Get()->set_always_logged_in(false);
-    base::RunLoop().RunUntilIdle();
 
     if (hotspot_state_handler_ &&
         hotspot_state_handler_->HasObserver(&observer_)) {
@@ -78,13 +91,16 @@
     }
     hotspot_state_handler_ = std::make_unique<HotspotStateHandler>();
     hotspot_state_handler_->AddObserver(&observer_);
-    hotspot_state_handler_->Init();
+    hotspot_state_handler_->Init(
+        network_state_test_helper_.network_state_handler());
+    base::RunLoop().RunUntilIdle();
   }
 
   void TearDown() override {
+    network_state_test_helper_.ClearDevices();
+    network_state_test_helper_.ClearServices();
     hotspot_state_handler_->RemoveObserver(&observer_);
     hotspot_state_handler_.reset();
-    shill_clients::Shutdown();
     LoginState::Shutdown();
   }
 
@@ -122,6 +138,8 @@
   base::test::ScopedFeatureList feature_list_;
   std::unique_ptr<HotspotStateHandler> hotspot_state_handler_;
   TestObserver observer_;
+  NetworkStateTestHelper network_state_test_helper_{
+      /*use_default_devices_and_services=*/false};
 };
 
 TEST_F(HotspotStateHandlerTest, GetHotspotState) {
@@ -132,7 +150,7 @@
   base::Value status_dict(base::Value::Type::DICTIONARY);
   status_dict.GetDict().Set(shill::kTetheringStatusStateProperty,
                             base::Value(shill::kTetheringStateActive));
-  ShillManagerClient::Get()->GetTestInterface()->SetManagerProperty(
+  network_state_test_helper_.manager_test()->SetManagerProperty(
       shill::kTetheringStatusProperty, status_dict);
   base::RunLoop().RunUntilIdle();
 
@@ -144,7 +162,7 @@
   // Update tethering status to idle in Shill.
   status_dict.GetDict().Set(shill::kTetheringStatusStateProperty,
                             base::Value(shill::kTetheringStateIdle));
-  ShillManagerClient::Get()->GetTestInterface()->SetManagerProperty(
+  network_state_test_helper_.manager_test()->SetManagerProperty(
       shill::kTetheringStatusProperty, status_dict);
   base::RunLoop().RunUntilIdle();
 
@@ -156,7 +174,7 @@
   // Simulate user starting tethering and failed.
   status_dict.GetDict().Set(shill::kTetheringStatusStateProperty,
                             base::Value(shill::kTetheringStateStarting));
-  ShillManagerClient::Get()->GetTestInterface()->SetManagerProperty(
+  network_state_test_helper_.manager_test()->SetManagerProperty(
       shill::kTetheringStatusProperty, status_dict);
   base::RunLoop().RunUntilIdle();
   // Update tethering status to failure in Shill.
@@ -165,7 +183,7 @@
   status_dict.GetDict().Set(
       shill::kTetheringStatusErrorProperty,
       base::Value(shill::kTetheringErrorUpstreamNotReady));
-  ShillManagerClient::Get()->GetTestInterface()->SetManagerProperty(
+  network_state_test_helper_.manager_test()->SetManagerProperty(
       shill::kTetheringStatusProperty, status_dict);
   base::RunLoop().RunUntilIdle();
 
@@ -179,7 +197,7 @@
   // Verify the edge case where the state is failure but error is not provided.
   status_dict.GetDict().Set(shill::kTetheringStatusStateProperty,
                             base::Value(shill::kTetheringStateStarting));
-  ShillManagerClient::Get()->GetTestInterface()->SetManagerProperty(
+  network_state_test_helper_.manager_test()->SetManagerProperty(
       shill::kTetheringStatusProperty, status_dict);
   base::RunLoop().RunUntilIdle();
   status_dict.GetDict().Set(shill::kTetheringStatusStateProperty,
@@ -202,7 +220,7 @@
   base::Value status_dict(base::Value::Type::DICTIONARY);
   status_dict.GetDict().Set(shill::kTetheringStatusStateProperty,
                             base::Value(shill::kTetheringStateActive));
-  ShillManagerClient::Get()->GetTestInterface()->SetManagerProperty(
+  network_state_test_helper_.manager_test()->SetManagerProperty(
       shill::kTetheringStatusProperty, status_dict);
   base::RunLoop().RunUntilIdle();
 
@@ -221,7 +239,7 @@
   active_clients_list.Append(std::move(client));
   status_dict.GetDict().Set(shill::kTetheringStatusClientsProperty,
                             std::move(active_clients_list));
-  ShillManagerClient::Get()->GetTestInterface()->SetManagerProperty(
+  network_state_test_helper_.manager_test()->SetManagerProperty(
       shill::kTetheringStatusProperty, status_dict);
   base::RunLoop().RunUntilIdle();
 
@@ -231,7 +249,7 @@
   status_dict.GetDict().Set(shill::kTetheringStatusStateProperty,
                             base::Value(shill::kTetheringStateIdle));
   status_dict.GetDict().Remove(shill::kTetheringStatusClientsProperty);
-  ShillManagerClient::Get()->GetTestInterface()->SetManagerProperty(
+  network_state_test_helper_.manager_test()->SetManagerProperty(
       shill::kTetheringStatusProperty, status_dict);
   base::RunLoop().RunUntilIdle();
 
@@ -239,6 +257,111 @@
   EXPECT_EQ(3u, observer_.hotspot_status_changed_count());
 }
 
+TEST_F(HotspotStateHandlerTest, GetHotspotCapabilities) {
+  EXPECT_EQ(chromeos::hotspot_config::mojom::HotspotAllowStatus::
+                kDisallowedNoCellularUpstream,
+            hotspot_state_handler_->GetHotspotCapabilities().allow_status);
+  EXPECT_EQ(0u, observer_.hotspot_capabilities_changed_count());
+
+  base::Value capabilities_dict(base::Value::Type::DICTIONARY);
+  capabilities_dict.GetDict().Set(shill::kTetheringCapUpstreamProperty,
+                                  base::Value(base::Value::Type::LIST));
+  capabilities_dict.GetDict().Set(shill::kTetheringCapDownstreamProperty,
+                                  base::Value(base::Value::Type::LIST));
+  capabilities_dict.GetDict().Set(shill::kTetheringCapSecurityProperty,
+                                  base::Value(base::Value::Type::LIST));
+  network_state_test_helper_.manager_test()->SetManagerProperty(
+      shill::kTetheringCapabilitiesProperty, capabilities_dict);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(chromeos::hotspot_config::mojom::HotspotAllowStatus::
+                kDisallowedNoCellularUpstream,
+            hotspot_state_handler_->GetHotspotCapabilities().allow_status);
+  EXPECT_EQ(0u, observer_.hotspot_capabilities_changed_count());
+
+  base::Value upstream_list(base::Value::Type::LIST);
+  upstream_list.Append(base::Value(shill::kTypeCellular));
+  capabilities_dict.GetDict().Set(shill::kTetheringCapUpstreamProperty,
+                                  std::move(upstream_list));
+  network_state_test_helper_.manager_test()->SetManagerProperty(
+      shill::kTetheringCapabilitiesProperty, capabilities_dict);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(chromeos::hotspot_config::mojom::HotspotAllowStatus::
+                kDisallowedNoWiFiDownstream,
+            hotspot_state_handler_->GetHotspotCapabilities().allow_status);
+  EXPECT_EQ(1u, observer_.hotspot_capabilities_changed_count());
+
+  // Add WiFi to the downstream technology list in Shill
+  base::Value downstream_list(base::Value::Type::LIST);
+  downstream_list.Append(base::Value(shill::kTypeWifi));
+  capabilities_dict.GetDict().Set(shill::kTetheringCapDownstreamProperty,
+                                  std::move(downstream_list));
+  // Add allowed WiFi security mode in Shill
+  base::Value security_list(base::Value::Type::LIST);
+  security_list.Append(base::Value(shill::kSecurityWpa2));
+  security_list.Append(base::Value(shill::kSecurityWpa3));
+  capabilities_dict.GetDict().Set(shill::kTetheringCapSecurityProperty,
+                                  std::move(security_list));
+  network_state_test_helper_.manager_test()->SetManagerProperty(
+      shill::kTetheringCapabilitiesProperty, capabilities_dict);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(chromeos::hotspot_config::mojom::HotspotAllowStatus::
+                kDisallowedNoMobileData,
+            hotspot_state_handler_->GetHotspotCapabilities().allow_status);
+  EXPECT_EQ(2u, hotspot_state_handler_->GetHotspotCapabilities()
+                    .allowed_security_modes.size());
+  EXPECT_EQ(2u, observer_.hotspot_capabilities_changed_count());
+
+  // Add an active cellular network and simulate check tethering readiness
+  // operation fail.
+  network_state_test_helper_.manager_test()
+      ->SetSimulateCheckTetheringReadinessResult(
+          FakeShillSimulatedResult::kFailure,
+          /*readiness_status=*/std::string());
+  ShillServiceClient::TestInterface* service_test =
+      network_state_test_helper_.service_test();
+  service_test->AddService(kCellularServicePath, kCellularServiceGuid,
+                           kCellularServiceName, shill::kTypeCellular,
+                           shill::kStateOnline, /*visible=*/true);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(chromeos::hotspot_config::mojom::HotspotAllowStatus::
+                kDisallowedReadinessCheckFail,
+            hotspot_state_handler_->GetHotspotCapabilities().allow_status);
+  EXPECT_EQ(3u, observer_.hotspot_capabilities_changed_count());
+
+  // Disconnect the active cellular network
+  service_test->SetServiceProperty(kCellularServicePath, shill::kStateProperty,
+                                   base::Value(shill::kStateIdle));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(chromeos::hotspot_config::mojom::HotspotAllowStatus::
+                kDisallowedNoMobileData,
+            hotspot_state_handler_->GetHotspotCapabilities().allow_status);
+  EXPECT_EQ(4u, observer_.hotspot_capabilities_changed_count());
+
+  // Simulate check tethering readiness operation success and re-connect the
+  // cellular network
+  network_state_test_helper_.manager_test()
+      ->SetSimulateCheckTetheringReadinessResult(
+          FakeShillSimulatedResult::kSuccess, shill::kTetheringReadinessReady);
+  service_test->SetServiceProperty(kCellularServicePath, shill::kStateProperty,
+                                   base::Value(shill::kStateOnline));
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(chromeos::hotspot_config::mojom::HotspotAllowStatus::kAllowed,
+            hotspot_state_handler_->GetHotspotCapabilities().allow_status);
+  EXPECT_EQ(5u, observer_.hotspot_capabilities_changed_count());
+
+  hotspot_state_handler_->SetPolicyAllowHotspot(/*allow*/ false);
+  base::RunLoop().RunUntilIdle();
+  // TODO (jiajunz): Should expect equal after SetPolicyAllowHotspot() is
+  // implemented.
+  EXPECT_NE(
+      chromeos::hotspot_config::mojom::HotspotAllowStatus::kDisallowedByPolicy,
+      hotspot_state_handler_->GetHotspotCapabilities().allow_status);
+}
+
 TEST_F(HotspotStateHandlerTest, SetAndGetHotspotConfig) {
   EXPECT_EQ(
       chromeos::hotspot_config::mojom::SetHotspotConfigResult::kFailedNotLogin,
diff --git a/chromeos/ash/components/network/hotspot_util.cc b/chromeos/ash/components/network/hotspot_util.cc
index 86cbbab..c1fb4902 100644
--- a/chromeos/ash/components/network/hotspot_util.cc
+++ b/chromeos/ash/components/network/hotspot_util.cc
@@ -36,25 +36,6 @@
   return WiFiBand::k5GHz;
 }
 
-hotspot_config::mojom::WiFiSecurityMode ShillSecurityToMojom(
-    const std::string& shill_security) {
-  using hotspot_config::mojom::WiFiSecurityMode;
-
-  if (shill_security == shill::kSecurityWpa2) {
-    return WiFiSecurityMode::kWpa2;
-  }
-  if (shill_security == shill::kSecurityWpa2) {
-    return WiFiSecurityMode::kWpa3;
-  }
-  if (shill_security == shill::kSecurityWpa2Wpa3) {
-    return WiFiSecurityMode::kWpa2Wpa3;
-  }
-
-  NOTREACHED() << "Unexpected shill tethering security mode: "
-               << shill_security;
-  return WiFiSecurityMode::kWpa2;
-}
-
 std::string MojomBandToString(hotspot_config::mojom::WiFiBand mojom_band) {
   using hotspot_config::mojom::WiFiBand;
 
@@ -106,6 +87,24 @@
   return HotspotState::kDisabled;
 }
 
+hotspot_config::mojom::WiFiSecurityMode ShillSecurityToMojom(
+    const std::string& shill_security) {
+  using hotspot_config::mojom::WiFiSecurityMode;
+
+  if (shill_security == shill::kSecurityWpa2) {
+    return WiFiSecurityMode::kWpa2;
+  }
+  if (shill_security == shill::kSecurityWpa3) {
+    return WiFiSecurityMode::kWpa3;
+  }
+  if (shill_security == shill::kSecurityWpa2Wpa3) {
+    return WiFiSecurityMode::kWpa2Wpa3;
+  }
+
+  NOTREACHED() << "Unexpeted shill tethering security mode: " << shill_security;
+  return WiFiSecurityMode::kWpa2;
+}
+
 hotspot_config::mojom::HotspotConfigPtr ShillTetheringConfigToMojomConfig(
     const base::Value& shill_tethering_config) {
   using hotspot_config::mojom::HotspotConfig;
diff --git a/chromeos/ash/components/network/hotspot_util.h b/chromeos/ash/components/network/hotspot_util.h
index c473209b..3fdc507 100644
--- a/chromeos/ash/components/network/hotspot_util.h
+++ b/chromeos/ash/components/network/hotspot_util.h
@@ -21,6 +21,11 @@
 chromeos::hotspot_config::mojom::HotspotState ShillTetheringStateToMojomState(
     const std::string& shill_state);
 
+// Convert shill security mode string value to mojom::WiFiSecurityMode enum
+COMPONENT_EXPORT(CHROMEOS_NETWORK)
+chromeos::hotspot_config::mojom::WiFiSecurityMode ShillSecurityToMojom(
+    const std::string& shill_security);
+
 // Convert shill tethering config dictionary value to mojom::HotspotConfigPtr
 COMPONENT_EXPORT(CHROMEOS_NETWORK)
 chromeos::hotspot_config::mojom::HotspotConfigPtr
diff --git a/chromeos/ash/components/network/managed_network_configuration_handler_impl.cc b/chromeos/ash/components/network/managed_network_configuration_handler_impl.cc
index 77cd25b..cd70e1d 100644
--- a/chromeos/ash/components/network/managed_network_configuration_handler_impl.cc
+++ b/chromeos/ash/components/network/managed_network_configuration_handler_impl.cc
@@ -278,22 +278,23 @@
 
   // Validate the ONC dictionary. We are liberal and ignore unknown field
   // names. User settings are only partial ONC, thus we ignore missing fields.
-  onc::Validator validator(false,  // Ignore unknown fields.
-                           false,  // Ignore invalid recommended field names.
-                           false,  // Ignore missing fields.
-                           false,  // This ONC does not come from policy.
-                           true);  // Log warnings.
+  chromeos::onc::Validator validator(
+      false,  // Ignore unknown fields.
+      false,  // Ignore invalid recommended field names.
+      false,  // Ignore missing fields.
+      false,  // This ONC does not come from policy.
+      true);  // Log warnings.
 
-  onc::Validator::Result validation_result;
-  base::Value validated_user_settings =
-      validator.ValidateAndRepairObject(&onc::kNetworkConfigurationSignature,
-                                        user_settings_copy, &validation_result);
-  if (validation_result == onc::Validator::INVALID) {
+  chromeos::onc::Validator::Result validation_result;
+  base::Value validated_user_settings = validator.ValidateAndRepairObject(
+      &chromeos::onc::kNetworkConfigurationSignature, user_settings_copy,
+      &validation_result);
+  if (validation_result == chromeos::onc::Validator::INVALID) {
     InvokeErrorCallback(service_path, std::move(error_callback),
                         kInvalidUserSettings);
     return;
   }
-  if (validation_result == onc::Validator::VALID_WITH_WARNINGS)
+  if (validation_result == chromeos::onc::Validator::VALID_WITH_WARNINGS)
     NET_LOG(USER) << "Validation of ONC user settings produced warnings.";
   DCHECK(validated_user_settings.is_dict());
 
@@ -307,8 +308,8 @@
   }
 
   // Fill in HexSSID field from contents of SSID field if not set already.
-  onc::FillInHexSSIDFieldsInOncObject(onc::kNetworkConfigurationSignature,
-                                      &validated_user_settings);
+  onc::FillInHexSSIDFieldsInOncObject(
+      chromeos::onc::kNetworkConfigurationSignature, &validated_user_settings);
 
   const base::Value* network_policy = policies->GetPolicyByGuid(guid);
   if (network_policy)
@@ -371,27 +372,29 @@
 
   // Validate the ONC dictionary. We are liberal and ignore unknown field
   // names. User settings are only partial ONC, thus we ignore missing fields.
-  onc::Validator validator(false,   // Ignore unknown fields.
-                           false,   // Ignore invalid recommended field names.
-                           false,   // Ignore missing fields.
-                           false,   // This ONC does not come from policy.
-                           false);  // Don't log warnings.
+  chromeos::onc::Validator validator(
+      false,   // Ignore unknown fields.
+      false,   // Ignore invalid recommended field names.
+      false,   // Ignore missing fields.
+      false,   // This ONC does not come from policy.
+      false);  // Don't log warnings.
 
-  onc::Validator::Result validation_result;
+  chromeos::onc::Validator::Result validation_result;
   base::Value validated_properties = validator.ValidateAndRepairObject(
-      &onc::kNetworkConfigurationSignature, properties, &validation_result);
-  if (validation_result == onc::Validator::INVALID) {
+      &chromeos::onc::kNetworkConfigurationSignature, properties,
+      &validation_result);
+  if (validation_result == chromeos::onc::Validator::INVALID) {
     InvokeErrorCallback("", std::move(error_callback), kInvalidUserSettings);
     return;
   }
-  if (validation_result == onc::Validator::VALID_WITH_WARNINGS)
+  if (validation_result == chromeos::onc::Validator::VALID_WITH_WARNINGS)
     NET_LOG(DEBUG) << "Validation of ONC user settings produced warnings.";
   DCHECK(validated_properties.is_dict());
 
   // Fill in HexSSID field from contents of SSID field if not set already - this
   // is required to properly match the configuration against existing policies.
-  onc::FillInHexSSIDFieldsInOncObject(onc::kNetworkConfigurationSignature,
-                                      &validated_properties);
+  onc::FillInHexSSIDFieldsInOncObject(
+      chromeos::onc::kNetworkConfigurationSignature, &validated_properties);
 
   // Make sure the network is not configured through a user policy.
   const ProfilePolicies* policies = nullptr;
@@ -1239,7 +1242,7 @@
   ::onc::ONCSource onc_source;
   FindPolicyByGUID(userhash, *guid, &onc_source);
   base::Value onc_network = onc::TranslateShillServiceToONCPart(
-      *shill_properties, onc_source, &onc::kNetworkWithStateSignature,
+      *shill_properties, onc_source, &chromeos::onc::kNetworkWithStateSignature,
       network_state);
 
   if (properties_type == PropertiesType::kUnmanaged) {
diff --git a/chromeos/ash/components/network/managed_network_configuration_handler_unittest.cc b/chromeos/ash/components/network/managed_network_configuration_handler_unittest.cc
index 7e71305..07d86b0 100644
--- a/chromeos/ash/components/network/managed_network_configuration_handler_unittest.cc
+++ b/chromeos/ash/components/network/managed_network_configuration_handler_unittest.cc
@@ -272,16 +272,17 @@
   void SetPolicy(::onc::ONCSource onc_source,
                  const std::string& userhash,
                  base::Value policy) {
-    onc::Validator validator(true,   // error_on_unknown_field
-                             true,   // error_on_wrong_recommended
-                             false,  // error_on_missing_field
-                             true,   // managed_onc
-                             true);  // log_warnings
+    chromeos::onc::Validator validator(true,   // error_on_unknown_field
+                                       true,   // error_on_wrong_recommended
+                                       false,  // error_on_missing_field
+                                       true,   // managed_onc
+                                       true);  // log_warnings
     validator.SetOncSource(onc_source);
-    onc::Validator::Result validation_result;
+    chromeos::onc::Validator::Result validation_result;
     base::Value validated_policy = validator.ValidateAndRepairObject(
-        &onc::kToplevelConfigurationSignature, policy, &validation_result);
-    if (validation_result == onc::Validator::INVALID) {
+        &chromeos::onc::kToplevelConfigurationSignature, policy,
+        &validation_result);
+    if (validation_result == chromeos::onc::Validator::INVALID) {
       ADD_FAILURE() << "Network configuration invalid.";
       return;
     }
diff --git a/chromeos/ash/components/network/network_device_handler_impl.cc b/chromeos/ash/components/network/network_device_handler_impl.cc
index a53b799..aa35df0c 100644
--- a/chromeos/ash/components/network/network_device_handler_impl.cc
+++ b/chromeos/ash/components/network/network_device_handler_impl.cc
@@ -466,10 +466,10 @@
        it != list.end(); ++it) {
     const DeviceState* device_state = *it;
 
-    SetDevicePropertyInternal(
-        device_state->path(), shill::kUseAttachAPNProperty,
-        base::Value(features::ShouldUseAttachApn()), base::DoNothing(),
-        network_handler::ErrorCallback());
+    SetDevicePropertyInternal(device_state->path(),
+                              shill::kUseAttachAPNProperty,
+                              /*value=*/base::Value(true), base::DoNothing(),
+                              network_handler::ErrorCallback());
   }
 }
 
diff --git a/chromeos/ash/components/network/network_handler.cc b/chromeos/ash/components/network/network_handler.cc
index d970cdd0..2297b98 100644
--- a/chromeos/ash/components/network/network_handler.cc
+++ b/chromeos/ash/components/network/network_handler.cc
@@ -131,7 +131,7 @@
                                   network_configuration_handler_.get());
   }
   if (ash::features::IsHotspotEnabled()) {
-    hotspot_state_handler_->Init();
+    hotspot_state_handler_->Init(network_state_handler_.get());
   }
   managed_cellular_pref_handler_->Init(network_state_handler_.get());
   esim_policy_login_metrics_logger_->Init(
diff --git a/chromeos/ash/components/network/network_util.cc b/chromeos/ash/components/network/network_util.cc
index 19ec9acd..a0bb058 100644
--- a/chromeos/ash/components/network/network_util.cc
+++ b/chromeos/ash/components/network/network_util.cc
@@ -237,7 +237,8 @@
       ->FindPolicyByGUID(user_id_hash, network->guid(), &onc_source);
 
   base::Value onc_dictionary = onc::TranslateShillServiceToONCPart(
-      shill_dictionary, onc_source, &onc::kNetworkWithStateSignature, network);
+      shill_dictionary, onc_source, &chromeos::onc::kNetworkWithStateSignature,
+      network);
 
   // Remove IPAddressConfigType/NameServersConfigType as these were
   // historically not provided by TranslateNetworkStateToONC.
diff --git a/chromeos/ash/components/network/onc/network_onc_utils.cc b/chromeos/ash/components/network/onc/network_onc_utils.cc
index 52841c04..9e455e9 100644
--- a/chromeos/ash/components/network/onc/network_onc_utils.cc
+++ b/chromeos/ash/components/network/onc/network_onc_utils.cc
@@ -343,7 +343,8 @@
 
   // Note: It is OK for the placeholders to be replaced with empty strings if
   // that is what the getters on |user| provide.
-  VariableExpander variable_expander(GetVariableExpansionsForUser(user));
+  chromeos::VariableExpander variable_expander(
+      GetVariableExpansionsForUser(user));
   chromeos::onc::ExpandStringsInNetworks(variable_expander, network_configs);
 }
 
@@ -516,12 +517,12 @@
     // Remove irrelevant fields.
     onc::Normalizer normalizer(true /* remove recommended fields */);
     base::Value normalized_network = normalizer.NormalizeObject(
-        &onc::kNetworkConfigurationSignature, network);
+        &chromeos::onc::kNetworkConfigurationSignature, network);
 
     // TODO(b/235297258): Use ONC and ManagedNetworkConfigurationHandler
     // instead.
     base::Value shill_dict = onc::TranslateONCObjectToShill(
-        &onc::kNetworkConfigurationSignature, normalized_network);
+        &chromeos::onc::kNetworkConfigurationSignature, normalized_network);
 
     std::unique_ptr<NetworkUIData> ui_data(
         NetworkUIData::CreateFromONC(::onc::ONC_SOURCE_USER_IMPORT));
@@ -604,16 +605,17 @@
   return policy != nullptr;
 }
 
-bool HasUserPasswordSubsitutionVariable(const OncValueSignature& signature,
-                                        const base::Value* onc_object) {
+bool HasUserPasswordSubsitutionVariable(
+    const chromeos::onc::OncValueSignature& signature,
+    const base::Value* onc_object) {
   DCHECK(onc_object->is_dict());
-  if (&signature == &kEAPSignature) {
+  if (&signature == &chromeos::onc::kEAPSignature) {
     const std::string* password_field =
         onc_object->FindStringKey(::onc::eap::kPassword);
     return password_field &&
            *password_field == ::onc::substitutes::kPasswordPlaceholderVerbatim;
   }
-  if (&signature == &kL2TPSignature) {
+  if (&signature == &chromeos::onc::kL2TPSignature) {
     const std::string* password_field =
         onc_object->FindStringKey(::onc::l2tp::kPassword);
     return password_field &&
@@ -625,8 +627,8 @@
     if (!it.second.is_dict())
       continue;
 
-    const OncFieldSignature* field_signature =
-        GetFieldSignature(signature, it.first);
+    const chromeos::onc::OncFieldSignature* field_signature =
+        chromeos::onc::GetFieldSignature(signature, it.first);
     if (!field_signature)
       continue;
 
@@ -643,7 +645,7 @@
   for (auto& network : network_configs->GetListDeprecated()) {
     DCHECK(network.is_dict());
     bool result = HasUserPasswordSubsitutionVariable(
-        kNetworkConfigurationSignature, &network);
+        chromeos::onc::kNetworkConfigurationSignature, &network);
     if (result)
       return true;
   }
diff --git a/chromeos/ash/components/network/onc/network_onc_utils.h b/chromeos/ash/components/network/onc/network_onc_utils.h
index 04c455f8..ce00233 100644
--- a/chromeos/ash/components/network/onc/network_onc_utils.h
+++ b/chromeos/ash/components/network/onc/network_onc_utils.h
@@ -14,8 +14,6 @@
 #include "base/containers/flat_map.h"
 #include "base/memory/ref_counted.h"
 #include "chromeos/ash/components/network/network_type_pattern.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "chromeos/components/onc/onc_signature.h"
 #include "chromeos/components/onc/variable_expander.h"
 #include "components/onc/onc_constants.h"
 #include "net/cert/scoped_nss_types.h"
@@ -26,6 +24,10 @@
 class Value;
 }
 
+namespace chromeos::onc {
+struct OncValueSignature;
+}
+
 namespace user_manager {
 class User;
 }
@@ -86,8 +88,9 @@
 // Checks whether a WiFi dictionary object has the ${PASSWORD} substitution
 // variable set as the password.
 COMPONENT_EXPORT(CHROMEOS_NETWORK)
-bool HasUserPasswordSubsitutionVariable(const OncValueSignature& signature,
-                                        const base::Value* onc_object);
+bool HasUserPasswordSubsitutionVariable(
+    const chromeos::onc::OncValueSignature& signature,
+    const base::Value* onc_object);
 
 // Checks whether a list of network objects has at least one network with the
 // ${PASSWORD} substitution variable set as the password.
diff --git a/chromeos/ash/components/network/onc/network_onc_utils_unittest.cc b/chromeos/ash/components/network/onc/network_onc_utils_unittest.cc
index 45fd5be2..054c112 100644
--- a/chromeos/ash/components/network/onc/network_onc_utils_unittest.cc
+++ b/chromeos/ash/components/network/onc/network_onc_utils_unittest.cc
@@ -78,8 +78,8 @@
   const auto wifi_onc = test_utils::ReadTestDictionaryValue(
       "wifi_eap_ttls_with_password_variable.onc");
 
-  EXPECT_TRUE(HasUserPasswordSubsitutionVariable(kNetworkConfigurationSignature,
-                                                 &wifi_onc));
+  EXPECT_TRUE(HasUserPasswordSubsitutionVariable(
+      chromeos::onc::kNetworkConfigurationSignature, &wifi_onc));
 }
 
 TEST(ONCPasswordVariable, PasswordNotAvailable) {
@@ -87,7 +87,7 @@
       test_utils::ReadTestDictionaryValue("wifi_eap_ttls.onc");
 
   EXPECT_FALSE(HasUserPasswordSubsitutionVariable(
-      kNetworkConfigurationSignature, &wifi_onc));
+      chromeos::onc::kNetworkConfigurationSignature, &wifi_onc));
 }
 
 TEST(ONCPasswordVariable, PasswordHarcdoded) {
@@ -95,7 +95,7 @@
       "wifi_eap_ttls_with_hardcoded_password.onc");
 
   EXPECT_FALSE(HasUserPasswordSubsitutionVariable(
-      kNetworkConfigurationSignature, &wifi_onc));
+      chromeos::onc::kNetworkConfigurationSignature, &wifi_onc));
 }
 
 TEST(ONCPasswordVariable, MultipleNetworksPasswordAvailable) {
diff --git a/chromeos/ash/components/network/onc/onc_certificate_importer.h b/chromeos/ash/components/network/onc/onc_certificate_importer.h
index 61d4f1a1..7fe40dd 100644
--- a/chromeos/ash/components/network/onc/onc_certificate_importer.h
+++ b/chromeos/ash/components/network/onc/onc_certificate_importer.h
@@ -37,9 +37,11 @@
   // equal to true if all certificates were imported successfully.
   // Never calls |done_callback| after this importer is destructed.
   virtual void ImportAllCertificatesUserInitiated(
-      const std::vector<OncParsedCertificates::ServerOrAuthorityCertificate>&
+      const std::vector<
+          chromeos::onc::OncParsedCertificates::ServerOrAuthorityCertificate>&
           server_or_authority_certificates,
-      const std::vector<OncParsedCertificates::ClientCertificate>&
+      const std::vector<
+          chromeos::onc::OncParsedCertificates::ClientCertificate>&
           client_certificates,
       DoneCallback done_callback) = 0;
 
@@ -48,7 +50,8 @@
   // equal to true if all certificates were imported successfully.
   // Never calls |done_callback| after this importer is destructed.
   virtual void ImportClientCertificates(
-      const std::vector<OncParsedCertificates::ClientCertificate>&
+      const std::vector<
+          chromeos::onc::OncParsedCertificates::ClientCertificate>&
           client_certificates,
       DoneCallback done_callback) = 0;
 };
diff --git a/chromeos/ash/components/network/onc/onc_certificate_importer_impl.cc b/chromeos/ash/components/network/onc/onc_certificate_importer_impl.cc
index e907398..40bbdec 100644
--- a/chromeos/ash/components/network/onc/onc_certificate_importer_impl.cc
+++ b/chromeos/ash/components/network/onc/onc_certificate_importer_impl.cc
@@ -41,9 +41,10 @@
 CertificateImporterImpl::~CertificateImporterImpl() = default;
 
 void CertificateImporterImpl::ImportAllCertificatesUserInitiated(
-    const std::vector<OncParsedCertificates::ServerOrAuthorityCertificate>&
+    const std::vector<
+        chromeos::onc::OncParsedCertificates::ServerOrAuthorityCertificate>&
         server_or_authority_certificates,
-    const std::vector<OncParsedCertificates::ClientCertificate>&
+    const std::vector<chromeos::onc::OncParsedCertificates::ClientCertificate>&
         client_certificates,
     DoneCallback done_callback) {
   VLOG(2) << "Importing " << server_or_authority_certificates.size()
@@ -57,7 +58,7 @@
 }
 
 void CertificateImporterImpl::ImportClientCertificates(
-    const std::vector<OncParsedCertificates::ClientCertificate>&
+    const std::vector<chromeos::onc::OncParsedCertificates::ClientCertificate>&
         client_certificates,
     DoneCallback done_callback) {
   VLOG(2) << "Permanently importing " << client_certificates.size()
@@ -92,13 +93,13 @@
 
 // static
 bool CertificateImporterImpl::StoreClientCertificates(
-    const std::vector<OncParsedCertificates::ClientCertificate>&
+    const std::vector<chromeos::onc::OncParsedCertificates::ClientCertificate>&
         client_certificates,
     net::NSSCertDatabase* nssdb) {
   bool success = true;
 
-  for (const OncParsedCertificates::ClientCertificate& client_certificate :
-       client_certificates) {
+  for (const chromeos::onc::OncParsedCertificates::ClientCertificate&
+           client_certificate : client_certificates) {
     if (!StoreClientCertificate(client_certificate, nssdb)) {
       success = false;
     } else {
@@ -111,14 +112,15 @@
 
 // static
 bool CertificateImporterImpl::StoreAllCertificatesUserInitiated(
-    const std::vector<OncParsedCertificates::ServerOrAuthorityCertificate>&
+    const std::vector<
+        chromeos::onc::OncParsedCertificates::ServerOrAuthorityCertificate>&
         server_or_authority_certificates,
-    const std::vector<OncParsedCertificates::ClientCertificate>&
+    const std::vector<chromeos::onc::OncParsedCertificates::ClientCertificate>&
         client_certificates,
     net::NSSCertDatabase* nssdb) {
   bool success = true;
 
-  for (const OncParsedCertificates::ServerOrAuthorityCertificate&
+  for (const chromeos::onc::OncParsedCertificates::ServerOrAuthorityCertificate&
            server_or_authority_cert : server_or_authority_certificates) {
     if (!StoreServerOrCaCertificateUserInitiated(server_or_authority_cert,
                                                  nssdb)) {
@@ -136,7 +138,8 @@
 
 // static
 bool CertificateImporterImpl::StoreServerOrCaCertificateUserInitiated(
-    const OncParsedCertificates::ServerOrAuthorityCertificate& certificate,
+    const chromeos::onc::OncParsedCertificates::ServerOrAuthorityCertificate&
+        certificate,
     net::NSSCertDatabase* nssdb) {
   net::ScopedCERTCertificate x509_cert =
       net::x509_util::CreateCERTCertificateFromX509Certificate(
@@ -155,7 +158,7 @@
 
   if (x509_cert.get()->isperm) {
     net::CertType net_cert_type =
-        certificate.type() == OncParsedCertificates::
+        certificate.type() == chromeos::onc::OncParsedCertificates::
                                   ServerOrAuthorityCertificate::Type::kServer
             ? net::SERVER_CERT
             : net::CA_CERT;
@@ -181,8 +184,8 @@
     cert_list.push_back(net::x509_util::DupCERTCertificate(x509_cert.get()));
     net::NSSCertDatabase::ImportCertFailureList failures;
     bool success = false;
-    if (certificate.type() ==
-        OncParsedCertificates::ServerOrAuthorityCertificate::Type::kServer)
+    if (certificate.type() == chromeos::onc::OncParsedCertificates::
+                                  ServerOrAuthorityCertificate::Type::kServer)
       success = nssdb->ImportServerCert(cert_list, trust, &failures);
     else  // Authority cert
       success = nssdb->ImportCACerts(cert_list, trust, &failures);
@@ -206,7 +209,7 @@
 
 // static
 bool CertificateImporterImpl::StoreClientCertificate(
-    const OncParsedCertificates::ClientCertificate& certificate,
+    const chromeos::onc::OncParsedCertificates::ClientCertificate& certificate,
     net::NSSCertDatabase* nssdb) {
   // Since this has a private key, always use the private module.
   crypto::ScopedPK11Slot private_slot(nssdb->GetPrivateSlot());
diff --git a/chromeos/ash/components/network/onc/onc_certificate_importer_impl.h b/chromeos/ash/components/network/onc/onc_certificate_importer_impl.h
index 891cc93..ca382f4 100644
--- a/chromeos/ash/components/network/onc/onc_certificate_importer_impl.h
+++ b/chromeos/ash/components/network/onc/onc_certificate_importer_impl.h
@@ -49,14 +49,17 @@
 
   // CertificateImporter overrides
   void ImportAllCertificatesUserInitiated(
-      const std::vector<OncParsedCertificates::ServerOrAuthorityCertificate>&
+      const std::vector<
+          chromeos::onc::OncParsedCertificates::ServerOrAuthorityCertificate>&
           server_or_authority_certificates,
-      const std::vector<OncParsedCertificates::ClientCertificate>&
+      const std::vector<
+          chromeos::onc::OncParsedCertificates::ClientCertificate>&
           client_certificates,
       DoneCallback done_callback) override;
 
   void ImportClientCertificates(
-      const std::vector<OncParsedCertificates::ClientCertificate>&
+      const std::vector<
+          chromeos::onc::OncParsedCertificates::ClientCertificate>&
           client_certificates,
       DoneCallback done_callback) override;
 
@@ -74,7 +77,8 @@
   // Synchronously imports |client_certificates| into |nssdb|. This will be
   // executed on the |io_task_runner_|.
   static bool StoreClientCertificates(
-      const std::vector<OncParsedCertificates::ClientCertificate>&
+      const std::vector<
+          chromeos::onc::OncParsedCertificates::ClientCertificate>&
           client_certificates,
       net::NSSCertDatabase* nssdb);
 
@@ -82,20 +86,24 @@
   // |certificates| into |nssdb|. This will be executed on the
   // |io_task_runner_|.
   static bool StoreAllCertificatesUserInitiated(
-      const std::vector<OncParsedCertificates::ServerOrAuthorityCertificate>&
+      const std::vector<
+          chromeos::onc::OncParsedCertificates::ServerOrAuthorityCertificate>&
           server_or_authority_certificates,
-      const std::vector<OncParsedCertificates::ClientCertificate>&
+      const std::vector<
+          chromeos::onc::OncParsedCertificates::ClientCertificate>&
           client_certificates,
       net::NSSCertDatabase* nssdb);
 
   // Imports the Server or CA certificate |certificate|. Web trust is only
   // applied if the certificate requests the TrustBits attribute "Web".
   static bool StoreServerOrCaCertificateUserInitiated(
-      const OncParsedCertificates::ServerOrAuthorityCertificate& certificate,
+      const chromeos::onc::OncParsedCertificates::ServerOrAuthorityCertificate&
+          certificate,
       net::NSSCertDatabase* nssdb);
 
   static bool StoreClientCertificate(
-      const OncParsedCertificates::ClientCertificate& certificate,
+      const chromeos::onc::OncParsedCertificates::ClientCertificate&
+          certificate,
       net::NSSCertDatabase* nssdb);
 
   // The task runner to use for NSSCertDatabase accesses.
diff --git a/chromeos/ash/components/network/onc/onc_certificate_importer_impl_unittest.cc b/chromeos/ash/components/network/onc/onc_certificate_importer_impl_unittest.cc
index 6074ecf..91423fd 100644
--- a/chromeos/ash/components/network/onc/onc_certificate_importer_impl_unittest.cc
+++ b/chromeos/ash/components/network/onc/onc_certificate_importer_impl_unittest.cc
@@ -80,7 +80,8 @@
 
     CertificateImporterImpl importer(task_runner_, test_nssdb_.get());
     auto onc_parsed_certificates =
-        std::make_unique<OncParsedCertificates>(onc_certificates_);
+        std::make_unique<chromeos::onc::OncParsedCertificates>(
+            onc_certificates_);
     EXPECT_EQ(expected_parse_success, !onc_parsed_certificates->has_error());
     switch (import_type) {
       case ImportType::kClientCertificatesOnly:
diff --git a/chromeos/ash/components/network/onc/onc_merger.cc b/chromeos/ash/components/network/onc/onc_merger.cc
index 029d6225..be454e06 100644
--- a/chromeos/ash/components/network/onc/onc_merger.cc
+++ b/chromeos/ash/components/network/onc/onc_merger.cc
@@ -24,13 +24,13 @@
 
 // Returns true if the field is the identifier of a configuration, i.e. the GUID
 // of a network or a certificate, the ICCID of a cellular.
-bool IsIdentifierField(const OncValueSignature& value_signature,
+bool IsIdentifierField(const chromeos::onc::OncValueSignature& value_signature,
                        const std::string& field_name) {
-  if (&value_signature == &kNetworkConfigurationSignature)
+  if (&value_signature == &chromeos::onc::kNetworkConfigurationSignature)
     return field_name == ::onc::network_config::kGUID;
-  if (&value_signature == &kCertificateSignature)
+  if (&value_signature == &chromeos::onc::kCertificateSignature)
     return field_name == ::onc::certificate::kGUID;
-  if (&value_signature == &kCellularSignature)
+  if (&value_signature == &chromeos::onc::kCellularSignature)
     return field_name == ::onc::cellular::kICCID;
   return false;
 }
@@ -38,11 +38,11 @@
 // Identifier fields and other read-only fields (specifically Type) are
 // handled specially during merging because they are always identical for the
 // various setting sources.
-bool IsReadOnlyField(const OncValueSignature& value_signature,
+bool IsReadOnlyField(const chromeos::onc::OncValueSignature& value_signature,
                      const std::string& field_name) {
   if (IsIdentifierField(value_signature, field_name))
     return true;
-  if (&value_signature == &kNetworkConfigurationSignature)
+  if (&value_signature == &chromeos::onc::kNetworkConfigurationSignature)
     return field_name == ::onc::network_config::kType;
   return false;
 }
@@ -61,7 +61,7 @@
 }
 
 // Returns the default value for ONC field specified by |field|.
-base::Value GetDefaultValue(const OncFieldSignature* field) {
+base::Value GetDefaultValue(const chromeos::onc::OncFieldSignature* field) {
   if (field->default_value_setter)
     return field->default_value_setter();
 
@@ -339,12 +339,13 @@
   MergeToAugmented(const MergeToAugmented&) = delete;
   MergeToAugmented& operator=(const MergeToAugmented&) = delete;
 
-  base::Value MergeDictionaries(const OncValueSignature& signature,
-                                const base::Value* user_policy,
-                                const base::Value* device_policy,
-                                const base::Value* user_settings,
-                                const base::Value* shared_settings,
-                                const base::Value* active_settings) {
+  base::Value MergeDictionaries(
+      const chromeos::onc::OncValueSignature& signature,
+      const base::Value* user_policy,
+      const base::Value* device_policy,
+      const base::Value* user_settings,
+      const base::Value* shared_settings,
+      const base::Value* active_settings) {
     signature_ = &signature;
     return MergeToEffective::MergeDictionaries(user_policy, device_policy,
                                                user_settings, shared_settings,
@@ -355,9 +356,9 @@
   // MergeSettingsAndPolicies override.
   base::Value MergeValues(const std::string& key,
                           const ValueParams& values) override {
-    const OncFieldSignature* field = nullptr;
+    const chromeos::onc::OncFieldSignature* field = nullptr;
     if (signature_)
-      field = GetFieldSignature(*signature_, key);
+      field = chromeos::onc::GetFieldSignature(*signature_, key);
 
     if (!field) {
       // This field is not part of the provided ONCSignature, thus it cannot be
@@ -408,7 +409,7 @@
     // User/shared credentials are not stored separately, so they cannot
     // leak here.
     // User and Shared settings are already replaced with |kFakeCredential|.
-    bool is_credential = onc::FieldIsCredential(*signature_, key);
+    bool is_credential = chromeos::onc::FieldIsCredential(*signature_, key);
     if (is_credential) {
       // Set |kFakeCredential| to notify UI that credential is saved.
       if (values.user_policy) {
@@ -478,11 +479,11 @@
   base::Value MergeNestedDictionaries(const std::string& key,
                                       const ValuePtrs& dicts) override {
     if (signature_) {
-      const OncValueSignature* enclosing_signature = signature_;
+      const chromeos::onc::OncValueSignature* enclosing_signature = signature_;
       signature_ = nullptr;
 
-      const OncFieldSignature* field =
-          GetFieldSignature(*enclosing_signature, key);
+      const chromeos::onc::OncFieldSignature* field =
+          chromeos::onc::GetFieldSignature(*enclosing_signature, key);
       if (field)
         signature_ = field->value_signature;
       base::Value result =
@@ -494,7 +495,7 @@
   }
 
  private:
-  const OncValueSignature* signature_;
+  const chromeos::onc::OncValueSignature* signature_;
 };
 
 }  // namespace
@@ -510,7 +511,7 @@
 }
 
 base::Value MergeSettingsAndPoliciesToAugmented(
-    const OncValueSignature& signature,
+    const chromeos::onc::OncValueSignature& signature,
     const base::Value* user_policy,
     const base::Value* device_policy,
     const base::Value* user_settings,
diff --git a/chromeos/ash/components/network/onc/onc_merger.h b/chromeos/ash/components/network/onc/onc_merger.h
index 0542040..02955c25 100644
--- a/chromeos/ash/components/network/onc/onc_merger.h
+++ b/chromeos/ash/components/network/onc/onc_merger.h
@@ -6,13 +6,15 @@
 #define CHROMEOS_ASH_COMPONENTS_NETWORK_ONC_ONC_MERGER_H_
 
 #include "base/component_export.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "chromeos/components/onc/onc_signature.h"
 
 namespace base {
 class Value;
 }
 
+namespace chromeos::onc {
+struct OncValueSignature;
+}
+
 namespace ash::onc {
 
 // Merges the given |user_settings| and |shared_settings| settings with the
@@ -40,7 +42,7 @@
 // result.
 COMPONENT_EXPORT(CHROMEOS_NETWORK)
 base::Value MergeSettingsAndPoliciesToAugmented(
-    const OncValueSignature& signature,
+    const chromeos::onc::OncValueSignature& signature,
     const base::Value* user_policy,
     const base::Value* device_policy,
     const base::Value* user_settings,
diff --git a/chromeos/ash/components/network/onc/onc_merger_unittest.cc b/chromeos/ash/components/network/onc/onc_merger_unittest.cc
index 44f5fc7..179dd2a 100644
--- a/chromeos/ash/components/network/onc/onc_merger_unittest.cc
+++ b/chromeos/ash/components/network/onc/onc_merger_unittest.cc
@@ -144,8 +144,8 @@
   base::Value expected_augmented =
       test_utils::ReadTestDictionaryValue("augmented_merge.json");
   base::Value merged(MergeSettingsAndPoliciesToAugmented(
-      kNetworkConfigurationSignature, &policy_, &device_policy_, &user_,
-      nullptr, &active_));
+      chromeos::onc::kNetworkConfigurationSignature, &policy_, &device_policy_,
+      &user_, nullptr, &active_));
   EXPECT_TRUE(test_utils::Equals(&expected_augmented, &merged));
 }
 
diff --git a/chromeos/ash/components/network/onc/onc_normalizer.cc b/chromeos/ash/components/network/onc/onc_normalizer.cc
index ecf83cd..6a94bf7 100644
--- a/chromeos/ash/components/network/onc/onc_normalizer.cc
+++ b/chromeos/ash/components/network/onc/onc_normalizer.cc
@@ -22,7 +22,7 @@
 Normalizer::~Normalizer() = default;
 
 base::Value Normalizer::NormalizeObject(
-    const OncValueSignature* object_signature,
+    const chromeos::onc::OncValueSignature* object_signature,
     const base::Value& onc_object) {
   CHECK(object_signature != nullptr);
   bool error = false;
@@ -32,10 +32,12 @@
   return result;
 }
 
-base::Value Normalizer::MapObject(const OncValueSignature& signature,
-                                  const base::Value& onc_object,
-                                  bool* error) {
-  base::Value normalized = Mapper::MapObject(signature, onc_object, error);
+base::Value Normalizer::MapObject(
+    const chromeos::onc::OncValueSignature& signature,
+    const base::Value& onc_object,
+    bool* error) {
+  base::Value normalized =
+      chromeos::onc::Mapper::MapObject(signature, onc_object, error);
 
   if (normalized.is_none())
     return {};
@@ -43,23 +45,23 @@
   if (remove_recommended_fields_)
     normalized.RemoveKey(::onc::kRecommended);
 
-  if (&signature == &kCertificateSignature)
+  if (&signature == &chromeos::onc::kCertificateSignature)
     NormalizeCertificate(&normalized);
-  else if (&signature == &kEAPSignature)
+  else if (&signature == &chromeos::onc::kEAPSignature)
     NormalizeEAP(&normalized);
-  else if (&signature == &kEthernetSignature)
+  else if (&signature == &chromeos::onc::kEthernetSignature)
     NormalizeEthernet(&normalized);
-  else if (&signature == &kIPsecSignature)
+  else if (&signature == &chromeos::onc::kIPsecSignature)
     NormalizeIPsec(&normalized);
-  else if (&signature == &kNetworkConfigurationSignature)
+  else if (&signature == &chromeos::onc::kNetworkConfigurationSignature)
     NormalizeNetworkConfiguration(&normalized);
-  else if (&signature == &kOpenVPNSignature)
+  else if (&signature == &chromeos::onc::kOpenVPNSignature)
     NormalizeOpenVPN(&normalized);
-  else if (&signature == &kProxySettingsSignature)
+  else if (&signature == &chromeos::onc::kProxySettingsSignature)
     NormalizeProxySettings(&normalized);
-  else if (&signature == &kVPNSignature)
+  else if (&signature == &chromeos::onc::kVPNSignature)
     NormalizeVPN(&normalized);
-  else if (&signature == &kWiFiSignature)
+  else if (&signature == &chromeos::onc::kWiFiSignature)
     NormalizeWiFi(&normalized);
 
   return normalized;
diff --git a/chromeos/ash/components/network/onc/onc_normalizer.h b/chromeos/ash/components/network/onc/onc_normalizer.h
index 0a247b7c..0e96d2f 100644
--- a/chromeos/ash/components/network/onc/onc_normalizer.h
+++ b/chromeos/ash/components/network/onc/onc_normalizer.h
@@ -8,12 +8,15 @@
 #include "base/component_export.h"
 #include "base/values.h"
 #include "chromeos/components/onc/onc_mapper.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "chromeos/components/onc/onc_signature.h"
+
+namespace chromeos::onc {
+struct OncValueSignature;
+}
 
 namespace ash::onc {
 
-class COMPONENT_EXPORT(CHROMEOS_NETWORK) Normalizer : public Mapper {
+class COMPONENT_EXPORT(CHROMEOS_NETWORK) Normalizer
+    : public chromeos::onc::Mapper {
  public:
   explicit Normalizer(bool remove_recommended_fields);
 
@@ -31,12 +34,13 @@
   // is set, but the field "HexSSID" is not, the contents of the "SSID" field is
   // converted to UTF-8 encoding, a hex representation of the byte sequence is
   // created and stored in the field "HexSSID".
-  base::Value NormalizeObject(const OncValueSignature* object_signature,
-                              const base::Value& onc_object);
+  base::Value NormalizeObject(
+      const chromeos::onc::OncValueSignature* object_signature,
+      const base::Value& onc_object);
 
  private:
   // Dispatch to the right normalization function according to |signature|.
-  base::Value MapObject(const OncValueSignature& signature,
+  base::Value MapObject(const chromeos::onc::OncValueSignature& signature,
                         const base::Value& onc_object,
                         bool* error) override;
 
diff --git a/chromeos/ash/components/network/onc/onc_normalizer_fuzzer.cc b/chromeos/ash/components/network/onc/onc_normalizer_fuzzer.cc
index dc711ce..a243035 100644
--- a/chromeos/ash/components/network/onc/onc_normalizer_fuzzer.cc
+++ b/chromeos/ash/components/network/onc/onc_normalizer_fuzzer.cc
@@ -23,7 +23,8 @@
 
   for (bool remove_recommended_fields : {false, true}) {
     Normalizer normalizer(remove_recommended_fields);
-    normalizer.NormalizeObject(&kNetworkConfigurationSignature, *parsed_json);
+    normalizer.NormalizeObject(&chromeos::onc::kNetworkConfigurationSignature,
+                               *parsed_json);
   }
 
   return 0;
diff --git a/chromeos/ash/components/network/onc/onc_normalizer_unittest.cc b/chromeos/ash/components/network/onc/onc_normalizer_unittest.cc
index d94d054..b272358 100644
--- a/chromeos/ash/components/network/onc/onc_normalizer_unittest.cc
+++ b/chromeos/ash/components/network/onc/onc_normalizer_unittest.cc
@@ -23,8 +23,8 @@
   const base::Value* expected_normalized =
       data.FindDictKey("unnecessary-address-staticipconfig-normalized");
 
-  base::Value actual_normalized =
-      normalizer.NormalizeObject(&kNetworkConfigurationSignature, *original);
+  base::Value actual_normalized = normalizer.NormalizeObject(
+      &chromeos::onc::kNetworkConfigurationSignature, *original);
   EXPECT_TRUE(test_utils::Equals(expected_normalized, &actual_normalized));
 }
 
@@ -41,8 +41,8 @@
   const base::Value* expected_normalized =
       data.FindDictKey("unnecessary-address-staticipconfig-normalized");
 
-  base::Value actual_normalized =
-      normalizer.NormalizeObject(&kNetworkConfigurationSignature, *original);
+  base::Value actual_normalized = normalizer.NormalizeObject(
+      &chromeos::onc::kNetworkConfigurationSignature, *original);
   EXPECT_TRUE(test_utils::Equals(expected_normalized, &actual_normalized));
 }
 
@@ -58,8 +58,8 @@
   const base::Value* expected_normalized =
       data.FindDictKey("irrelevant-staticipconfig-fields-normalized");
 
-  base::Value actual_normalized =
-      normalizer.NormalizeObject(&kNetworkConfigurationSignature, *original);
+  base::Value actual_normalized = normalizer.NormalizeObject(
+      &chromeos::onc::kNetworkConfigurationSignature, *original);
   EXPECT_TRUE(test_utils::Equals(expected_normalized, &actual_normalized));
 }
 
@@ -74,8 +74,8 @@
   const base::Value* expected_normalized =
       data.FindDictKey("irrelevant-nameservers-normalized");
 
-  base::Value actual_normalized =
-      normalizer.NormalizeObject(&kNetworkConfigurationSignature, *original);
+  base::Value actual_normalized = normalizer.NormalizeObject(
+      &chromeos::onc::kNetworkConfigurationSignature, *original);
   EXPECT_TRUE(test_utils::Equals(expected_normalized, &actual_normalized));
 }
 
@@ -90,8 +90,8 @@
   const base::Value* expected_normalized =
       data.FindDictKey("missing-ip-fields-normalized");
 
-  base::Value actual_normalized =
-      normalizer.NormalizeObject(&kNetworkConfigurationSignature, *original);
+  base::Value actual_normalized = normalizer.NormalizeObject(
+      &chromeos::onc::kNetworkConfigurationSignature, *original);
   EXPECT_TRUE(test_utils::Equals(expected_normalized, &actual_normalized));
 }
 // This test case is about validating valid ONC objects.
@@ -104,8 +104,8 @@
   const base::Value* expected_normalized =
       data.FindDictKey("ethernet-and-vpn-normalized");
 
-  base::Value actual_normalized =
-      normalizer.NormalizeObject(&kNetworkConfigurationSignature, *original);
+  base::Value actual_normalized = normalizer.NormalizeObject(
+      &chromeos::onc::kNetworkConfigurationSignature, *original);
   EXPECT_TRUE(test_utils::Equals(expected_normalized, &actual_normalized));
 }
 
@@ -118,8 +118,8 @@
   const base::Value* original = data.FindDictKey("wifi");
   const base::Value* expected_normalized = data.FindDictKey("wifi-normalized");
 
-  base::Value actual_normalized =
-      normalizer.NormalizeObject(&kNetworkConfigurationSignature, *original);
+  base::Value actual_normalized = normalizer.NormalizeObject(
+      &chromeos::onc::kNetworkConfigurationSignature, *original);
   EXPECT_TRUE(test_utils::Equals(expected_normalized, &actual_normalized));
 }
 
diff --git a/chromeos/ash/components/network/onc/onc_translation_tables.cc b/chromeos/ash/components/network/onc/onc_translation_tables.cc
index 15e56567..7c57b79a 100644
--- a/chromeos/ash/components/network/onc/onc_translation_tables.cc
+++ b/chromeos/ash/components/network/onc/onc_translation_tables.cc
@@ -281,41 +281,43 @@
     {nullptr}};
 
 struct OncValueTranslationEntry {
-  const OncValueSignature* onc_signature;
+  const chromeos::onc::OncValueSignature* onc_signature;
   const FieldTranslationEntry* field_translation_table;
 };
 
 const OncValueTranslationEntry onc_value_translation_table[] = {
-    {&kEAPSignature, eap_fields},
-    {&kIPsecSignature, ipsec_fields},
-    {&kL2TPSignature, l2tp_fields},
-    {&kXAUTHSignature, xauth_fields},
-    {&kOpenVPNSignature, openvpn_fields},
-    {&kWireGuardSignature, wireguard_fields},
-    {&kWireGuardPeerSignature, wireguard_peer_fields},
-    {&kARCVPNSignature, arc_vpn_fields},
-    {&kVerifyX509Signature, verify_x509_fields},
-    {&kVPNSignature, vpn_fields},
-    {&kTetherSignature, tether_fields},
-    {&kTetherWithStateSignature, tether_fields},
-    {&kWiFiSignature, wifi_fields},
-    {&kWiFiWithStateSignature, wifi_fields},
-    {&kCellularApnSignature, cellular_apn_fields},
-    {&kCellularFoundNetworkSignature, cellular_found_network_fields},
-    {&kCellularPaymentPortalSignature, cellular_payment_portal_fields},
-    {&kCellularProviderSignature, cellular_provider_fields},
-    {&kSIMLockStatusSignature, sim_lock_status_fields},
-    {&kCellularSignature, cellular_fields},
-    {&kCellularWithStateSignature, cellular_fields},
-    {&kNetworkWithStateSignature, network_fields},
-    {&kNetworkConfigurationSignature, network_fields},
-    {&kIPConfigSignature, ipconfig_fields},
-    {&kSavedIPConfigSignature, static_or_saved_ipconfig_fields},
-    {&kStaticIPConfigSignature, static_or_saved_ipconfig_fields},
+    {&chromeos::onc::kEAPSignature, eap_fields},
+    {&chromeos::onc::kIPsecSignature, ipsec_fields},
+    {&chromeos::onc::kL2TPSignature, l2tp_fields},
+    {&chromeos::onc::kXAUTHSignature, xauth_fields},
+    {&chromeos::onc::kOpenVPNSignature, openvpn_fields},
+    {&chromeos::onc::kWireGuardSignature, wireguard_fields},
+    {&chromeos::onc::kWireGuardPeerSignature, wireguard_peer_fields},
+    {&chromeos::onc::kARCVPNSignature, arc_vpn_fields},
+    {&chromeos::onc::kVerifyX509Signature, verify_x509_fields},
+    {&chromeos::onc::kVPNSignature, vpn_fields},
+    {&chromeos::onc::kTetherSignature, tether_fields},
+    {&chromeos::onc::kTetherWithStateSignature, tether_fields},
+    {&chromeos::onc::kWiFiSignature, wifi_fields},
+    {&chromeos::onc::kWiFiWithStateSignature, wifi_fields},
+    {&chromeos::onc::kCellularApnSignature, cellular_apn_fields},
+    {&chromeos::onc::kCellularFoundNetworkSignature,
+     cellular_found_network_fields},
+    {&chromeos::onc::kCellularPaymentPortalSignature,
+     cellular_payment_portal_fields},
+    {&chromeos::onc::kCellularProviderSignature, cellular_provider_fields},
+    {&chromeos::onc::kSIMLockStatusSignature, sim_lock_status_fields},
+    {&chromeos::onc::kCellularSignature, cellular_fields},
+    {&chromeos::onc::kCellularWithStateSignature, cellular_fields},
+    {&chromeos::onc::kNetworkWithStateSignature, network_fields},
+    {&chromeos::onc::kNetworkConfigurationSignature, network_fields},
+    {&chromeos::onc::kIPConfigSignature, ipconfig_fields},
+    {&chromeos::onc::kSavedIPConfigSignature, static_or_saved_ipconfig_fields},
+    {&chromeos::onc::kStaticIPConfigSignature, static_or_saved_ipconfig_fields},
     {nullptr}};
 
 struct NestedShillDictionaryEntry {
-  const OncValueSignature* onc_signature;
+  const chromeos::onc::OncValueSignature* onc_signature;
   // nullptr terminated list of Shill property keys.
   const char* const* shill_property_path;
 };
@@ -327,8 +329,8 @@
                                                nullptr};
 
 const NestedShillDictionaryEntry nested_shill_dictionaries[] = {
-    {&kCellularApnSignature, cellular_apn_path_entries},
-    {&kStaticIPConfigSignature, static_ip_config_path_entries},
+    {&chromeos::onc::kCellularApnSignature, cellular_apn_path_entries},
+    {&chromeos::onc::kStaticIPConfigSignature, static_ip_config_path_entries},
     {nullptr}};
 
 // Translation of the EAP.Inner field in case of EAP.Outer == PEAP
@@ -463,7 +465,7 @@
     {nullptr}};
 
 const FieldTranslationEntry* GetFieldTranslationTable(
-    const OncValueSignature& onc_signature) {
+    const chromeos::onc::OncValueSignature& onc_signature) {
   for (const OncValueTranslationEntry* it = onc_value_translation_table;
        it->onc_signature != nullptr; ++it) {
     if (it->onc_signature == &onc_signature)
@@ -497,7 +499,7 @@
 }
 
 std::vector<std::string> GetPathToNestedShillDictionary(
-    const OncValueSignature& onc_signature) {
+    const chromeos::onc::OncValueSignature& onc_signature) {
   std::vector<std::string> shill_property_path;
   for (const NestedShillDictionaryEntry* it = nested_shill_dictionaries;
        it->onc_signature != nullptr; ++it) {
diff --git a/chromeos/ash/components/network/onc/onc_translation_tables.h b/chromeos/ash/components/network/onc/onc_translation_tables.h
index a1eff4eb..f0a475c 100644
--- a/chromeos/ash/components/network/onc/onc_translation_tables.h
+++ b/chromeos/ash/components/network/onc/onc_translation_tables.h
@@ -57,7 +57,7 @@
 extern const FieldTranslationEntry kIPsecIKEv2Table[];
 
 const FieldTranslationEntry* GetFieldTranslationTable(
-    const OncValueSignature& onc_signature);
+    const chromeos::onc::OncValueSignature& onc_signature);
 
 // Returns the translation table for EAP.Inner based on the value of EAP.Outer
 // represented in Shill, or nullptr if no translation table is available for
@@ -76,7 +76,7 @@
 // The default is that values are stored directly in the top level of the Shill
 // dictionary.
 std::vector<std::string> GetPathToNestedShillDictionary(
-    const OncValueSignature& onc_signature);
+    const chromeos::onc::OncValueSignature& onc_signature);
 
 bool GetShillPropertyName(const std::string& onc_field_name,
                           const FieldTranslationEntry table[],
diff --git a/chromeos/ash/components/network/onc/onc_translator.h b/chromeos/ash/components/network/onc/onc_translator.h
index d0cf719..88538a3 100644
--- a/chromeos/ash/components/network/onc/onc_translator.h
+++ b/chromeos/ash/components/network/onc/onc_translator.h
@@ -6,14 +6,16 @@
 #define CHROMEOS_ASH_COMPONENTS_NETWORK_ONC_ONC_TRANSLATOR_H_
 
 #include "base/component_export.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "chromeos/components/onc/onc_signature.h"
 #include "components/onc/onc_constants.h"
 
 namespace base {
 class Value;
 }
 
+namespace chromeos::onc {
+struct OncValueSignature;
+}
+
 namespace ash {
 
 class NetworkState;
@@ -28,8 +30,9 @@
 // This function is used to translate network settings from ONC to Shill's
 // format before sending them to Shill.
 COMPONENT_EXPORT(CHROMEOS_NETWORK)
-base::Value TranslateONCObjectToShill(const OncValueSignature* signature,
-                                      const base::Value& onc_object);
+base::Value TranslateONCObjectToShill(
+    const chromeos::onc::OncValueSignature* signature,
+    const base::Value& onc_object);
 
 // Translates a |shill_dictionary| (a Value of type DICTIONARY) to an ONC object
 // according to the given |onc_signature|. |onc_signature| must point to a
@@ -47,7 +50,7 @@
 base::Value TranslateShillServiceToONCPart(
     const base::Value& shill_dictionary,
     ::onc::ONCSource onc_source,
-    const OncValueSignature* onc_signature,
+    const chromeos::onc::OncValueSignature* onc_signature,
     const NetworkState* network_state);
 
 }  // namespace onc
diff --git a/chromeos/ash/components/network/onc/onc_translator_onc_to_shill.cc b/chromeos/ash/components/network/onc/onc_translator_onc_to_shill.cc
index eba3a17..cf3dbf9 100644
--- a/chromeos/ash/components/network/onc/onc_translator_onc_to_shill.cc
+++ b/chromeos/ash/components/network/onc/onc_translator_onc_to_shill.cc
@@ -87,7 +87,7 @@
 // TranslateONCHierarchy.
 class LocalTranslator {
  public:
-  LocalTranslator(const OncValueSignature& onc_signature,
+  LocalTranslator(const chromeos::onc::OncValueSignature& onc_signature,
                   const base::Value& onc_object,
                   base::Value* shill_dictionary)
       : onc_signature_(&onc_signature),
@@ -135,30 +135,30 @@
                                 const StringTranslationEntry table[],
                                 const std::string& shill_property_name);
 
-  const OncValueSignature* onc_signature_;
+  const chromeos::onc::OncValueSignature* onc_signature_;
   const FieldTranslationEntry* field_translation_table_;
   const base::Value* onc_object_;
   base::Value* shill_dictionary_;
 };
 
 void LocalTranslator::TranslateFields() {
-  if (onc_signature_ == &kNetworkConfigurationSignature)
+  if (onc_signature_ == &chromeos::onc::kNetworkConfigurationSignature)
     TranslateNetworkConfiguration();
-  else if (onc_signature_ == &kEthernetSignature)
+  else if (onc_signature_ == &chromeos::onc::kEthernetSignature)
     TranslateEthernet();
-  else if (onc_signature_ == &kVPNSignature)
+  else if (onc_signature_ == &chromeos::onc::kVPNSignature)
     TranslateVPN();
-  else if (onc_signature_ == &kOpenVPNSignature)
+  else if (onc_signature_ == &chromeos::onc::kOpenVPNSignature)
     TranslateOpenVPN();
-  else if (onc_signature_ == &kIPsecSignature)
+  else if (onc_signature_ == &chromeos::onc::kIPsecSignature)
     TranslateIPsec();
-  else if (onc_signature_ == &kL2TPSignature)
+  else if (onc_signature_ == &chromeos::onc::kL2TPSignature)
     TranslateL2TP();
-  else if (onc_signature_ == &kWiFiSignature)
+  else if (onc_signature_ == &chromeos::onc::kWiFiSignature)
     TranslateWiFi();
-  else if (onc_signature_ == &kEAPSignature)
+  else if (onc_signature_ == &chromeos::onc::kEAPSignature)
     TranslateEAP();
-  else if (onc_signature_ == &kStaticIPConfigSignature)
+  else if (onc_signature_ == &chromeos::onc::kStaticIPConfigSignature)
     TranslateStaticIPConfig();
   else
     CopyFieldsAccordingToSignature();
@@ -491,8 +491,8 @@
   if (!value)
     return;
 
-  const OncFieldSignature* field_signature =
-      GetFieldSignature(*onc_signature_, onc_field_name);
+  const chromeos::onc::OncFieldSignature* field_signature =
+      chromeos::onc::GetFieldSignature(*onc_signature_, onc_field_name);
   if (field_signature) {
     base::Value::Type expected_type =
         field_signature->value_signature->onc_type;
@@ -541,7 +541,7 @@
 // Iterates recursively over |onc_object| and its |signature|. At each object
 // applies the local translation using LocalTranslator::TranslateFields. The
 // results are written to |shill_dictionary|.
-void TranslateONCHierarchy(const OncValueSignature& signature,
+void TranslateONCHierarchy(const chromeos::onc::OncValueSignature& signature,
                            const base::Value& onc_object,
                            base::Value* shill_dictionary) {
   const std::vector<std::string> path =
@@ -564,8 +564,8 @@
     if (!it.second.is_dict())
       continue;
 
-    const OncFieldSignature* field_signature =
-        GetFieldSignature(signature, it.first);
+    const chromeos::onc::OncFieldSignature* field_signature =
+        chromeos::onc::GetFieldSignature(signature, it.first);
     if (!field_signature) {
       NET_LOG(ERROR) << "Unexpected or deprecated ONC key: " << it.first;
       continue;
@@ -577,8 +577,9 @@
 
 }  // namespace
 
-base::Value TranslateONCObjectToShill(const OncValueSignature* onc_signature,
-                                      const base::Value& onc_object) {
+base::Value TranslateONCObjectToShill(
+    const chromeos::onc::OncValueSignature* onc_signature,
+    const base::Value& onc_object) {
   CHECK(onc_signature != NULL);
   base::Value shill_dictionary(base::Value::Type::DICTIONARY);
   TranslateONCHierarchy(*onc_signature, onc_object, &shill_dictionary);
diff --git a/chromeos/ash/components/network/onc/onc_translator_shill_to_onc.cc b/chromeos/ash/components/network/onc/onc_translator_shill_to_onc.cc
index 4c8b3c7..9ffab73 100644
--- a/chromeos/ash/components/network/onc/onc_translator_shill_to_onc.cc
+++ b/chromeos/ash/components/network/onc/onc_translator_shill_to_onc.cc
@@ -89,7 +89,7 @@
  public:
   ShillToONCTranslator(const base::Value& shill_dictionary,
                        ::onc::ONCSource onc_source,
-                       const OncValueSignature& onc_signature,
+                       const chromeos::onc::OncValueSignature& onc_signature,
                        const NetworkState* network_state)
       : shill_dictionary_(&shill_dictionary),
         onc_source_(onc_source),
@@ -100,7 +100,7 @@
 
   ShillToONCTranslator(const base::Value& shill_dictionary,
                        ::onc::ONCSource onc_source,
-                       const OncValueSignature& onc_signature,
+                       const chromeos::onc::OncValueSignature& onc_signature,
                        const FieldTranslationEntry* field_translation_table,
                        const NetworkState* network_state)
       : shill_dictionary_(&shill_dictionary),
@@ -168,7 +168,7 @@
   // Applies function CopyProperty to each field of |value_signature| and its
   // base signatures.
   void CopyPropertiesAccordingToSignature(
-      const OncValueSignature* value_signature);
+      const chromeos::onc::OncValueSignature* value_signature);
 
   // Applies function CopyProperty to each field of |onc_signature_| and its
   // base signatures.
@@ -176,14 +176,14 @@
 
   // If |shill_property_name| is defined in |field_signature|, copies this
   // entry from |shill_dictionary_| to |onc_object_| if it exists.
-  void CopyProperty(const OncFieldSignature* field_signature);
+  void CopyProperty(const chromeos::onc::OncFieldSignature* field_signature);
 
   // Applies defaults to fields according to |onc_signature_|.
   void SetDefaultsAccordingToSignature();
 
   // Applies defaults to fields according to |value_signature|.
   void SetDefaultsAccordingToSignature(
-      const OncValueSignature* value_signature);
+      const chromeos::onc::OncValueSignature* value_signature);
 
   // If existent, translates the entry at |shill_property_name| in
   // |shill_dictionary_| using |table|. It is an error if no matching table
@@ -199,7 +199,7 @@
 
   const base::Value* shill_dictionary_;
   ::onc::ONCSource onc_source_;
-  const OncValueSignature* onc_signature_;
+  const chromeos::onc::OncValueSignature* onc_signature_;
   const FieldTranslationEntry* field_translation_table_;
   base::Value onc_object_;
   const NetworkState* network_state_;
@@ -207,34 +207,34 @@
 
 base::Value ShillToONCTranslator::CreateTranslatedONCObject() {
   onc_object_ = base::Value(base::Value::Type::DICTIONARY);
-  if (onc_signature_ == &kNetworkWithStateSignature) {
+  if (onc_signature_ == &chromeos::onc::kNetworkWithStateSignature) {
     TranslateNetworkWithState();
-  } else if (onc_signature_ == &kEthernetSignature) {
+  } else if (onc_signature_ == &chromeos::onc::kEthernetSignature) {
     TranslateEthernet();
-  } else if (onc_signature_ == &kVPNSignature) {
+  } else if (onc_signature_ == &chromeos::onc::kVPNSignature) {
     TranslateVPN();
-  } else if (onc_signature_ == &kOpenVPNSignature) {
+  } else if (onc_signature_ == &chromeos::onc::kOpenVPNSignature) {
     TranslateOpenVPN();
-  } else if (onc_signature_ == &kIPsecSignature) {
+  } else if (onc_signature_ == &chromeos::onc::kIPsecSignature) {
     TranslateIPsec();
-  } else if (onc_signature_ == &kL2TPSignature) {
+  } else if (onc_signature_ == &chromeos::onc::kL2TPSignature) {
     TranslateL2TP();
-  } else if (onc_signature_ == &kThirdPartyVPNSignature) {
+  } else if (onc_signature_ == &chromeos::onc::kThirdPartyVPNSignature) {
     TranslateThirdPartyVPN();
-  } else if (onc_signature_ == &kWiFiWithStateSignature) {
+  } else if (onc_signature_ == &chromeos::onc::kWiFiWithStateSignature) {
     TranslateWiFiWithState();
-  } else if (onc_signature_ == &kCellularWithStateSignature) {
+  } else if (onc_signature_ == &chromeos::onc::kCellularWithStateSignature) {
     if (field_translation_table_ == kCellularDeviceTable)
       TranslateCellularDevice();
     else
       TranslateCellularWithState();
-  } else if (onc_signature_ == &kIPConfigSignature) {
+  } else if (onc_signature_ == &chromeos::onc::kIPConfigSignature) {
     TranslateIPConfig();
-  } else if (onc_signature_ == &kSavedIPConfigSignature) {
+  } else if (onc_signature_ == &chromeos::onc::kSavedIPConfigSignature) {
     TranslateSavedIPConfig();
-  } else if (onc_signature_ == &kStaticIPConfigSignature) {
+  } else if (onc_signature_ == &chromeos::onc::kStaticIPConfigSignature) {
     TranslateStaticIPConfig();
-  } else if (onc_signature_ == &kEAPSignature) {
+  } else if (onc_signature_ == &chromeos::onc::kEAPSignature) {
     TranslateEap();
   } else {
     CopyPropertiesAccordingToSignature();
@@ -278,7 +278,8 @@
                            kOpenVpnCompressionAlgorithmTable,
                            ::onc::openvpn::kCompressionAlgorithm);
 
-  for (const OncFieldSignature* field_signature = onc_signature_->fields;
+  for (const chromeos::onc::OncFieldSignature* field_signature =
+           onc_signature_->fields;
        field_signature->onc_field_name != NULL; ++field_signature) {
     const std::string& onc_field_name = field_signature->onc_field_name;
     if (onc_field_name == ::onc::openvpn::kRemoteCertKU ||
@@ -431,7 +432,8 @@
         {::onc::vpn::kIPsec, ::onc::ipsec::kAuthenticationType}, "."));
     if (auth_type && *auth_type == ::onc::ipsec::kEAP) {
       ShillToONCTranslator eap_translator(*shill_dictionary_, onc_source_,
-                                          kEAPSignature, network_state_);
+                                          chromeos::onc::kEAPSignature,
+                                          network_state_);
       base::Value eap_object = eap_translator.CreateTranslatedONCObject();
       if (!eap_object.DictEmpty()) {
         onc_object_.SetPath(
@@ -519,8 +521,9 @@
     // Merge the Device dictionary with this one (Cellular) using the
     // CellularDevice signature.
     ShillToONCTranslator nested_translator(
-        *device_dictionary, onc_source_, kCellularWithStateSignature,
-        kCellularDeviceTable, network_state_);
+        *device_dictionary, onc_source_,
+        chromeos::onc::kCellularWithStateSignature, kCellularDeviceTable,
+        network_state_);
     base::Value nested_object = nested_translator.CreateTranslatedONCObject();
     onc_object_.MergeDictionary(&nested_object);
 
@@ -846,8 +849,8 @@
 void ShillToONCTranslator::TranslateAndAddNestedObject(
     const std::string& onc_field_name,
     const base::Value& dictionary) {
-  const OncFieldSignature* field_signature =
-      GetFieldSignature(*onc_signature_, onc_field_name);
+  const chromeos::onc::OncFieldSignature* field_signature =
+      chromeos::onc::GetFieldSignature(*onc_signature_, onc_field_name);
   if (!field_signature) {
     NET_LOG(ERROR) << "Unable to find signature for field: " << onc_field_name;
     return;
@@ -861,8 +864,8 @@
     const std::string& onc_field_name,
     const base::Value& dictionary,
     const FieldTranslationEntry* field_translation_table) {
-  const OncFieldSignature* field_signature =
-      GetFieldSignature(*onc_signature_, onc_field_name);
+  const chromeos::onc::OncFieldSignature* field_signature =
+      chromeos::onc::GetFieldSignature(*onc_signature_, onc_field_name);
   if (!field_signature) {
     NET_LOG(ERROR) << "Unable to find signature for field: " << onc_field_name;
     return;
@@ -886,8 +889,8 @@
 void ShillToONCTranslator::TranslateAndAddListOfObjects(
     const std::string& onc_field_name,
     const base::Value& list) {
-  const OncFieldSignature* field_signature =
-      GetFieldSignature(*onc_signature_, onc_field_name);
+  const chromeos::onc::OncFieldSignature* field_signature =
+      chromeos::onc::GetFieldSignature(*onc_signature_, onc_field_name);
   if (field_signature->value_signature->onc_type != base::Value::Type::LIST) {
     NET_LOG(ERROR) << "ONC Field name: '" << onc_field_name << "' has type '"
                    << field_signature->value_signature->onc_type
@@ -921,19 +924,20 @@
 }
 
 void ShillToONCTranslator::CopyPropertiesAccordingToSignature(
-    const OncValueSignature* value_signature) {
+    const chromeos::onc::OncValueSignature* value_signature) {
   if (value_signature->base_signature)
     CopyPropertiesAccordingToSignature(value_signature->base_signature);
   if (!value_signature->fields)
     return;
-  for (const OncFieldSignature* field_signature = value_signature->fields;
+  for (const chromeos::onc::OncFieldSignature* field_signature =
+           value_signature->fields;
        field_signature->onc_field_name != NULL; ++field_signature) {
     CopyProperty(field_signature);
   }
 }
 
 void ShillToONCTranslator::CopyProperty(
-    const OncFieldSignature* field_signature) {
+    const chromeos::onc::OncFieldSignature* field_signature) {
   std::string shill_property_name;
   if (!field_translation_table_ ||
       !GetShillPropertyName(field_signature->onc_field_name,
@@ -965,12 +969,13 @@
 }
 
 void ShillToONCTranslator::SetDefaultsAccordingToSignature(
-    const OncValueSignature* value_signature) {
+    const chromeos::onc::OncValueSignature* value_signature) {
   if (value_signature->base_signature)
     SetDefaultsAccordingToSignature(value_signature->base_signature);
   if (!value_signature->fields)
     return;
-  for (const OncFieldSignature* field_signature = value_signature->fields;
+  for (const chromeos::onc::OncFieldSignature* field_signature =
+           value_signature->fields;
        field_signature->onc_field_name != nullptr; ++field_signature) {
     if (!field_signature->default_value_setter)
       continue;
@@ -1012,7 +1017,7 @@
 base::Value TranslateShillServiceToONCPart(
     const base::Value& shill_dictionary,
     ::onc::ONCSource onc_source,
-    const OncValueSignature* onc_signature,
+    const chromeos::onc::OncValueSignature* onc_signature,
     const NetworkState* network_state) {
   CHECK(onc_signature != NULL);
 
diff --git a/chromeos/ash/components/network/onc/onc_translator_unittest.cc b/chromeos/ash/components/network/onc/onc_translator_unittest.cc
index f3bd3023..24ccba1 100644
--- a/chromeos/ash/components/network/onc/onc_translator_unittest.cc
+++ b/chromeos/ash/components/network/onc/onc_translator_unittest.cc
@@ -29,8 +29,8 @@
   base::Value expected_shill_network =
       test_utils::ReadTestDictionaryValue(result_shill_filename);
 
-  base::Value translation =
-      TranslateONCObjectToShill(&kNetworkConfigurationSignature, onc_network);
+  base::Value translation = TranslateONCObjectToShill(
+      &chromeos::onc::kNetworkConfigurationSignature, onc_network);
 
   EXPECT_TRUE(test_utils::Equals(&expected_shill_network, &translation));
 }
@@ -106,8 +106,8 @@
       test_utils::ReadTestDictionaryValue(result_onc_filename);
 
   base::Value translation = TranslateShillServiceToONCPart(
-      shill_network, ::onc::ONC_SOURCE_NONE, &kNetworkWithStateSignature,
-      nullptr /* network_state */);
+      shill_network, ::onc::ONC_SOURCE_NONE,
+      &chromeos::onc::kNetworkWithStateSignature, nullptr /* network_state */);
 
   EXPECT_TRUE(test_utils::Equals(&expected_onc_network, &translation));
 }
diff --git a/chromeos/ash/components/network/policy_applicator.cc b/chromeos/ash/components/network/policy_applicator.cc
index e43ba8b..77c2331 100644
--- a/chromeos/ash/components/network/policy_applicator.cc
+++ b/chromeos/ash/components/network/policy_applicator.cc
@@ -186,7 +186,7 @@
 
   base::Value onc_part = onc::TranslateShillServiceToONCPart(
       entry_properties, ::onc::ONC_SOURCE_UNKNOWN,
-      &onc::kNetworkWithStateSignature, nullptr /* network_state */);
+      &chromeos::onc::kNetworkWithStateSignature, nullptr /* network_state */);
 
   std::string old_guid = GetGUIDFromONCPart(onc_part);
   std::unique_ptr<NetworkUIData> ui_data =
diff --git a/chromeos/ash/components/network/policy_util.cc b/chromeos/ash/components/network/policy_util.cc
index 641667fb..f53a7f24 100644
--- a/chromeos/ash/components/network/policy_util.cc
+++ b/chromeos/ash/components/network/policy_util.cc
@@ -38,7 +38,7 @@
 
 // Removes all kFakeCredential values from sensitive fields (determined by
 // onc::FieldIsCredential) of |onc_object|.
-void RemoveFakeCredentials(const onc::OncValueSignature& signature,
+void RemoveFakeCredentials(const chromeos::onc::OncValueSignature& signature,
                            base::Value* onc_object) {
   std::vector<std::string> entries_to_remove;
   for (auto iter : onc_object->DictItems()) {
@@ -47,8 +47,8 @@
 
     // If |value| is a dictionary, recurse.
     if (value->is_dict()) {
-      const onc::OncFieldSignature* field_signature =
-          onc::GetFieldSignature(signature, field_name);
+      const chromeos::onc::OncFieldSignature* field_signature =
+          chromeos::onc::GetFieldSignature(signature, field_name);
       if (field_signature)
         RemoveFakeCredentials(*field_signature->value_signature, value);
       else
@@ -57,7 +57,8 @@
     }
 
     // If |value| is a string, check if it is a fake credential.
-    if (value->is_string() && onc::FieldIsCredential(signature, field_name)) {
+    if (value->is_string() &&
+        chromeos::onc::FieldIsCredential(signature, field_name)) {
       if (value->GetString() == kFakeCredential) {
         // The value wasn't modified by the UI, thus we remove the field to keep
         // the existing value that is stored in Shill.
@@ -177,7 +178,7 @@
 
   // This call also removes credentials from policies.
   base::Value augmented_onc_network = onc::MergeSettingsAndPoliciesToAugmented(
-      onc::kNetworkConfigurationSignature, user_policy, device_policy,
+      chromeos::onc::kNetworkConfigurationSignature, user_policy, device_policy,
       nonshared_user_settings, shared_user_settings, active_settings);
 
   // If present, apply the Autoconnect policy only to networks that are not
@@ -263,17 +264,18 @@
     NOTREACHED();
   }
 
-  RemoveFakeCredentials(onc::kNetworkConfigurationSignature, &effective);
+  RemoveFakeCredentials(chromeos::onc::kNetworkConfigurationSignature,
+                        &effective);
 
   effective.SetKey(::onc::network_config::kGUID, base::Value(guid));
 
   // Remove irrelevant fields.
   onc::Normalizer normalizer(true /* remove recommended fields */);
-  effective = normalizer.NormalizeObject(&onc::kNetworkConfigurationSignature,
-                                         effective);
+  effective = normalizer.NormalizeObject(
+      &chromeos::onc::kNetworkConfigurationSignature, effective);
 
   base::Value shill_dictionary = onc::TranslateONCObjectToShill(
-      &onc::kNetworkConfigurationSignature, effective);
+      &chromeos::onc::kNetworkConfigurationSignature, effective);
   shill_dictionary.SetKey(shill::kProfileProperty, base::Value(profile.path));
 
   // If AutoConnect is enabled by policy, set the ManagedCredentials property to
@@ -319,7 +321,8 @@
     const std::string credential_mask =
         saving_credentials ? kFakeCredential : std::string();
     base::Value sanitized_user_settings = onc::MaskCredentialsInOncObject(
-        onc::kNetworkConfigurationSignature, *user_settings, credential_mask);
+        chromeos::onc::kNetworkConfigurationSignature, *user_settings,
+        credential_mask);
     ui_data->SetUserSettingsDictionary(std::move(sanitized_user_settings));
   }
 
diff --git a/chromeos/ash/components/network/profile_policies.cc b/chromeos/ash/components/network/profile_policies.cc
index 98128db9..0a77ed44 100644
--- a/chromeos/ash/components/network/profile_policies.cc
+++ b/chromeos/ash/components/network/profile_policies.cc
@@ -50,9 +50,9 @@
   // cloning if the variable expansion doesn't change anything when this is the
   // only caller of ExpandStringsInOncObject.
   base::Value expanded = onc_network_configuration.Clone();
-  VariableExpander variable_expander(
+  chromeos::VariableExpander variable_expander(
       GetAllExpansions(profile_wide_expansions, resolved_cert));
-  onc::ExpandStringsInOncObject(onc::kNetworkConfigurationSignature,
+  onc::ExpandStringsInOncObject(chromeos::onc::kNetworkConfigurationSignature,
                                 variable_expander, &expanded);
   client_cert::SetResolvedCertInOnc(resolved_cert, expanded);
   return expanded;
diff --git a/chromeos/ash/resources/BUILD.gn b/chromeos/ash/resources/BUILD.gn
index 00b0742..5bad8e5 100644
--- a/chromeos/ash/resources/BUILD.gn
+++ b/chromeos/ash/resources/BUILD.gn
@@ -32,6 +32,7 @@
     "//ash/services/device_sync/public/mojom:mojom_js",
     "//ash/services/multidevice_setup/public/mojom:mojom_js",
     "//chromeos/ash/components/human_presence:human_presence_internals_ts",
+    "//chromeos/ash/components/language/public/mojom:mojom_js",
     "//chromeos/ash/services/auth_factor_config/public/mojom:mojom_js",
   ]
 }
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd
index f0afc58a..6775c26d 100644
--- a/chromeos/chromeos_strings.grd
+++ b/chromeos/chromeos_strings.grd
@@ -2886,7 +2886,7 @@
         Perform RMA Server Unlock
       </message>
       <message name="IDS_SHIMLESS_RMA_RSU_CODE_INSTRUCTIONS" translateable="false" desc="Instructions for the RSU challenge page.">
-        Use this QR code to get the 8 character unlock code. You can also manually type <ph name="LINK_BEGIN">&lt;a&gt;</ph>this URL<ph name="LINK_END">&lt;/a&gt;</ph>.
+        Use this QR code to get the 8 character unlock code. You can also manually type <ph name="LINK_BEGIN">&lt;a id="rsuCodeDialogLink"&gt;</ph>this URL<ph name="LINK_END">&lt;/a&gt;</ph>.
       </message>
       <message name="IDS_SHIMLESS_RMA_RSU_CODE_LABEL" translateable="false" desc="Label for the RSU code input box.">
         Enter the 8-characters
diff --git a/chromeos/components/onc/onc_mapper.h b/chromeos/components/onc/onc_mapper.h
index cc65554..181ec2c 100644
--- a/chromeos/components/onc/onc_mapper.h
+++ b/chromeos/components/onc/onc_mapper.h
@@ -103,9 +103,4 @@
 }  // namespace onc
 }  // namespace chromeos
 
-// TODO(https://crbug.com/1164001): remove when it moved to ash.
-namespace ash::onc {
-using ::chromeos::onc::Mapper;
-}
-
 #endif  // CHROMEOS_COMPONENTS_ONC_ONC_MAPPER_H_
diff --git a/chromeos/components/onc/onc_parsed_certificates.h b/chromeos/components/onc/onc_parsed_certificates.h
index f166d7b..86c0e43 100644
--- a/chromeos/components/onc/onc_parsed_certificates.h
+++ b/chromeos/components/onc/onc_parsed_certificates.h
@@ -140,9 +140,4 @@
 }  // namespace onc
 }  // namespace chromeos
 
-// TODO(https://crbug.com/1164001): remove when it moved to ash.
-namespace ash::onc {
-using ::chromeos::onc::OncParsedCertificates;
-}
-
 #endif  // CHROMEOS_COMPONENTS_ONC_ONC_PARSED_CERTIFICATES_H_
diff --git a/chromeos/components/onc/onc_signature.h b/chromeos/components/onc/onc_signature.h
index cabcf2d..42a660983 100644
--- a/chromeos/components/onc/onc_signature.h
+++ b/chromeos/components/onc/onc_signature.h
@@ -134,55 +134,4 @@
 }  // namespace onc
 }  // namespace chromeos
 
-// TODO(https://crbug.com/1164001): remove when it moved to ash.
-namespace ash::onc {
-using ::chromeos::onc::FieldIsCredential;
-using ::chromeos::onc::GetFieldSignature;
-using ::chromeos::onc::kARCVPNSignature;
-using ::chromeos::onc::kCellularApnSignature;
-using ::chromeos::onc::kCellularFoundNetworkSignature;
-using ::chromeos::onc::kCellularPaymentPortalSignature;
-using ::chromeos::onc::kCellularProviderSignature;
-using ::chromeos::onc::kCellularSignature;
-using ::chromeos::onc::kCellularWithStateSignature;
-using ::chromeos::onc::kCertificateListSignature;
-using ::chromeos::onc::kCertificatePatternSignature;
-using ::chromeos::onc::kCertificateSignature;
-using ::chromeos::onc::kEAPSignature;
-using ::chromeos::onc::kEAPSubjectAlternativeNameMatchListSignature;
-using ::chromeos::onc::kEAPSubjectAlternativeNameMatchSignature;
-using ::chromeos::onc::kEthernetSignature;
-using ::chromeos::onc::kGlobalNetworkConfigurationSignature;
-using ::chromeos::onc::kIPConfigSignature;
-using ::chromeos::onc::kIPsecSignature;
-using ::chromeos::onc::kIssuerSubjectPatternSignature;
-using ::chromeos::onc::kL2TPSignature;
-using ::chromeos::onc::kNetworkConfigurationListSignature;
-using ::chromeos::onc::kNetworkConfigurationSignature;
-using ::chromeos::onc::kNetworkWithStateSignature;
-using ::chromeos::onc::kOpenVPNSignature;
-using ::chromeos::onc::kProxyLocationSignature;
-using ::chromeos::onc::kProxyManualSignature;
-using ::chromeos::onc::kProxySettingsSignature;
-using ::chromeos::onc::kRecommendedSignature;
-using ::chromeos::onc::kSavedIPConfigSignature;
-using ::chromeos::onc::kScopeSignature;
-using ::chromeos::onc::kSIMLockStatusSignature;
-using ::chromeos::onc::kStaticIPConfigSignature;
-using ::chromeos::onc::kTetherSignature;
-using ::chromeos::onc::kTetherWithStateSignature;
-using ::chromeos::onc::kThirdPartyVPNSignature;
-using ::chromeos::onc::kToplevelConfigurationSignature;
-using ::chromeos::onc::kVerifyX509Signature;
-using ::chromeos::onc::kVPNSignature;
-using ::chromeos::onc::kWiFiSignature;
-using ::chromeos::onc::kWiFiWithStateSignature;
-using ::chromeos::onc::kWireGuardPeerListSignature;
-using ::chromeos::onc::kWireGuardPeerSignature;
-using ::chromeos::onc::kWireGuardSignature;
-using ::chromeos::onc::kXAUTHSignature;
-using ::chromeos::onc::OncFieldSignature;
-using ::chromeos::onc::OncValueSignature;
-}  // namespace ash::onc
-
 #endif  // CHROMEOS_COMPONENTS_ONC_ONC_SIGNATURE_H_
diff --git a/chromeos/components/onc/onc_validator.h b/chromeos/components/onc/onc_validator.h
index 877c8c7..82ca0690 100644
--- a/chromeos/components/onc/onc_validator.h
+++ b/chromeos/components/onc/onc_validator.h
@@ -290,9 +290,4 @@
 }  // namespace onc
 }  // namespace chromeos
 
-// TODO(https://crbug.com/1164001): remove when it moved to ash.
-namespace ash::onc {
-using ::chromeos::onc::Validator;
-}
-
 #endif  // CHROMEOS_COMPONENTS_ONC_ONC_VALIDATOR_H_
diff --git a/chromeos/components/onc/variable_expander.h b/chromeos/components/onc/variable_expander.h
index cadbe951..e0c91cf 100644
--- a/chromeos/components/onc/variable_expander.h
+++ b/chromeos/components/onc/variable_expander.h
@@ -56,10 +56,4 @@
 
 }  // namespace chromeos
 
-// TODO(https://crbug.com/1164001): remove when chromeos/network is moved to
-// ash.
-namespace ash {
-using ::chromeos::VariableExpander;
-}  // namespace ash
-
 #endif  // CHROMEOS_COMPONENTS_ONC_VARIABLE_EXPANDER_H_
diff --git a/chromeos/profiles/atom.afdo.newest.txt b/chromeos/profiles/atom.afdo.newest.txt
index 4b292e25..5c2cb94 100644
--- a/chromeos/profiles/atom.afdo.newest.txt
+++ b/chromeos/profiles/atom.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-atom-107-5249.12-1661766978-benchmark-107.0.5270.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-atom-107-5249.12-1661766978-benchmark-107.0.5271.0-r1-redacted.afdo.xz
diff --git a/chromeos/resources/BUILD.gn b/chromeos/resources/BUILD.gn
index f7f5687..b710de9 100644
--- a/chromeos/resources/BUILD.gn
+++ b/chromeos/resources/BUILD.gn
@@ -23,7 +23,6 @@
   ]
 
   deps = [
-    "//chromeos/language/public/mojom:mojom_js",
     "//chromeos/services/bluetooth_config/public/mojom:mojom_js",
 
     # Generated ml service js bindings are required by external clients, the
diff --git a/chromeos/services/hotspot_config/public/mojom/cros_hotspot_config.mojom b/chromeos/services/hotspot_config/public/mojom/cros_hotspot_config.mojom
index 742712a..c82b422 100644
--- a/chromeos/services/hotspot_config/public/mojom/cros_hotspot_config.mojom
+++ b/chromeos/services/hotspot_config/public/mojom/cros_hotspot_config.mojom
@@ -49,3 +49,20 @@
   // Failed for invalid hotspot configuration.
   kFailedInvalidConfiguration,
 };
+
+// Status about whether Hotspot is allowed or not.
+enum HotspotAllowStatus {
+  // Disallowed because Cellular is not a supported upstream technology.
+  kDisallowedNoCellularUpstream,
+  // Disallowed because WiFi is not a supported downstream technology.
+  kDisallowedNoWiFiDownstream,
+  // Disallowed because no WiFi security modes are supported.
+  kDisallowedNoWiFiSecurityModes,
+  // Disallowed because there's no upstream mobile data connectivity.
+  kDisallowedNoMobileData,
+  // Disallowed because the tethering readiness check failed.
+  kDisallowedReadinessCheckFail,
+  // Disallowed because policy prohibited.
+  kDisallowedByPolicy,
+  kAllowed,
+};
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/gesture/BackPressHandler.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/gesture/BackPressHandler.java
index a467fd0e..6038f34a 100644
--- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/gesture/BackPressHandler.java
+++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/gesture/BackPressHandler.java
@@ -41,7 +41,7 @@
         int FULLSCREEN = 7;
         int BOTTOM_SHEET = 8;
         int TAB_MODAL_HANDLER = 9;
-        int TAB_SWITCHER_TO_BROWSING = 10;
+        int TAB_SWITCHER_TO_BROWSING = 10; // Removed.
         int CLOSE_WATCHER = 11;
         int FIND_TOOLBAR = 12;
         int LOCATION_BAR = 13;
diff --git a/components/services/app_service/public/cpp/app_registry_cache.cc b/components/services/app_service/public/cpp/app_registry_cache.cc
index 291bc30..b40c3c69 100644
--- a/components/services/app_service/public/cpp/app_registry_cache.cc
+++ b/components/services/app_service/public/cpp/app_registry_cache.cc
@@ -62,9 +62,6 @@
 
   if (should_notify_initialized) {
     DCHECK_NE(apps::mojom::AppType::kUnknown, app_type);
-    if (!IsAppTypeInitialized(ConvertMojomAppTypToAppType(app_type))) {
-      in_progress_initialized_mojom_app_types_.insert(app_type);
-    }
   }
 
   if (!mojom_deltas_in_progress_.empty()) {
@@ -79,8 +76,6 @@
     pending.swap(mojom_deltas_pending_);
     DoOnApps(std::move(pending));
   }
-
-  OnAppTypeInitialized();
 }
 
 void AppRegistryCache::OnApps(std::vector<AppPtr> deltas,
@@ -292,33 +287,21 @@
 }
 
 void AppRegistryCache::OnAppTypeInitialized() {
-  // Check both the non mojom and mojom initialized status. Only when they are
-  // not initialized, call OnAppTypeInitialized to notify observers, because
-  // observers might use the non mojom or mojom App struct.
-  //
-  // TODO(crbug.com/1253250): Remove the mojom initialized checking when all
-  // observers use the non mojom App struct only.
-  if (in_progress_initialized_mojom_app_types_.empty() ||
-      in_progress_initialized_app_types_.empty()) {
+  if (in_progress_initialized_app_types_.empty()) {
     return;
   }
 
-  // In observer's OnAppTypeInitialized callback, `OnApp` might be call  to
+  // In observer's OnAppTypeInitialized callback, `OnApp` might be called to
   // update the app, then this OnAppTypeInitialized might be called again. So we
   // need to check the initialized `app_type` first, and remove it from
   // `in_progress_initialized_app_types_` to prevent the dead loop.
   std::set<AppType> in_progress_initialized_app_types;
   for (auto app_type : in_progress_initialized_app_types_) {
-    if (base::Contains(in_progress_initialized_mojom_app_types_,
-                       ConvertAppTypeToMojomAppType(app_type))) {
-      in_progress_initialized_app_types.insert(app_type);
-    }
+    in_progress_initialized_app_types.insert(app_type);
   }
 
   for (auto app_type : in_progress_initialized_app_types) {
-    auto mojom_app_type = ConvertAppTypeToMojomAppType(app_type);
     in_progress_initialized_app_types_.erase(app_type);
-    in_progress_initialized_mojom_app_types_.erase(mojom_app_type);
     initialized_app_types_.insert(app_type);
     for (auto& obs : observers_) {
       obs.OnAppTypeInitialized(app_type);
diff --git a/components/services/app_service/public/cpp/app_registry_cache.h b/components/services/app_service/public/cpp/app_registry_cache.h
index e2448a8..c1e69291 100644
--- a/components/services/app_service/public/cpp/app_registry_cache.h
+++ b/components/services/app_service/public/cpp/app_registry_cache.h
@@ -233,7 +233,6 @@
 
   // Saves app types which will finish initialization, and OnAppTypeInitialized
   // will be called to notify observers.
-  std::set<apps::mojom::AppType> in_progress_initialized_mojom_app_types_;
   std::set<AppType> in_progress_initialized_app_types_;
 
   // Saves app types which have finished initialization, and
diff --git a/components/services/app_service/public/cpp/app_registry_cache_unittest.cc b/components/services/app_service/public/cpp/app_registry_cache_unittest.cc
index dbf648889..0b0123f 100644
--- a/components/services/app_service/public/cpp/app_registry_cache_unittest.cc
+++ b/components/services/app_service/public/cpp/app_registry_cache_unittest.cc
@@ -975,13 +975,13 @@
   cache.OnApps(std::move(deltas1), AppType::kArc,
                true /* should_notify_initialized */);
 
-  // Verify OnAppTypeInitialized is not called when the non mojom Apps are
+  // Verify OnAppTypeInitialized is called when the non mojom Apps are
   // added.
-  EXPECT_TRUE(observer1.app_types().empty());
-  EXPECT_EQ(0, observer1.initialized_app_type_count());
-  EXPECT_EQ(0, observer1.app_count_at_initialization());
-  EXPECT_EQ(0u, cache.InitializedAppTypes().size());
-  EXPECT_FALSE(cache.IsAppTypeInitialized(AppType::kArc));
+  EXPECT_TRUE(base::Contains(observer1.app_types(), AppType::kArc));
+  EXPECT_EQ(1, observer1.initialized_app_type_count());
+  EXPECT_EQ(2, observer1.app_count_at_initialization());
+  EXPECT_EQ(1u, cache.InitializedAppTypes().size());
+  EXPECT_TRUE(cache.IsAppTypeInitialized(AppType::kArc));
 
   std::vector<apps::mojom::AppPtr> mojom_deltas1;
   mojom_deltas1.push_back(MakeMojomApp("a", "avocado"));
@@ -989,8 +989,7 @@
   cache.OnApps(std::move(mojom_deltas1), apps::mojom::AppType::kArc,
                true /* should_notify_initialized */);
 
-  // Verify OnAppTypeInitialized is called when both the non mojom and mojom
-  // Apps are added.
+  // Verify OnAppTypeInitialized is not called.
   EXPECT_TRUE(base::Contains(observer1.app_types(), AppType::kArc));
   EXPECT_EQ(1, observer1.initialized_app_type_count());
   EXPECT_EQ(2, observer1.app_count_at_initialization());
@@ -1090,12 +1089,13 @@
   cache.OnApps(std::move(deltas1), AppType::kArc,
                true /* should_notify_initialized */);
 
-  // Verify OnAppTypeInitialized is not called when the non mojom Apps are
+  // Verify OnAppTypeInitialized is called when the non mojom Apps are
   // added.
-  EXPECT_TRUE(observer1.app_types().empty());
-  EXPECT_EQ(0, observer1.initialized_app_type_count());
-  EXPECT_EQ(0, observer1.app_count_at_initialization());
-  EXPECT_TRUE(cache.InitializedAppTypes().empty());
+  EXPECT_TRUE(base::Contains(observer1.app_types(), AppType::kArc));
+  EXPECT_EQ(1, observer1.initialized_app_type_count());
+  EXPECT_EQ(2, observer1.app_count_at_initialization());
+  EXPECT_EQ(1u, cache.InitializedAppTypes().size());
+  EXPECT_TRUE(cache.IsAppTypeInitialized(AppType::kArc));
 
   std::vector<apps::mojom::AppPtr> mojom_deltas1;
   mojom_deltas1.push_back(MakeMojomApp("a", "avocado"));
@@ -1103,8 +1103,7 @@
   cache.OnApps(std::move(mojom_deltas1), apps::mojom::AppType::kArc,
                true /* should_notify_initialized */);
 
-  // Verify OnAppTypeInitialized is called when both the non mojom and mojom
-  // Apps are added.
+  // Verify OnAppTypeInitialized is not called.
   EXPECT_TRUE(base::Contains(observer1.app_types(), AppType::kArc));
   EXPECT_EQ(1, observer1.initialized_app_type_count());
   EXPECT_EQ(2, observer1.app_count_at_initialization());
@@ -1156,20 +1155,21 @@
   cache.OnApps(std::move(deltas1), AppType::kStandaloneBrowserChromeApp,
                true /* should_notify_initialized */);
 
-  // Verify OnAppTypeInitialized is not called when the non mojom Apps are
+  // Verify OnAppTypeInitialized is called when the non mojom Apps are
   // initialized.
-  EXPECT_TRUE(observer1.app_types().empty());
-  EXPECT_EQ(0, observer1.initialized_app_type_count());
+  EXPECT_TRUE(base::Contains(observer1.app_types(),
+                             AppType::kStandaloneBrowserChromeApp));
+  EXPECT_EQ(1, observer1.initialized_app_type_count());
   EXPECT_EQ(0, observer1.app_count_at_initialization());
-  EXPECT_TRUE(cache.InitializedAppTypes().empty());
+  EXPECT_EQ(1u, cache.InitializedAppTypes().size());
+  EXPECT_TRUE(cache.IsAppTypeInitialized(AppType::kStandaloneBrowserChromeApp));
 
   std::vector<apps::mojom::AppPtr> mojom_deltas1;
   cache.OnApps(std::move(mojom_deltas1),
                apps::mojom::AppType::kStandaloneBrowserChromeApp,
                true /* should_notify_initialized */);
 
-  // Verify OnAppTypeInitialized is called when both the mojom and non mojom
-  // Apps are initialized.
+  // Verify OnAppTypeInitialized is not called.
   EXPECT_TRUE(base::Contains(observer1.app_types(),
                              AppType::kStandaloneBrowserChromeApp));
   EXPECT_EQ(1, observer1.initialized_app_type_count());
diff --git a/content/browser/accessibility/accessibility_tree_formatter_blink.cc b/content/browser/accessibility/accessibility_tree_formatter_blink.cc
index b123d41..2201c43 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_blink.cc
+++ b/content/browser/accessibility/accessibility_tree_formatter_blink.cc
@@ -274,7 +274,7 @@
   ui::AXTreeManager* ax_mgr = ui::AXTreeManager::FromID(tree_id);
   DCHECK(ax_mgr);
   SetPropertyFilters(property_filters, kFiltersDefaultSet);
-  base::Value dict = BuildTreeForNode(ax_mgr->GetRootAsAXNode());
+  base::Value dict = BuildTreeForNode(ax_mgr->GetRoot());
   return FormatTree(dict);
 }
 
diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc
index 663790f..ea2cf77 100644
--- a/content/browser/accessibility/browser_accessibility_manager.cc
+++ b/content/browser/accessibility/browser_accessibility_manager.cc
@@ -357,7 +357,7 @@
 
 BrowserAccessibility* BrowserAccessibilityManager::GetBrowserAccessibilityRoot()
     const {
-  ui::AXNode* root = GetRootAsAXNode();
+  ui::AXNode* root = GetRoot();
   return root ? GetFromAXNode(root) : nullptr;
 }
 
@@ -1706,7 +1706,7 @@
   if (!parent_manager)
     return nullptr;
 
-  DCHECK(GetRootAsAXNode());
+  DCHECK(GetRoot());
 
   std::set<int32_t> host_node_ids =
       parent_manager->ax_tree()->GetNodeIdsForChildTreeId(ax_tree_id_);
@@ -1830,7 +1830,7 @@
       ax_serializable_tree()->CreateTreeSource());
   ui::AXTreeSerializer<const ui::AXNode*> serializer(tree_source.get());
   ui::AXTreeUpdate update;
-  serializer.SerializeChanges(GetRootAsAXNode(), &update);
+  serializer.SerializeChanges(GetRoot(), &update);
   return update;
 }
 
diff --git a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
index 8c8c81f..ee54c364 100644
--- a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
+++ b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
@@ -531,7 +531,7 @@
       BrowserAccessibilityManager::FromID(iframe_tree_id);
   ASSERT_NE(nullptr, iframe_manager);
 
-  const ui::AXNode* sub_document = iframe_manager->GetRootAsAXNode();
+  const ui::AXNode* sub_document = iframe_manager->GetRoot();
   EXPECT_EQ(ax::mojom::Role::kRootWebArea, sub_document->data().role);
   ASSERT_EQ(1u, sub_document->children().size());
 
diff --git a/content/browser/devtools/devtools_instrumentation.cc b/content/browser/devtools/devtools_instrumentation.cc
index 19cc663..919c3245 100644
--- a/content/browser/devtools/devtools_instrumentation.cc
+++ b/content/browser/devtools/devtools_instrumentation.cc
@@ -318,6 +318,11 @@
 
 void DidActivatePrerender(const NavigationRequest& nav_request) {
   FrameTreeNode* ftn = nav_request.frame_tree_node();
+  WebContentsImpl* web_contents = WebContentsImpl::FromFrameTreeNode(ftn);
+  // Record prerender activation here because users don't necessarily open
+  // DevTools when the activation is triggered. If the DevTools is not opened at
+  // the moment, recording the activation here will still preserve the signal.
+  web_contents->set_last_navigation_was_prerender_activation_for_devtools();
   DispatchToAgents(ftn, &protocol::PageHandler::DidActivatePrerender,
                    nav_request);
 }
diff --git a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
index acf3ede..34bf2fe 100644
--- a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
+++ b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -223,9 +223,18 @@
         prerender_helper_->GetPrerenderedMainFrameHost(host_id));
   }
 
- private:
+  void NavigatePrimaryPage(const GURL& url) {
+    prerender_helper_->NavigatePrimaryPage(url);
+  }
+
+  // WebContentsDelegate overrides.
+  bool IsPrerender2Supported(WebContents& web_contents) override {
+    return true;
+  }
+
   WebContents* web_contents() const { return shell()->web_contents(); }
 
+ private:
   std::unique_ptr<test::PrerenderTestHelper> prerender_helper_;
 };
 
@@ -3387,4 +3396,63 @@
       PrerenderHost::FinalStatus::kMojoBinderPolicy, 1);
 }
 
+IN_PROC_BROWSER_TEST_F(PrerenderDevToolsProtocolTest,
+                       RemoveStoredPrerenderActivationIfNavigateAway) {
+  base::HistogramTester histogram_tester;
+  ASSERT_TRUE(embedded_test_server()->Start());
+  const GURL kInitialUrl = GetUrl("/empty.html");
+  const GURL kPrerenderingUrl = GetUrl("/empty.html?prerender");
+  WebContentsImpl* web_contents_impl =
+      static_cast<WebContentsImpl*>(web_contents());
+
+  // Navigate to an initial page.
+  ASSERT_TRUE(NavigateToURL(shell(), kInitialUrl));
+
+  // Make a prerendered page.
+  AddPrerender(kPrerenderingUrl);
+
+  Attach();
+  SendCommandSync("Page.enable");
+  SendCommandSync("Runtime.enable");
+  NavigatePrimaryPage(kPrerenderingUrl);
+
+  WaitForNotification("Page.prerenderAttemptCompleted", true);
+
+  // Navigate away from the prerendered page, and this should trigger the
+  // mechanism of removing the stored prerender activation.
+  ASSERT_TRUE(NavigateToURL(shell(), kInitialUrl));
+  ASSERT_FALSE(web_contents_impl
+                   ->last_navigation_was_prerender_activation_for_devtools());
+}
+
+IN_PROC_BROWSER_TEST_F(PrerenderDevToolsProtocolTest,
+                       NewPrerenderActivationOverrideTheOldOne) {
+  base::HistogramTester histogram_tester;
+  ASSERT_TRUE(embedded_test_server()->Start());
+  const GURL kInitialUrl = GetUrl("/empty.html");
+  const GURL kPrerenderingUrl = GetUrl("/empty.html?prerender");
+  const GURL kPrerenderingUrl2 = GetUrl("/title1.html?prerender2");
+  WebContentsImpl* web_contents_impl =
+      static_cast<WebContentsImpl*>(web_contents());
+
+  // Navigate to an initial page.
+  ASSERT_TRUE(NavigateToURL(shell(), kInitialUrl));
+
+  // Make a prerendered page.
+  AddPrerender(kPrerenderingUrl);
+
+  Attach();
+  SendCommandSync("Page.enable");
+  SendCommandSync("Runtime.enable");
+  NavigatePrimaryPage(kPrerenderingUrl);
+
+  WaitForNotification("Page.prerenderAttemptCompleted", true);
+
+  // Trigger another prerender activation.
+  AddPrerender(kPrerenderingUrl2);
+  NavigatePrimaryPage(kPrerenderingUrl2);
+  ASSERT_TRUE(web_contents_impl
+                  ->last_navigation_was_prerender_activation_for_devtools());
+}
+
 }  // namespace content
diff --git a/content/browser/devtools/protocol/page_handler.cc b/content/browser/devtools/protocol/page_handler.cc
index d350c78..090ab72 100644
--- a/content/browser/devtools/protocol/page_handler.cc
+++ b/content/browser/devtools/protocol/page_handler.cc
@@ -54,6 +54,8 @@
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/common/referrer.h"
 #include "content/public/common/result_codes.h"
+#include "content/public/common/url_constants.h"
+#include "content/public/common/url_utils.h"
 #include "net/base/filename_util.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/common/manifest/manifest_util.h"
@@ -196,13 +198,12 @@
     EmulationHandler* emulation_handler,
     BrowserHandler* browser_handler,
     bool allow_unsafe_operations,
-    bool may_capture_screenshots_not_from_surface,
+    bool is_trusted,
     absl::optional<url::Origin> navigation_initiator_origin,
     bool may_read_local_files)
     : DevToolsDomainHandler(Page::Metainfo::domainName),
       allow_unsafe_operations_(allow_unsafe_operations),
-      may_capture_screenshots_not_from_surface_(
-          may_capture_screenshots_not_from_surface),
+      is_trusted_(is_trusted),
       navigation_initiator_origin_(navigation_initiator_origin),
       may_read_local_files_(may_read_local_files),
       enabled_(false),
@@ -345,6 +346,7 @@
 
 Response PageHandler::Enable() {
   enabled_ = true;
+  RetrievePrerenderActivationFromWebContents();
   return Response::FallThrough();
 }
 
@@ -497,6 +499,14 @@
     return;
   }
 
+  // chrome-untrusted:// WebUIs might perform high-priviledged actions on
+  // navigation, disallow navigation to them unless the client is trusted.
+  if (gurl.SchemeIs(kChromeUIUntrustedScheme) && !is_trusted_) {
+    callback->sendFailure(Response::ServerError(
+        "Navigating to a URL with a privileged scheme is not allowed"));
+    return;
+  }
+
   ui::PageTransition type;
   std::string transition_type =
       maybe_transition_type.fromMaybe(Page::TransitionTypeEnum::Typed);
@@ -781,7 +791,7 @@
 
   // We don't support clip/emulation when capturing from window, bail out.
   if (!from_surface.fromMaybe(true)) {
-    if (!may_capture_screenshots_not_from_surface_) {
+    if (!is_trusted_) {
       callback->sendFailure(
           Response::ServerError("Only screenshots from surface are allowed."));
       return;
@@ -1930,6 +1940,7 @@
 }
 
 void PageHandler::DidActivatePrerender(const NavigationRequest& nav_request) {
+  has_dispatched_stored_prerender_activation_ = false;
   if (!enabled_)
     return;
   FrameTreeNode* ftn = nav_request.frame_tree_node();
@@ -1944,6 +1955,7 @@
                                      const std::string& initiating_frame_id,
                                      PrerenderHost::FinalStatus status,
                                      const std::string& reason_details) {
+  has_dispatched_stored_prerender_activation_ = false;
   if (!enabled_)
     return;
   DCHECK_NE(status, PrerenderHost::FinalStatus::kActivated);
@@ -1959,5 +1971,21 @@
   return enabled_ && bypass_csp_;
 }
 
+void PageHandler::RetrievePrerenderActivationFromWebContents() {
+  if (!host_)
+    return;
+  WebContentsImpl* web_contents =
+      WebContentsImpl::FromRenderFrameHostImpl(host_);
+  if (web_contents->last_navigation_was_prerender_activation_for_devtools() &&
+      !has_dispatched_stored_prerender_activation_) {
+    std::string frame_token =
+        host_->frame_tree_node()->devtools_frame_token().ToString();
+    has_dispatched_stored_prerender_activation_ = true;
+    frontend_->PrerenderAttemptCompleted(
+        frame_token, host_->GetLastCommittedURL().spec(),
+        Page::PrerenderFinalStatusEnum::Activated);
+  }
+}
+
 }  // namespace protocol
 }  // namespace content
diff --git a/content/browser/devtools/protocol/page_handler.h b/content/browser/devtools/protocol/page_handler.h
index 1f38edf..3e38acc 100644
--- a/content/browser/devtools/protocol/page_handler.h
+++ b/content/browser/devtools/protocol/page_handler.h
@@ -67,7 +67,7 @@
   PageHandler(EmulationHandler* emulation_handler,
               BrowserHandler* browser_handler,
               bool allow_unsafe_operations,
-              bool may_capture_screenshots_not_from_surface,
+              bool is_trusted,
               absl::optional<url::Origin> navigation_initiator_origin,
               bool may_read_local_files);
 
@@ -223,8 +223,10 @@
   using ResponseOrWebContents = absl::variant<Response, WebContentsImpl*>;
   ResponseOrWebContents GetWebContentsForTopLevelActiveFrame();
 
+  void RetrievePrerenderActivationFromWebContents();
+
   const bool allow_unsafe_operations_;
-  const bool may_capture_screenshots_not_from_surface_;
+  const bool is_trusted_;
   const absl::optional<url::Origin> navigation_initiator_origin_;
   const bool may_read_local_files_;
 
@@ -241,6 +243,10 @@
   int frame_counter_;
   int frames_in_flight_;
 
+  // Whether stored prerender activation has been dispatched to Devtools. Reset
+  // whenever a new prerender event received.
+  bool has_dispatched_stored_prerender_activation_ = false;
+
   // |video_consumer_| consumes video frames from FrameSinkVideoCapturerImpl,
   // and provides PageHandler with these frames via OnFrameFromVideoConsumer.
   // This is only used if Viz is enabled and if OS is not Android.
diff --git a/content/browser/interest_group/interest_group_auction.cc b/content/browser/interest_group/interest_group_auction.cc
index 34af0413..7d8a042b 100644
--- a/content/browser/interest_group/interest_group_auction.cc
+++ b/content/browser/interest_group/interest_group_auction.cc
@@ -1364,8 +1364,14 @@
       std::make_unique<BuyerHelper>(this, std::move(interest_groups));
 
   // BuyerHelper may filter out additional interest groups on construction.
-  if (buyer_helper->has_potential_bidder())
+  if (buyer_helper->has_potential_bidder()) {
     buyer_helpers_.emplace_back(std::move(buyer_helper));
+  } else {
+    // `buyer_helper` has a raw pointer to `this`, so if it's not added to
+    // buyer_helpers_, delete it now to avoid a dangling pointer, since
+    // OnOneLoadCompleted() could result in deleting `this`.
+    buyer_helper.reset();
+  }
 
   OnOneLoadCompleted();
 }
diff --git a/content/browser/preloading/speculation_rules/speculation_host_impl.cc b/content/browser/preloading/speculation_rules/speculation_host_impl.cc
index e45f125..538e30f 100644
--- a/content/browser/preloading/speculation_rules/speculation_host_impl.cc
+++ b/content/browser/preloading/speculation_rules/speculation_host_impl.cc
@@ -42,6 +42,15 @@
       mojo::ReportBadMessage("SH_NON_HTTP");
       return false;
     }
+
+    // `target_browsing_context_name_hint` on non-prerender actions should be
+    // filtered out in Blink.
+    if (candidate->action != blink::mojom::SpeculationAction::kPrerender &&
+        candidate->target_browsing_context_name_hint !=
+            blink::mojom::SpeculationTargetHint::kNoHint) {
+      mojo::ReportBadMessage("SH_TARGET_HINT_ON_PREFETCH");
+      return false;
+    }
   }
   return true;
 }
@@ -330,6 +339,8 @@
       }
     }
 
+    // TODO(crbug.com/1354049): Pass `target_browsing_context_name_hint` to
+    // start prerendering in a new tab.
     Referrer referrer(*(it->referrer));
     int prerender_host_id = registry_->CreateAndStartHost(
         PrerenderAttributes(it->url, PrerenderTriggerType::kSpeculationRule,
@@ -341,6 +352,10 @@
                             rfhi.GetPageUkmSourceId(), ui::PAGE_TRANSITION_LINK,
                             /*url_match_predicate=*/absl::nullopt),
         *web_contents, /*preloading_attempt=*/preloading_attempt);
+    // TODO(crbug.com/1354049): Handle the case where multiple speculation rules
+    // have the same URL but its `target_browsing_context_name_hint` is
+    // different. In the current implementation, only the first rule is
+    // triggered.
     started_prerenders_.insert(end, {.url = it->url,
                                      .referrer = referrer,
                                      .prerender_host_id = prerender_host_id});
diff --git a/content/browser/preloading/speculation_rules/speculation_host_impl_unittest.cc b/content/browser/preloading/speculation_rules/speculation_host_impl_unittest.cc
index 3c2b92b6..f611bf4 100644
--- a/content/browser/preloading/speculation_rules/speculation_host_impl_unittest.cc
+++ b/content/browser/preloading/speculation_rules/speculation_host_impl_unittest.cc
@@ -141,7 +141,7 @@
       registry->FindHostByUrlForTesting(kSecondPrerenderingUrlSameOrigin));
 }
 
-// Tests that SpeculationHostImpl crash the renderer process if it receives
+// Tests that SpeculationHostImpl crashes the renderer process if it receives
 // non-http prerender candidates.
 TEST_F(SpeculationHostImplTest, ReportNonHttpMessage) {
   RenderFrameHostImpl* render_frame_host = GetRenderFrameHost();
@@ -169,6 +169,40 @@
   EXPECT_FALSE(registry->FindHostByUrlForTesting(kPrerenderingUrl));
 }
 
+// Tests that SpeculationHostImpl crashes the renderer process if it receives
+// prefetch candidates that have a valid `target_browsing_context_name_hint`.
+TEST_F(SpeculationHostImplTest,
+       ReportTargetBrowsingContextNameHintOnPrefetchCandidate) {
+  RenderFrameHostImpl* render_frame_host = GetRenderFrameHost();
+  mojo::Remote<blink::mojom::SpeculationHost> remote;
+  SpeculationHostImpl::Bind(render_frame_host,
+                            remote.BindNewPipeAndPassReceiver());
+
+  // Set up the error handler for bad mojo messages.
+  std::string bad_message_error;
+  mojo::SetDefaultProcessErrorHandler(
+      base::BindLambdaForTesting([&](const std::string& error) {
+        EXPECT_FALSE(error.empty());
+        EXPECT_TRUE(bad_message_error.empty());
+        bad_message_error = error;
+      }));
+
+  // Create a prefetch candidate that has a valid target hint.
+  auto candidate = blink::mojom::SpeculationCandidate::New();
+  candidate->action = blink::mojom::SpeculationAction::kPrefetch;
+  candidate->url = GetSameOriginUrl("/empty.html");
+  candidate->referrer = blink::mojom::Referrer::New();
+  candidate->target_browsing_context_name_hint =
+      blink::mojom::SpeculationTargetHint::kBlank;
+
+  std::vector<blink::mojom::SpeculationCandidatePtr> candidates;
+  candidates.push_back(std::move(candidate));
+
+  remote->UpdateSpeculationCandidates(std::move(candidates));
+  remote.FlushForTesting();
+  EXPECT_EQ(bad_message_error, "SH_TARGET_HINT_ON_PREFETCH");
+}
+
 class TestSpeculationHostDelegate : public SpeculationHostDelegate {
  public:
   TestSpeculationHostDelegate() = default;
diff --git a/content/browser/site_per_process_layout_browsertest.cc b/content/browser/site_per_process_layout_browsertest.cc
index 03ffecc6..2aa5f78 100644
--- a/content/browser/site_per_process_layout_browsertest.cc
+++ b/content/browser/site_per_process_layout_browsertest.cc
@@ -1001,8 +1001,8 @@
       filter->GetIntersectionState()->main_frame_intersection.IsEmpty());
 }
 
-// Tests that main_frame_scroll_position is not shared by frames in the same
-// process. This is a regression test for https://crbug.com/1063760.
+// Tests that outermost_main_frame_scroll_position is not shared by frames in
+// the same process. This is a regression test for https://crbug.com/1063760.
 //
 // Set up the frame tree to be A(B1(C1),B2(C2)). Send IPC's with different
 // ViewportIntersection information to B1 and B2, and then check that the
@@ -1060,17 +1060,18 @@
 
   // Now that everything is in a stable, consistent state, we will send viewport
   // intersection IPC's to B1 and B2 that contain a different
-  // main_frame_scroll_position, and then verify that each of them propagates
-  // their own value of main_frame_scroll_position to C1 and C2, respectively.
-  // The IPC code mimics messages that A would send to B1 and B2.
+  // outermost_main_frame_scroll_position, and then verify that each of them
+  // propagates their own value of outermost_main_frame_scroll_position to C1
+  // and C2, respectively. The IPC code mimics messages that A would send to B1
+  // and B2.
   auto b1_intersection_state = b1_node->render_manager()
                                    ->GetProxyToParent()
                                    ->cross_process_frame_connector()
                                    ->intersection_state();
 
-  b1_intersection_state.main_frame_scroll_position.Offset(10, 0);
-  // A change in main_frame_scroll_position by itself will not cause B1 to be
-  // marked dirty, so we also modify viewport_intersection.
+  b1_intersection_state.outermost_main_frame_scroll_position.Offset(10, 0);
+  // A change in outermost_main_frame_scroll_position by itself will not cause
+  // B1 to be marked dirty, so we also modify viewport_intersection.
   b1_intersection_state.viewport_intersection.set_y(
       b1_intersection_state.viewport_intersection.y() + 7);
   b1_intersection_state.viewport_intersection.set_height(
@@ -1083,7 +1084,7 @@
                                    ->cross_process_frame_connector()
                                    ->intersection_state();
 
-  b2_intersection_state.main_frame_scroll_position.Offset(20, 0);
+  b2_intersection_state.outermost_main_frame_scroll_position.Offset(20, 0);
   b2_intersection_state.viewport_intersection.set_y(
       b2_intersection_state.viewport_intersection.y() + 7);
   b2_intersection_state.viewport_intersection.set_height(
@@ -1092,16 +1093,16 @@
   ForceUpdateViewportIntersection(b2_node, b2_intersection_state);
 
   // Once IPC's have been flushed to the C frames, we should see conflicting
-  // values for main_frame_scroll_position.
+  // values for outermost_main_frame_scroll_position.
   flush_ipcs(b1_node);
   flush_ipcs(b2_node);
   ASSERT_TRUE(b1_to_c1_message_filter->MessageReceived());
   ASSERT_TRUE(b2_to_c2_message_filter->MessageReceived());
   EXPECT_EQ(b1_to_c1_message_filter->GetIntersectionState()
-                ->main_frame_scroll_position,
+                ->outermost_main_frame_scroll_position,
             gfx::Point(10, 0));
   EXPECT_EQ(b2_to_c2_message_filter->GetIntersectionState()
-                ->main_frame_scroll_position,
+                ->outermost_main_frame_scroll_position,
             gfx::Point(20, 0));
   b1_to_c1_message_filter->Clear();
   b2_to_c2_message_filter->Clear();
@@ -1122,10 +1123,10 @@
                                         ->GetDeviceScaleFactor();
   float expected_y = device_scale_factor * 5.0;
   EXPECT_NEAR(b1_to_c1_message_filter->GetIntersectionState()
-                  ->main_frame_scroll_position.y(),
+                  ->outermost_main_frame_scroll_position.y(),
               expected_y, 1.f);
   EXPECT_NEAR(b2_to_c2_message_filter->GetIntersectionState()
-                  ->main_frame_scroll_position.y(),
+                  ->outermost_main_frame_scroll_position.y(),
               expected_y, 1.f);
 }
 
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 29e19a8..8f0afba 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -5717,6 +5717,15 @@
       was_ever_audible_ = false;
     }
 
+    // Clear the stored prerender activation result if this is not a prerender
+    // activation. If this is another prerender activation, it will override
+    // the old result in DevTools.
+    if (!navigation_handle->IsPrerenderedPageActivation() &&
+        !navigation_handle->IsSameDocument() &&
+        navigation_handle->IsInPrimaryMainFrame()) {
+      last_navigation_was_prerender_activation_for_devtools_ = false;
+    }
+
     if (!navigation_handle->IsSameDocument())
       last_screen_orientation_change_time_ = base::TimeTicks();
   }
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 335ed04c..345eba7 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -1344,6 +1344,16 @@
     return mouse_lock_widget_;
   }
 
+  // Record a prerender activation for DevTools.
+  void set_last_navigation_was_prerender_activation_for_devtools() {
+    last_navigation_was_prerender_activation_for_devtools_ = true;
+  }
+
+  // Check if prerender was just activated.
+  bool last_navigation_was_prerender_activation_for_devtools() {
+    return last_navigation_was_prerender_activation_for_devtools_;
+  }
+
  private:
   using FrameTreeIterationCallback = base::RepeatingCallback<void(FrameTree*)>;
   using RenderViewHostIterationCallback =
@@ -2349,6 +2359,12 @@
 
   VisibleTimeRequestTrigger visible_time_request_trigger_;
 
+  // Stores the information whether last navigation was prerender activation for
+  // DevTools. Set when a prerender activation completes, and cleared when
+  // either DevTools is opened and consults this value or when a non-prerendered
+  // navigation commits in the primary main frame.
+  bool last_navigation_was_prerender_activation_for_devtools_ = false;
+
   bool prerender2_disabled_ = false;
 
   base::WeakPtrFactory<WebContentsImpl> loading_weak_factory_{this};
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index d19e832..467cbce 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -2437,27 +2437,15 @@
 
 namespace {
 
-RenderFrameMetadataProviderImpl* RenderFrameMetadataProviderFromFrameTreeNode(
-    FrameTreeNode* node) {
-  DCHECK(node);
-  DCHECK(node->current_frame_host());
-  DCHECK(node->current_frame_host()->GetRenderWidgetHost());
-  return node->current_frame_host()
-      ->GetRenderWidgetHost()
-      ->render_frame_metadata_provider();
-}
-
-RenderFrameMetadataProviderImpl* RenderFrameMetadataProviderFromWebContents(
-    WebContents* web_contents) {
-  DCHECK(web_contents);
-  DCHECK(web_contents->GetPrimaryMainFrame()->GetRenderViewHost());
-  DCHECK(
-      RenderWidgetHostImpl::From(
-          web_contents->GetPrimaryMainFrame()->GetRenderViewHost()->GetWidget())
-          ->render_frame_metadata_provider());
-  return RenderWidgetHostImpl::From(web_contents->GetPrimaryMainFrame()
-                                        ->GetRenderViewHost()
-                                        ->GetWidget())
+RenderFrameMetadataProviderImpl* RenderFrameMetadataProviderFromRenderFrameHost(
+    RenderFrameHost* render_frame_host) {
+  DCHECK(render_frame_host);
+  DCHECK(render_frame_host->GetRenderWidgetHost());
+  // This helper should return a valid provider since it's used for
+  // RenderFrameSubmissionObserver ctor.
+  DCHECK(RenderWidgetHostImpl::From(render_frame_host->GetRenderWidgetHost())
+             ->render_frame_metadata_provider());
+  return RenderWidgetHostImpl::From(render_frame_host->GetRenderWidgetHost())
       ->render_frame_metadata_provider();
 }
 
@@ -2798,12 +2786,19 @@
 RenderFrameSubmissionObserver::RenderFrameSubmissionObserver(
     FrameTreeNode* node)
     : RenderFrameSubmissionObserver(
-          RenderFrameMetadataProviderFromFrameTreeNode(node)) {}
+          RenderFrameMetadataProviderFromRenderFrameHost(
+              node->current_frame_host())) {}
 
 RenderFrameSubmissionObserver::RenderFrameSubmissionObserver(
     WebContents* web_contents)
     : RenderFrameSubmissionObserver(
-          RenderFrameMetadataProviderFromWebContents(web_contents)) {}
+          RenderFrameMetadataProviderFromRenderFrameHost(
+              web_contents->GetPrimaryMainFrame())) {}
+
+RenderFrameSubmissionObserver::RenderFrameSubmissionObserver(
+    RenderFrameHost* rfh)
+    : RenderFrameSubmissionObserver(
+          RenderFrameMetadataProviderFromRenderFrameHost(rfh)) {}
 
 RenderFrameSubmissionObserver::~RenderFrameSubmissionObserver() {
   render_frame_metadata_provider_->RemoveObserver(this);
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h
index 3ff4a11..d1c40b51 100644
--- a/content/public/test/browser_test_utils.h
+++ b/content/public/test/browser_test_utils.h
@@ -1362,6 +1362,7 @@
       RenderFrameMetadataProviderImpl* render_frame_metadata_provider);
   explicit RenderFrameSubmissionObserver(FrameTreeNode* node);
   explicit RenderFrameSubmissionObserver(WebContents* web_contents);
+  explicit RenderFrameSubmissionObserver(RenderFrameHost* rfh);
   ~RenderFrameSubmissionObserver() override;
 
   // Resets the current |render_frame_count|;
diff --git a/content/public/test/test_frame_navigation_observer.h b/content/public/test/test_frame_navigation_observer.h
index b8f8d0af..f5e2fb9 100644
--- a/content/public/test/test_frame_navigation_observer.h
+++ b/content/public/test/test_frame_navigation_observer.h
@@ -43,6 +43,8 @@
 
   net::Error last_net_error_code() const { return last_net_error_code_; }
 
+  bool navigation_started() const { return navigation_started_; }
+
  private:
   // WebContentsObserver
   void DidStartNavigation(NavigationHandle* navigation_handle) override;
diff --git a/extensions/browser/extension_prefs.cc b/extensions/browser/extension_prefs.cc
index 3a3d9f9..397fbb1 100644
--- a/extensions/browser/extension_prefs.cc
+++ b/extensions/browser/extension_prefs.cc
@@ -1431,7 +1431,7 @@
   // no longer lists the extension).
   if (!external_uninstall && Manifest::IsExternalLocation(location)) {
     ListPrefUpdate update(prefs_, kExternalUninstalls);
-    update->Append(extension_id);
+    update->GetList().Append(extension_id);
   }
 
   DeleteExtensionPrefs(extension_id);
@@ -2330,10 +2330,10 @@
     const char* pref,
     const ExtensionIdContainer& strings) {
   ListPrefUpdate update(prefs_, pref);
-  base::Value* list_of_values = update.Get();
-  list_of_values->ClearList();
+  base::Value::List& list_of_values = update->GetList();
+  list_of_values.clear();
   for (auto iter = strings.cbegin(); iter != strings.cend(); ++iter) {
-    list_of_values->Append(*iter);
+    list_of_values.Append(*iter);
   }
 }
 
@@ -2663,15 +2663,15 @@
     return;
 
   ListPrefUpdate update(prefs_, kExternalUninstalls);
-  base::Value* current_ids = update.Get();
+  base::Value::List& current_ids = update->GetList();
   for (const auto& id : uninstalled_ids) {
-    base::Value::ListView list = current_ids->GetListDeprecated();
     auto existing_entry =
-        std::find_if(list.begin(), list.end(), [&id](const base::Value& value) {
-          return value.is_string() && value.GetString() == id;
-        });
-    if (existing_entry == list.end())
-      current_ids->Append(id);
+        std::find_if(current_ids.begin(), current_ids.end(),
+                     [&id](const base::Value& value) {
+                       return value.is_string() && value.GetString() == id;
+                     });
+    if (existing_entry == current_ids.end())
+      current_ids.Append(id);
 
     DeleteExtensionPrefs(id);
   }
@@ -2680,35 +2680,35 @@
 bool ExtensionPrefs::ShouldInstallObsoleteComponentExtension(
     const std::string& extension_id) {
   ListPrefUpdate update(prefs_, pref_names::kDeletedComponentExtensions);
-  base::Value* current_ids = update.Get();
-  base::Value::ListView list = current_ids->GetListDeprecated();
-  auto existing_entry = std::find_if(
-      list.begin(), list.end(), [&extension_id](const base::Value& value) {
-        return value.is_string() && value.GetString() == extension_id;
-      });
-  return (existing_entry == list.end());
+  base::Value::List& current_ids = update->GetList();
+  auto existing_entry = std::find_if(current_ids.begin(), current_ids.end(),
+                                     [&extension_id](const base::Value& value) {
+                                       return value.is_string() &&
+                                              value.GetString() == extension_id;
+                                     });
+  return (existing_entry == current_ids.end());
 }
 
 void ExtensionPrefs::MarkObsoleteComponentExtensionAsRemoved(
     const std::string& extension_id,
     const ManifestLocation location) {
   ListPrefUpdate update(prefs_, pref_names::kDeletedComponentExtensions);
-  base::Value* current_ids = update.Get();
-  base::Value::ListView list = current_ids->GetListDeprecated();
-  auto existing_entry = std::find_if(
-      list.begin(), list.end(), [&extension_id](const base::Value& value) {
-        return value.is_string() && value.GetString() == extension_id;
-      });
+  base::Value::List& current_ids = update->GetList();
+  auto existing_entry = std::find_if(current_ids.begin(), current_ids.end(),
+                                     [&extension_id](const base::Value& value) {
+                                       return value.is_string() &&
+                                              value.GetString() == extension_id;
+                                     });
   // This should only be called once per extension.
-  DCHECK(existing_entry == list.end());
-  current_ids->Append(extension_id);
+  DCHECK(existing_entry == current_ids.end());
+  current_ids.Append(extension_id);
   OnExtensionUninstalled(extension_id, location, false);
 }
 
 void ExtensionPrefs::ClearExternalUninstallBit(const ExtensionId& id) {
   ListPrefUpdate update(prefs_, kExternalUninstalls);
-  base::Value* current_ids = update.Get();
-  current_ids->EraseListValueIf([&id](const base::Value& value) {
+  base::Value::List& current_ids = update->GetList();
+  current_ids.EraseIf([&id](const base::Value& value) {
     return value.is_string() && value.GetString() == id;
   });
 }
diff --git a/gpu/command_buffer/service/shared_image/compound_image_backing.cc b/gpu/command_buffer/service/shared_image/compound_image_backing.cc
index 90665ad..1d86252 100644
--- a/gpu/command_buffer/service/shared_image/compound_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image/compound_image_backing.cc
@@ -184,16 +184,6 @@
                                       begin_semaphores, end_semaphores,
                                       end_state);
   }
-  sk_sp<SkSurface> BeginWriteAccess(
-      int final_msaa_count,
-      const SkSurfaceProps& surface_props,
-      std::vector<GrBackendSemaphore>* begin_semaphores,
-      std::vector<GrBackendSemaphore>* end_semaphores) final {
-    compound_backing()->NotifyBeginAccess(SharedImageAccessStream::kSkia,
-                                          AccessMode::kWrite);
-    return wrapped_->BeginWriteAccess(final_msaa_count, surface_props,
-                                      begin_semaphores, end_semaphores);
-  }
   sk_sp<SkPromiseImageTexture> BeginWriteAccess(
       std::vector<GrBackendSemaphore>* begin_semaphores,
       std::vector<GrBackendSemaphore>* end_semaphores,
@@ -216,13 +206,6 @@
     return wrapped_->BeginReadAccess(begin_semaphores, end_semaphores,
                                      end_state);
   }
-  sk_sp<SkPromiseImageTexture> BeginReadAccess(
-      std::vector<GrBackendSemaphore>* begin_semaphores,
-      std::vector<GrBackendSemaphore>* end_semaphores) final {
-    compound_backing()->NotifyBeginAccess(SharedImageAccessStream::kSkia,
-                                          AccessMode::kRead);
-    return wrapped_->BeginReadAccess(begin_semaphores, end_semaphores);
-  }
   void EndReadAccess() final { wrapped_->EndReadAccess(); }
 
  private:
@@ -320,19 +303,10 @@
       SHARED_IMAGE_USAGE_CPU_WRITE, std::move(shm_wrapper));
   shm_backing->SetNotReferencedCounted();
 
-  auto gpu_backing = gpu_backing_factory->CreateSharedImage(
-      mailbox, format, surface_handle, size, color_space, surface_origin,
-      alpha_type, usage | SHARED_IMAGE_USAGE_CPU_UPLOAD,
-      /*is_thread_safe=*/false);
-  if (!gpu_backing) {
-    DLOG(ERROR) << "Failed to create GPU backing";
-    return nullptr;
-  }
-  gpu_backing->SetNotReferencedCounted();
-
   return std::make_unique<CompoundImageBacking>(
       mailbox, format, size, color_space, surface_origin, alpha_type, usage,
-      std::move(shm_backing), std::move(gpu_backing));
+      surface_handle, std::move(shm_backing),
+      gpu_backing_factory->GetWeakPtr());
 }
 
 CompoundImageBacking::CompoundImageBacking(
@@ -343,8 +317,9 @@
     GrSurfaceOrigin surface_origin,
     SkAlphaType alpha_type,
     uint32_t usage,
+    SurfaceHandle surface_handle,
     std::unique_ptr<SharedMemoryImageBacking> shm_backing,
-    std::unique_ptr<SharedImageBacking> gpu_backing)
+    base::WeakPtr<SharedImageBackingFactory> gpu_backing_factory)
     : SharedImageBacking(mailbox,
                          format,
                          size,
@@ -352,13 +327,12 @@
                          surface_origin,
                          alpha_type,
                          usage,
-                         gpu_backing->estimated_size(),
+                         shm_backing->estimated_size(),
                          /*is_thread_safe=*/false),
+      surface_handle_(surface_handle),
       shm_backing_(std::move(shm_backing)),
-      gpu_backing_(std::move(gpu_backing)) {
-  DCHECK(gpu_backing_);
+      gpu_backing_factory_(std::move(gpu_backing_factory)) {
   DCHECK(shm_backing_);
-  DCHECK_EQ(size, gpu_backing_->size());
   DCHECK_EQ(size, shm_backing_->size());
 
   // First access will write pixels from shared memory backing to GPU backing
@@ -405,19 +379,21 @@
 }
 
 gfx::Rect CompoundImageBacking::ClearedRect() const {
-  return gpu_backing_->ClearedRect();
+  // Copy on access will always ensure backing is cleared by first access.
+  return gfx::Rect(size());
 }
 
-void CompoundImageBacking::SetClearedRect(const gfx::Rect& cleared_rect) {
-  // Shared memory backing doesn't track cleared rect.
-  gpu_backing_->SetClearedRect(cleared_rect);
-}
+void CompoundImageBacking::SetClearedRect(const gfx::Rect& cleared_rect) {}
 
 std::unique_ptr<DawnImageRepresentation> CompoundImageBacking::ProduceDawn(
     SharedImageManager* manager,
     MemoryTypeTracker* tracker,
     WGPUDevice device,
     WGPUBackendType backend_type) {
+  LazyAllocateGpuBacking();
+  if (!gpu_backing_)
+    return nullptr;
+
   auto real_rep =
       gpu_backing_->ProduceDawn(manager, tracker, device, backend_type);
   if (!real_rep)
@@ -430,6 +406,10 @@
 std::unique_ptr<GLTextureImageRepresentation>
 CompoundImageBacking::ProduceGLTexture(SharedImageManager* manager,
                                        MemoryTypeTracker* tracker) {
+  LazyAllocateGpuBacking();
+  if (!gpu_backing_)
+    return nullptr;
+
   auto real_rep = gpu_backing_->ProduceGLTexture(manager, tracker);
   if (!real_rep)
     return nullptr;
@@ -441,6 +421,10 @@
 std::unique_ptr<GLTexturePassthroughImageRepresentation>
 CompoundImageBacking::ProduceGLTexturePassthrough(SharedImageManager* manager,
                                                   MemoryTypeTracker* tracker) {
+  LazyAllocateGpuBacking();
+  if (!gpu_backing_)
+    return nullptr;
+
   auto real_rep = gpu_backing_->ProduceGLTexturePassthrough(manager, tracker);
   if (!real_rep)
     return nullptr;
@@ -454,6 +438,10 @@
     SharedImageManager* manager,
     MemoryTypeTracker* tracker,
     scoped_refptr<SharedContextState> context_state) {
+  LazyAllocateGpuBacking();
+  if (!gpu_backing_)
+    return nullptr;
+
   auto real_rep =
       gpu_backing_->ProduceSkia(manager, tracker, std::move(context_state));
   if (!real_rep)
@@ -466,6 +454,10 @@
 std::unique_ptr<OverlayImageRepresentation>
 CompoundImageBacking::ProduceOverlay(SharedImageManager* manager,
                                      MemoryTypeTracker* tracker) {
+  LazyAllocateGpuBacking();
+  if (!gpu_backing_)
+    return nullptr;
+
   auto real_rep = gpu_backing_->ProduceOverlay(manager, tracker);
   if (!real_rep)
     return nullptr;
@@ -503,15 +495,47 @@
   shm_backing_->OnMemoryDump(shm_dump_name, shm_client_guid, pmd,
                              client_tracing_id);
 
-  auto gpu_client_guid = GetSubBackingGUIDForTracing(mailbox(), 2);
-  std::string gpu_dump_name = base::StringPrintf("%s/gpu", dump_name.c_str());
-  gpu_backing_->OnMemoryDump(gpu_dump_name, gpu_client_guid, pmd,
-                             client_tracing_id);
+  if (gpu_backing_) {
+    auto gpu_client_guid = GetSubBackingGUIDForTracing(mailbox(), 2);
+    std::string gpu_dump_name = base::StringPrintf("%s/gpu", dump_name.c_str());
+    gpu_backing_->OnMemoryDump(gpu_dump_name, gpu_client_guid, pmd,
+                               client_tracing_id);
+  }
 }
 
 size_t CompoundImageBacking::EstimatedSizeForMemTracking() const {
-  return shm_backing_->EstimatedSizeForMemTracking() +
-         gpu_backing_->EstimatedSizeForMemTracking();
+  size_t estimated_size = shm_backing_->EstimatedSizeForMemTracking();
+  if (gpu_backing_)
+    estimated_size += gpu_backing_->EstimatedSizeForMemTracking();
+  return estimated_size;
+}
+
+void CompoundImageBacking::LazyAllocateGpuBacking() {
+  if (gpu_backing_)
+    return;
+
+  if (!gpu_backing_factory_) {
+    if (gpu_backing_factory_.WasInvalidated()) {
+      // The SharedImageFactory must no longer exist so the compound shared
+      // image must already have been destroyed.
+      LOG(ERROR) << "Can't allocate backing after image has been destroyed";
+      gpu_backing_factory_.reset();
+    }
+    return;
+  }
+
+  gpu_backing_ = gpu_backing_factory_->CreateSharedImage(
+      mailbox(), format(), surface_handle_, size(), color_space(),
+      surface_origin(), alpha_type(), usage() | SHARED_IMAGE_USAGE_CPU_UPLOAD,
+      /*is_thread_safe=*/false);
+  if (!gpu_backing_) {
+    LOG(ERROR) << "Failed to allocate GPU backing";
+    gpu_backing_factory_.reset();
+    return;
+  }
+
+  gpu_backing_->SetNotReferencedCounted();
+  gpu_backing_->SetClearedRect(gfx::Rect(size()));
 }
 
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/shared_image/compound_image_backing.h b/gpu/command_buffer/service/shared_image/compound_image_backing.h
index 7d8191b..9c8c10a 100644
--- a/gpu/command_buffer/service/shared_image/compound_image_backing.h
+++ b/gpu/command_buffer/service/shared_image/compound_image_backing.h
@@ -54,15 +54,17 @@
       SkAlphaType alpha_type,
       uint32_t usage);
 
-  CompoundImageBacking(const Mailbox& mailbox,
-                       viz::ResourceFormat format,
-                       const gfx::Size& size,
-                       const gfx::ColorSpace& color_space,
-                       GrSurfaceOrigin surface_origin,
-                       SkAlphaType alpha_type,
-                       uint32_t usage,
-                       std::unique_ptr<SharedMemoryImageBacking> shm_backing,
-                       std::unique_ptr<SharedImageBacking> gpu_backing);
+  CompoundImageBacking(
+      const Mailbox& mailbox,
+      viz::ResourceFormat format,
+      const gfx::Size& size,
+      const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
+      uint32_t usage,
+      SurfaceHandle surface_handle,
+      std::unique_ptr<SharedMemoryImageBacking> shm_backing,
+      base::WeakPtr<SharedImageBackingFactory> gpu_backing_factory);
 
   ~CompoundImageBacking() override;
 
@@ -108,7 +110,18 @@
                     uint64_t client_tracing_id) override;
   size_t EstimatedSizeForMemTracking() const override;
 
+  // The first call will attempt to allocate `gpu_backing_`. This can fail
+  // so `gpu_backing_` may be null afterwards.
+  void LazyAllocateGpuBacking();
+
+  const SurfaceHandle surface_handle_;
+
   std::unique_ptr<SharedImageBacking> shm_backing_;
+
+  // This will store backing factory to allocate `gpu_backing_` with. It must
+  // be a WeakPtr as the backing can outlive the factory that created it. This
+  // will be reset after lazy allocation is attempted.
+  base::WeakPtr<SharedImageBackingFactory> gpu_backing_factory_;
   std::unique_ptr<SharedImageBacking> gpu_backing_;
 
   // This will be true when shared memory backing has newer pixels than GPU
diff --git a/gpu/command_buffer/service/shared_image/compound_image_backing_unittest.cc b/gpu/command_buffer/service/shared_image/compound_image_backing_unittest.cc
index b819154..f192318 100644
--- a/gpu/command_buffer/service/shared_image/compound_image_backing_unittest.cc
+++ b/gpu/command_buffer/service/shared_image/compound_image_backing_unittest.cc
@@ -36,6 +36,9 @@
       SkAlphaType alpha_type,
       uint32_t usage,
       bool is_thread_safe) override {
+    if (allocations_should_fail_)
+      return nullptr;
+
     return std::make_unique<TestImageBacking>(mailbox, format, size,
                                               color_space, surface_origin,
                                               alpha_type, usage, 0);
@@ -74,12 +77,34 @@
                    base::span<const uint8_t> pixel_data) override {
     return true;
   }
+
+  using SharedImageBackingFactory::InvalidateWeakPtrsForTesting;
+
+  void SetAllocationsShouldFail(bool allocations_should_fail) {
+    allocations_should_fail_ = allocations_should_fail;
+  }
+
+ private:
+  bool allocations_should_fail_ = false;
 };
 
 }  // namespace
 
 class CompoundImageBackingTest : public testing::Test {
  public:
+  bool HasGpuBacking(CompoundImageBacking* backing) {
+    return !!backing->gpu_backing_;
+  }
+
+  bool GpuBackingFactoryIsValid(CompoundImageBacking* backing) {
+    return !!backing->gpu_backing_factory_;
+  }
+
+  bool GpuBackingFactoryIsCleared(CompoundImageBacking* backing) {
+    return !backing->gpu_backing_factory_ &&
+           !backing->gpu_backing_factory_.WasInvalidated();
+  }
+
   TestImageBacking* GetGpuBacking(CompoundImageBacking* backing) {
     auto* gpu_backing = backing->gpu_backing_.get();
     DCHECK_EQ(gpu_backing->GetType(), SharedImageBackingType::kTest);
@@ -118,12 +143,10 @@
   auto* compound_backing = static_cast<CompoundImageBacking*>(backing.get());
   EXPECT_NE(compound_backing, nullptr);
 
-  auto* gpu_backing = GetGpuBacking(compound_backing);
-
   // The compound backing hasn't been added to the manager yet so it should
   // have zero references.
   EXPECT_FALSE(compound_backing->HasAnyRefs());
-  EXPECT_FALSE(gpu_backing->HasAnyRefs());
+  EXPECT_FALSE(HasGpuBacking(compound_backing));
 
   auto factory_rep = manager_.Register(std::move(backing), &tracker_);
 
@@ -131,11 +154,13 @@
   // backing should never have any reference as it's owned by the compound
   // backing and isn't reference counted.
   EXPECT_TRUE(compound_backing->HasAnyRefs());
-  EXPECT_FALSE(gpu_backing->HasAnyRefs());
+  EXPECT_FALSE(HasGpuBacking(compound_backing));
 
   auto overlay_rep =
       manager_.ProduceOverlay(compound_backing->mailbox(), &tracker_);
 
+  auto* gpu_backing = GetGpuBacking(compound_backing);
+
   // GPU backing still shouldn't have any references after a wrapped
   // representation is created.
   EXPECT_TRUE(compound_backing->HasAnyRefs());
@@ -151,16 +176,17 @@
 TEST_F(CompoundImageBackingTest, UploadOnAccess) {
   auto backing = CreateCompoundBacking();
   auto* compound_backing = static_cast<CompoundImageBacking*>(backing.get());
-  auto* gpu_backing = GetGpuBacking(compound_backing);
 
   auto factory_rep = manager_.Register(std::move(backing), &tracker_);
 
-  // The compound backing hasn't been accessed yet.
-  EXPECT_FALSE(gpu_backing->GetUploadFromMemoryCalledAndReset());
-
   auto overlay_rep =
       manager_.ProduceOverlay(compound_backing->mailbox(), &tracker_);
 
+  auto* gpu_backing = GetGpuBacking(compound_backing);
+
+  // The compound backing hasn't been accessed yet.
+  EXPECT_FALSE(gpu_backing->GetUploadFromMemoryCalledAndReset());
+
   // First access should trigger upload from memory to GPU.
   overlay_rep->BeginScopedReadAccess(false);
   EXPECT_TRUE(gpu_backing->GetUploadFromMemoryCalledAndReset());
@@ -209,4 +235,54 @@
   EXPECT_TRUE(gpu_backing->GetUploadFromMemoryCalledAndReset());
 }
 
+TEST_F(CompoundImageBackingTest, LazyAllocationFailsCreate) {
+  auto backing = CreateCompoundBacking();
+  auto* compound_backing = static_cast<CompoundImageBacking*>(backing.get());
+
+  auto factory_rep = manager_.Register(std::move(backing), &tracker_);
+
+  // The compound backing shouldn't have GPU backing yet and should have
+  // a valid factory to create one.
+  EXPECT_FALSE(HasGpuBacking(compound_backing));
+  EXPECT_TRUE(GpuBackingFactoryIsValid(compound_backing));
+
+  test_factory_.SetAllocationsShouldFail(true);
+
+  auto gl_passthrough_rep = manager_.ProduceGLTexturePassthrough(
+      compound_backing->mailbox(), &tracker_);
+
+  // Creating the GPU backing should fail so representation should be null.
+  EXPECT_FALSE(gl_passthrough_rep);
+  EXPECT_FALSE(HasGpuBacking(compound_backing));
+
+  // The backing factory to create GPU backing should be reset so creation is
+  // not retried.
+  EXPECT_TRUE(GpuBackingFactoryIsCleared(compound_backing));
+}
+
+TEST_F(CompoundImageBackingTest, LazyAllocationFailsFactoryInvalidated) {
+  auto backing = CreateCompoundBacking();
+  auto* compound_backing = static_cast<CompoundImageBacking*>(backing.get());
+
+  auto factory_rep = manager_.Register(std::move(backing), &tracker_);
+
+  // The compound backing shouldn't have GPU backing yet and should have
+  // a valid factory to create one.
+  EXPECT_FALSE(HasGpuBacking(compound_backing));
+  EXPECT_TRUE(GpuBackingFactoryIsValid(compound_backing));
+
+  test_factory_.InvalidateWeakPtrsForTesting();
+
+  auto gl_passthrough_rep = manager_.ProduceGLTexturePassthrough(
+      compound_backing->mailbox(), &tracker_);
+
+  // Creating the GPU backing should fail so representation should be null.
+  EXPECT_FALSE(gl_passthrough_rep);
+  EXPECT_FALSE(HasGpuBacking(compound_backing));
+
+  // The backing factory to create GPU backing should be reset to avoid logging
+  // about destroyed image multiple times.
+  EXPECT_TRUE(GpuBackingFactoryIsCleared(compound_backing));
+}
+
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/shared_image/gl_image_backing.cc b/gpu/command_buffer/service/shared_image/gl_image_backing.cc
index 3d8e21f..bc501ce 100644
--- a/gpu/command_buffer/service/shared_image/gl_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image/gl_image_backing.cc
@@ -172,7 +172,8 @@
     int final_msaa_count,
     const SkSurfaceProps& surface_props,
     std::vector<GrBackendSemaphore>* begin_semaphores,
-    std::vector<GrBackendSemaphore>* end_semaphores) {
+    std::vector<GrBackendSemaphore>* end_semaphores,
+    std::unique_ptr<GrBackendSurfaceMutableState>* end_state) {
   CheckContext();
   if (client_) {
     DCHECK(context_state_->GrContextIsGL());
@@ -232,7 +233,8 @@
 
 sk_sp<SkPromiseImageTexture> SkiaGLCommonRepresentation::BeginReadAccess(
     std::vector<GrBackendSemaphore>* begin_semaphores,
-    std::vector<GrBackendSemaphore>* end_semaphores) {
+    std::vector<GrBackendSemaphore>* end_semaphores,
+    std::unique_ptr<GrBackendSurfaceMutableState>* end_state) {
   CheckContext();
   if (client_) {
     DCHECK(context_state_->GrContextIsGL());
diff --git a/gpu/command_buffer/service/shared_image/gl_image_backing.h b/gpu/command_buffer/service/shared_image/gl_image_backing.h
index d935cfa..d93699d0 100644
--- a/gpu/command_buffer/service/shared_image/gl_image_backing.h
+++ b/gpu/command_buffer/service/shared_image/gl_image_backing.h
@@ -99,7 +99,8 @@
       int final_msaa_count,
       const SkSurfaceProps& surface_props,
       std::vector<GrBackendSemaphore>* begin_semaphores,
-      std::vector<GrBackendSemaphore>* end_semaphores) override;
+      std::vector<GrBackendSemaphore>* end_semaphores,
+      std::unique_ptr<GrBackendSurfaceMutableState>* end_state) override;
   sk_sp<SkPromiseImageTexture> BeginWriteAccess(
       std::vector<GrBackendSemaphore>* begin_semaphores,
       std::vector<GrBackendSemaphore>* end_semaphore,
@@ -107,7 +108,8 @@
   void EndWriteAccess(sk_sp<SkSurface> surface) override;
   sk_sp<SkPromiseImageTexture> BeginReadAccess(
       std::vector<GrBackendSemaphore>* begin_semaphores,
-      std::vector<GrBackendSemaphore>* end_semaphores) override;
+      std::vector<GrBackendSemaphore>* end_semaphores,
+      std::unique_ptr<GrBackendSurfaceMutableState>* end_state) override;
   void EndReadAccess() override;
   bool SupportsMultipleConcurrentReadAccess() override;
 
diff --git a/gpu/command_buffer/service/shared_image/shared_image_backing_factory.cc b/gpu/command_buffer/service/shared_image/shared_image_backing_factory.cc
index eaf41487..4b3b752 100644
--- a/gpu/command_buffer/service/shared_image/shared_image_backing_factory.cc
+++ b/gpu/command_buffer/service/shared_image/shared_image_backing_factory.cc
@@ -7,6 +7,10 @@
 
 namespace gpu {
 
+SharedImageBackingFactory::SharedImageBackingFactory() = default;
+
+SharedImageBackingFactory::~SharedImageBackingFactory() = default;
+
 std::vector<std::unique_ptr<SharedImageBacking>>
 SharedImageBackingFactory::CreateSharedImageVideoPlanes(
     base::span<const Mailbox> mailboxes,
@@ -18,4 +22,13 @@
   return {};
 }
 
+base::WeakPtr<SharedImageBackingFactory>
+SharedImageBackingFactory::GetWeakPtr() {
+  return weak_ptr_factory_.GetWeakPtr();
+}
+
+void SharedImageBackingFactory::InvalidateWeakPtrsForTesting() {
+  weak_ptr_factory_.InvalidateWeakPtrs();
+}
+
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/shared_image/shared_image_backing_factory.h b/gpu/command_buffer/service/shared_image/shared_image_backing_factory.h
index e8efb25..232eea1 100644
--- a/gpu/command_buffer/service/shared_image/shared_image_backing_factory.h
+++ b/gpu/command_buffer/service/shared_image/shared_image_backing_factory.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "base/memory/weak_ptr.h"
 #include "components/viz/common/resources/resource_format.h"
 #include "gpu/config/gpu_preferences.h"
 #include "gpu/gpu_gles2_export.h"
@@ -27,7 +28,9 @@
 
 class GPU_GLES2_EXPORT SharedImageBackingFactory {
  public:
-  virtual ~SharedImageBackingFactory() = default;
+  SharedImageBackingFactory();
+  virtual ~SharedImageBackingFactory();
+
   virtual std::unique_ptr<SharedImageBacking> CreateSharedImage(
       const Mailbox& mailbox,
       viz::ResourceFormat format,
@@ -76,6 +79,14 @@
                            gfx::GpuMemoryBufferType gmb_type,
                            GrContextType gr_context_type,
                            base::span<const uint8_t> pixel_data) = 0;
+
+  base::WeakPtr<SharedImageBackingFactory> GetWeakPtr();
+
+ protected:
+  void InvalidateWeakPtrsForTesting();
+
+ private:
+  base::WeakPtrFactory<SharedImageBackingFactory> weak_ptr_factory_{this};
 };
 
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/shared_image/shared_image_representation.cc b/gpu/command_buffer/service/shared_image/shared_image_representation.cc
index bb73504..072ef61 100644
--- a/gpu/command_buffer/service/shared_image/shared_image_representation.cc
+++ b/gpu/command_buffer/service/shared_image/shared_image_representation.cc
@@ -268,15 +268,6 @@
     std::vector<GrBackendSemaphore>* begin_semaphores,
     std::vector<GrBackendSemaphore>* end_semaphores,
     std::unique_ptr<GrBackendSurfaceMutableState>* end_state) {
-  return BeginWriteAccess(final_msaa_count, surface_props, begin_semaphores,
-                          end_semaphores);
-}
-
-sk_sp<SkSurface> SkiaImageRepresentation::BeginWriteAccess(
-    int final_msaa_count,
-    const SkSurfaceProps& surface_props,
-    std::vector<GrBackendSemaphore>* begin_semaphores,
-    std::vector<GrBackendSemaphore>* end_semaphores) {
   return nullptr;
 }
 
@@ -284,12 +275,6 @@
     std::vector<GrBackendSemaphore>* begin_semaphores,
     std::vector<GrBackendSemaphore>* end_semaphores,
     std::unique_ptr<GrBackendSurfaceMutableState>* end_state) {
-  return BeginReadAccess(begin_semaphores, end_semaphores);
-}
-
-sk_sp<SkPromiseImageTexture> SkiaImageRepresentation::BeginReadAccess(
-    std::vector<GrBackendSemaphore>* begin_semaphores,
-    std::vector<GrBackendSemaphore>* end_semaphores) {
   return nullptr;
 }
 
diff --git a/gpu/command_buffer/service/shared_image/shared_image_representation.h b/gpu/command_buffer/service/shared_image/shared_image_representation.h
index fd96752..d2d8a5d 100644
--- a/gpu/command_buffer/service/shared_image/shared_image_representation.h
+++ b/gpu/command_buffer/service/shared_image/shared_image_representation.h
@@ -341,11 +341,6 @@
       std::vector<GrBackendSemaphore>* begin_semaphores,
       std::vector<GrBackendSemaphore>* end_semaphores,
       std::unique_ptr<GrBackendSurfaceMutableState>* end_state);
-  virtual sk_sp<SkSurface> BeginWriteAccess(
-      int final_msaa_count,
-      const SkSurfaceProps& surface_props,
-      std::vector<GrBackendSemaphore>* begin_semaphores,
-      std::vector<GrBackendSemaphore>* end_semaphores);
   virtual sk_sp<SkPromiseImageTexture> BeginWriteAccess(
       std::vector<GrBackendSemaphore>* begin_semaphores,
       std::vector<GrBackendSemaphore>* end_semaphores,
@@ -367,9 +362,6 @@
       std::vector<GrBackendSemaphore>* begin_semaphores,
       std::vector<GrBackendSemaphore>* end_semaphores,
       std::unique_ptr<GrBackendSurfaceMutableState>* end_state);
-  virtual sk_sp<SkPromiseImageTexture> BeginReadAccess(
-      std::vector<GrBackendSemaphore>* begin_semaphores,
-      std::vector<GrBackendSemaphore>* end_semaphores);
   virtual void EndReadAccess() = 0;
 };
 
diff --git a/gpu/command_buffer/service/shared_image/skia_gl_image_representation.cc b/gpu/command_buffer/service/shared_image/skia_gl_image_representation.cc
index d4f08ca..a62d4a60 100644
--- a/gpu/command_buffer/service/shared_image/skia_gl_image_representation.cc
+++ b/gpu/command_buffer/service/shared_image/skia_gl_image_representation.cc
@@ -83,7 +83,8 @@
     int final_msaa_count,
     const SkSurfaceProps& surface_props,
     std::vector<GrBackendSemaphore>* begin_semaphores,
-    std::vector<GrBackendSemaphore>* end_semaphores) {
+    std::vector<GrBackendSemaphore>* end_semaphores,
+    std::unique_ptr<GrBackendSurfaceMutableState>* end_state) {
   DCHECK_EQ(mode_, RepresentationAccessMode::kNone);
   CheckContext();
 
@@ -137,7 +138,8 @@
 
 sk_sp<SkPromiseImageTexture> SkiaGLImageRepresentation::BeginReadAccess(
     std::vector<GrBackendSemaphore>* begin_semaphores,
-    std::vector<GrBackendSemaphore>* end_semaphores) {
+    std::vector<GrBackendSemaphore>* end_semaphores,
+    std::unique_ptr<GrBackendSurfaceMutableState>* end_state) {
   DCHECK_EQ(mode_, RepresentationAccessMode::kNone);
   CheckContext();
 
diff --git a/gpu/command_buffer/service/shared_image/skia_gl_image_representation.h b/gpu/command_buffer/service/shared_image/skia_gl_image_representation.h
index b4c2a121..530abc4 100644
--- a/gpu/command_buffer/service/shared_image/skia_gl_image_representation.h
+++ b/gpu/command_buffer/service/shared_image/skia_gl_image_representation.h
@@ -32,7 +32,8 @@
       int final_msaa_count,
       const SkSurfaceProps& surface_props,
       std::vector<GrBackendSemaphore>* begin_semaphores,
-      std::vector<GrBackendSemaphore>* end_semaphores) override;
+      std::vector<GrBackendSemaphore>* end_semaphores,
+      std::unique_ptr<GrBackendSurfaceMutableState>* end_state) override;
   sk_sp<SkPromiseImageTexture> BeginWriteAccess(
       std::vector<GrBackendSemaphore>* begin_semaphores,
       std::vector<GrBackendSemaphore>* end_semaphores,
@@ -40,7 +41,8 @@
   void EndWriteAccess(sk_sp<SkSurface> surface) override;
   sk_sp<SkPromiseImageTexture> BeginReadAccess(
       std::vector<GrBackendSemaphore>* begin_semaphores,
-      std::vector<GrBackendSemaphore>* end_semaphores) override;
+      std::vector<GrBackendSemaphore>* end_semaphores,
+      std::unique_ptr<GrBackendSurfaceMutableState>* end_state) override;
   void EndReadAccess() override;
 
   bool SupportsMultipleConcurrentReadAccess() override;
diff --git a/gpu/command_buffer/service/shared_image/test_image_backing.cc b/gpu/command_buffer/service/shared_image/test_image_backing.cc
index 311dae8..90ec70ab 100644
--- a/gpu/command_buffer/service/shared_image/test_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image/test_image_backing.cc
@@ -68,7 +68,8 @@
       int final_msaa_count,
       const SkSurfaceProps& surface_props,
       std::vector<GrBackendSemaphore>* begin_semaphores,
-      std::vector<GrBackendSemaphore>* end_semaphores) override {
+      std::vector<GrBackendSemaphore>* end_semaphores,
+      std::unique_ptr<GrBackendSurfaceMutableState>* end_state) override {
     if (!static_cast<TestImageBacking*>(backing())->can_access()) {
       return nullptr;
     }
@@ -90,7 +91,8 @@
   void EndWriteAccess(sk_sp<SkSurface> surface) override {}
   sk_sp<SkPromiseImageTexture> BeginReadAccess(
       std::vector<GrBackendSemaphore>* begin_semaphores,
-      std::vector<GrBackendSemaphore>* end_semaphores) override {
+      std::vector<GrBackendSemaphore>* end_semaphores,
+      std::unique_ptr<GrBackendSurfaceMutableState>* end_state) override {
     if (!static_cast<TestImageBacking*>(backing())->can_access()) {
       return nullptr;
     }
diff --git a/gpu/command_buffer/service/shared_image/wrapped_sk_image_backing_factory.cc b/gpu/command_buffer/service/shared_image/wrapped_sk_image_backing_factory.cc
index e529c9b..8a6e554 100644
--- a/gpu/command_buffer/service/shared_image/wrapped_sk_image_backing_factory.cc
+++ b/gpu/command_buffer/service/shared_image/wrapped_sk_image_backing_factory.cc
@@ -357,7 +357,8 @@
       int final_msaa_count,
       const SkSurfaceProps& surface_props,
       std::vector<GrBackendSemaphore>* begin_semaphores,
-      std::vector<GrBackendSemaphore>* end_semaphores) override {
+      std::vector<GrBackendSemaphore>* end_semaphores,
+      std::unique_ptr<GrBackendSurfaceMutableState>* end_state) override {
     auto surface = wrapped_sk_image()->GetSkSurface(
         final_msaa_count, surface_props, context_state_);
     if (!surface)
@@ -388,7 +389,8 @@
 
   sk_sp<SkPromiseImageTexture> BeginReadAccess(
       std::vector<GrBackendSemaphore>* begin_semaphores,
-      std::vector<GrBackendSemaphore>* end_semaphores) override {
+      std::vector<GrBackendSemaphore>* end_semaphores,
+      std::unique_ptr<GrBackendSurfaceMutableState>* end_state) override {
     DCHECK(!write_surface_);
     return wrapped_sk_image()->promise_texture();
   }
diff --git a/ios/chrome/browser/ui/promos_manager/BUILD.gn b/ios/chrome/browser/ui/promos_manager/BUILD.gn
index 5e45b1b5..37cbcc8 100644
--- a/ios/chrome/browser/ui/promos_manager/BUILD.gn
+++ b/ios/chrome/browser/ui/promos_manager/BUILD.gn
@@ -6,9 +6,10 @@
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
     "promo_protocol.h",
+    "promos_manager_scene_availability_observer.h",
     "standard_promo_display_handler.h",
   ]
-  frameworks = [ "Foundation.framework" ]
+  frameworks = [ "UIKit.framework" ]
   deps = [
     "//ios/chrome/browser/promos_manager:constants",
     "//ios/chrome/browser/promos_manager:types",
@@ -22,6 +23,7 @@
     "promos_manager_scene_agent.mm",
   ]
   deps = [
+    ":promos",
     "//base",
     "//ios/chrome/app/application_delegate:app_state_header",
     "//ios/chrome/browser/ui/main:observing_scene_agent",
diff --git a/ios/chrome/browser/ui/promos_manager/promos_manager_scene_agent.h b/ios/chrome/browser/ui/promos_manager/promos_manager_scene_agent.h
index e519172..3197fd9 100644
--- a/ios/chrome/browser/ui/promos_manager/promos_manager_scene_agent.h
+++ b/ios/chrome/browser/ui/promos_manager/promos_manager_scene_agent.h
@@ -7,8 +7,10 @@
 
 #import "ios/chrome/browser/ui/main/observing_scene_state_agent.h"
 
-// A scene agent that monitors the state of the app and informs the Promos
-// Manager it's a valid time to show a promo. Promos are shown when the UI is
+@protocol PromosManagerSceneAvailabilityObserver;
+
+// A scene agent that monitors the state of the app and informs its observer
+// that it's a valid time to show a promo. Promos are shown when the UI is
 // available (i.e. the app & scene state allow it).
 //
 // The UI is considered available when the following conditions are met:
@@ -26,13 +28,20 @@
 // (2) the scene becomes active in the foreground, and
 // (3) the UI blocker is removed.
 //
-// In a multi-window context, only one scene will present the promo. The first
-// scene to receive the event that triggers the promo will be the one selected.
-// Another scene will be selected if the presenting scene is dismissed.
+// In a multi-window context, only one scene will present the promo: the most
+// recently foregrounded scene. The first scene to receive the event that
+// triggers the promo will be the one selected. Another scene will be selected
+// if the presenting scene is dismissed.
 @interface PromosManagerSceneAgent : ObservingSceneAgent
 
 - (instancetype)init;
 
+// Adds observer that registers promo scene availability updates.
+- (void)addObserver:(id<PromosManagerSceneAvailabilityObserver>)observer;
+
+// Removes observer that registers promo scene availability updates.
+- (void)removeObserver:(id<PromosManagerSceneAvailabilityObserver>)observer;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_PROMOS_MANAGER_PROMOS_MANAGER_SCENE_AGENT_H_
diff --git a/ios/chrome/browser/ui/promos_manager/promos_manager_scene_agent.mm b/ios/chrome/browser/ui/promos_manager/promos_manager_scene_agent.mm
index 5b301703..6b813a65 100644
--- a/ios/chrome/browser/ui/promos_manager/promos_manager_scene_agent.mm
+++ b/ios/chrome/browser/ui/promos_manager/promos_manager_scene_agent.mm
@@ -9,6 +9,7 @@
 #import "ios/chrome/app/application_delegate/app_state_observer.h"
 #import "ios/chrome/app/application_delegate/startup_information.h"
 #import "ios/chrome/browser/ui/main/scene_state.h"
+#import "ios/chrome/browser/ui/promos_manager/promos_manager_scene_availability_observer.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -17,12 +18,21 @@
 namespace {
 
 // If the previous app foregrounding occurred less than
-// `kMinutesBetweenForegrounding` minutes ago, a promo won't be displayed.
-constexpr int kMinutesBetweenForegrounding = 240;  // (4 hours) (inclusive)
+// `kHoursBetweenForegrounding` hours ago, a promo won't be displayed.
+constexpr base::TimeDelta kHoursBetweenForegrounding =
+    base::Hours(4);  // (4 hours) (inclusive)
 
 }  // namespace
 
 @interface PromosManagerSceneAgent () <AppStateObserver>
+
+// Weak reference to observer object.
+@property(nonatomic, weak) id<PromosManagerSceneAvailabilityObserver> observer;
+
+// Indicates whether or not the UI is available for a promo to be displayed.
+@property(nonatomic, assign, readonly, getter=isUIAvailableForPromo)
+    BOOL UIAvailableForPromo;
+
 @end
 
 @implementation PromosManagerSceneAgent
@@ -33,6 +43,16 @@
   return self;
 }
 
+#pragma mark - PromosManagerSceneAvailabilityObserver
+
+- (void)addObserver:(id<PromosManagerSceneAvailabilityObserver>)observer {
+  self.observer = observer;
+}
+
+- (void)removeObserver:(id<PromosManagerSceneAvailabilityObserver>)observer {
+  self.observer = nil;
+}
+
 #pragma mark - ObservingSceneAgent
 
 - (void)setSceneState:(SceneState*)sceneState {
@@ -47,7 +67,7 @@
     didTransitionFromInitStage:(InitStage)previousInitStage {
   // Monitor the app intialization stages to consider showing a promo at a point
   // in the initialization of the app that allows it.
-  [self handlePromoDisplayIfUIAvailable];
+  [self maybeNotifyObserver];
 }
 
 #pragma mark - SceneStateObserver
@@ -62,15 +82,15 @@
   // Monitor the scene activation level to consider showing a promo
   // when the scene becomes active and in the foreground. In which case the
   // scene is visible and interactable.
-  [self handlePromoDisplayIfUIAvailable];
+  [self maybeNotifyObserver];
 }
 
 #pragma mark - Private
 
-// Handle the display of a promo if the scene UI is available to display one.
-- (void)handlePromoDisplayIfUIAvailable {
-  if (![self isUIAvailableForPromo])
-    return;
+// Notify observer(s) that the UI is available for a promo.
+- (void)maybeNotifyObserver {
+  if (self.UIAvailableForPromo)
+    [self.observer sceneDidBecomeAvailableForPromo];
 }
 
 // Returns YES if a promo can be displayed.
@@ -87,14 +107,13 @@
   if (self.sceneState.activationLevel < SceneActivationLevelForegroundActive)
     return NO;
 
-  // (3) At least `kMinutesBetweenForegrounding` have elapsed since the app was
+  // (3) At least `kHoursBetweenForegrounding` have elapsed since the app was
   // last foregrounded, if ever.
   if (!self.sceneState.appState.lastTimeInForeground.is_null()) {
     base::TimeDelta elapsedTimeSinceLastForeground =
         base::TimeTicks::Now() - self.sceneState.appState.lastTimeInForeground;
 
-    if (elapsedTimeSinceLastForeground.InMinutes() <
-        kMinutesBetweenForegrounding)
+    if (elapsedTimeSinceLastForeground < kHoursBetweenForegrounding)
       return NO;
   }
 
diff --git a/ios/chrome/browser/ui/promos_manager/promos_manager_scene_availability_observer.h b/ios/chrome/browser/ui/promos_manager/promos_manager_scene_availability_observer.h
new file mode 100644
index 0000000..6ba135f
--- /dev/null
+++ b/ios/chrome/browser/ui/promos_manager/promos_manager_scene_availability_observer.h
@@ -0,0 +1,21 @@
+// Copyright 2022 The Chromium Authors.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_PROMOS_MANAGER_PROMOS_MANAGER_SCENE_AVAILABILITY_OBSERVER_H_
+#define IOS_CHROME_BROWSER_UI_PROMOS_MANAGER_PROMOS_MANAGER_SCENE_AVAILABILITY_OBSERVER_H_
+
+#import <UIKit/UIKit.h>
+
+// Observer protocol to inform about scene availability changes. Informs
+// observers when the scene is deemed to be in a valid, eligible state
+// to display a promo.
+@protocol PromosManagerSceneAvailabilityObserver <NSObject>
+
+// Indicates the scene has changed and become available to display a
+// promo.
+- (void)sceneDidBecomeAvailableForPromo;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_PROMOS_MANAGER_PROMOS_MANAGER_SCENE_AVAILABILITY_OBSERVER_H_
diff --git a/media/base/video_frame.h b/media/base/video_frame.h
index fe90648..eff1435 100644
--- a/media/base/video_frame.h
+++ b/media/base/video_frame.h
@@ -433,7 +433,7 @@
                                  base::ReadOnlySharedMemoryMapping mapping);
 
   // Valid for shared memory backed VideoFrames.
-  const base::ReadOnlySharedMemoryRegion* shm_region() {
+  const base::ReadOnlySharedMemoryRegion* shm_region() const {
     DCHECK(IsValidSharedMemoryFrame());
     DCHECK(storage_type_ == STORAGE_SHMEM);
     return shm_region_;
diff --git a/media/gpu/test/video_encoder/video_encoder_client.cc b/media/gpu/test/video_encoder/video_encoder_client.cc
index d4222e8..e80f164 100644
--- a/media/gpu/test/video_encoder/video_encoder_client.cc
+++ b/media/gpu/test/video_encoder/video_encoder_client.cc
@@ -316,7 +316,7 @@
       encoder_client_config_.input_storage_type ==
               VideoEncodeAccelerator::Config::StorageType::kGpuMemoryBuffer
           ? VideoFrame::STORAGE_GPU_MEMORY_BUFFER
-          : VideoFrame::STORAGE_MOJO_SHARED_BUFFER);
+          : VideoFrame::STORAGE_SHMEM);
 
   output_buffer_size_ = output_buffer_size;
 
diff --git a/media/gpu/test/video_test_helpers.cc b/media/gpu/test/video_test_helpers.cc
index bcd03a3..834f53c 100644
--- a/media/gpu/test/video_test_helpers.cc
+++ b/media/gpu/test/video_test_helpers.cc
@@ -19,7 +19,6 @@
 #include "media/filters/vp9_parser.h"
 #include "media/gpu/test/video.h"
 #include "media/gpu/test/video_frame_helpers.h"
-#include "media/mojo/common/mojo_shared_buffer_video_frame.h"
 #include "media/parsers/vp8_parser.h"
 #include "mojo/public/cpp/system/buffer.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -407,7 +406,7 @@
     InitializeGpuMemoryBufferFrames(stream, pixel_format, src_coded_size,
                                     dst_coded_size);
   } else {
-    LOG_ASSERT(storage_type == VideoFrame::STORAGE_MOJO_SHARED_BUFFER);
+    LOG_ASSERT(storage_type == VideoFrame::STORAGE_SHMEM);
     InitializeAlignedMemoryFrames(stream, pixel_format, src_coded_size,
                                   dst_coded_size);
   }
@@ -489,19 +488,18 @@
       LOG(ERROR) << "Failed duplicating shmem region";
       return nullptr;
     }
+    base::ReadOnlySharedMemoryMapping mapping = shmem_region.Map();
+    uint8_t* buf = const_cast<uint8_t*>(mapping.GetMemoryAs<uint8_t>());
+    uint8_t* data[3] = {};
+    for (size_t i = 0; layout_->planes().size(); i++)
+      data[i] = buf + layout_->planes()[i].offset;
 
-    std::vector<uint32_t> offsets(layout_->planes().size());
-    std::vector<int32_t> strides(layout_->planes().size());
-    for (size_t i = 0; i < layout_->planes().size(); i++) {
-      offsets[i] = layout_->planes()[i].offset;
-      strides[i] = layout_->planes()[i].stride;
-    }
-    const size_t video_frame_size =
-        layout_->planes().back().offset + layout_->planes().back().size;
-    DCHECK_EQ(video_frame_size, dup_region.GetSize());
-    return MojoSharedBufferVideoFrame::Create(
-        layout_->format(), layout_->coded_size(), visible_rect_, natural_size_,
-        std::move(dup_region), offsets, strides, frame_timestamp);
+    auto frame = media::VideoFrame::WrapExternalYuvDataWithLayout(
+        *layout_, visible_rect_, natural_size_, data[0], data[1], data[2],
+        frame_timestamp);
+    DCHECK(frame);
+    frame->BackWithOwnedSharedMemory(std::move(dup_region), std::move(mapping));
+    return frame;
   }
 }
 
diff --git a/media/gpu/v4l2/v4l2_video_encode_accelerator.cc b/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
index 6c2ac5c..07b5494 100644
--- a/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
@@ -431,7 +431,7 @@
 
   VideoFrame::StorageType input_storage_type =
       native_input_mode_ ? VideoFrame::STORAGE_GPU_MEMORY_BUFFER
-                         : VideoFrame::STORAGE_MOJO_SHARED_BUFFER;
+                         : VideoFrame::STORAGE_SHMEM;
   auto input_config = VideoFrameLayoutToPortConfig(
       *ip_input_layout, input_visible_rect, {input_storage_type});
   if (!input_config) {
diff --git a/media/mojo/clients/mojo_decryptor.cc b/media/mojo/clients/mojo_decryptor.cc
index 33f472f..3491af89 100644
--- a/media/mojo/clients/mojo_decryptor.cc
+++ b/media/mojo/clients/mojo_decryptor.cc
@@ -16,7 +16,6 @@
 #include "media/base/video_frame.h"
 #include "media/mojo/common/media_type_converters.h"
 #include "media/mojo/common/mojo_decoder_buffer_converter.h"
-#include "media/mojo/common/mojo_shared_buffer_video_frame.h"
 #include "media/mojo/mojom/decryptor.mojom.h"
 #include "mojo/public/cpp/bindings/callback_helpers.h"
 
diff --git a/media/mojo/clients/mojo_decryptor_unittest.cc b/media/mojo/clients/mojo_decryptor_unittest.cc
index 04383ed8..adb4b99 100644
--- a/media/mojo/clients/mojo_decryptor_unittest.cc
+++ b/media/mojo/clients/mojo_decryptor_unittest.cc
@@ -16,7 +16,6 @@
 #include "media/base/timestamp_constants.h"
 #include "media/base/video_frame.h"
 #include "media/mojo/clients/mojo_decryptor.h"
-#include "media/mojo/common/mojo_shared_buffer_video_frame.h"
 #include "media/mojo/mojom/decryptor.mojom.h"
 #include "media/mojo/services/mojo_decryptor_service.h"
 #include "mojo/public/cpp/bindings/receiver.h"
@@ -72,16 +71,22 @@
 
   void ReturnSharedBufferVideoFrame(scoped_refptr<DecoderBuffer> encrypted,
                                     Decryptor::VideoDecodeCB video_decode_cb) {
-    // We don't care about the encrypted data, just create a simple VideoFrame.
-    scoped_refptr<VideoFrame> frame(
-        MojoSharedBufferVideoFrame::CreateDefaultForTesting(
-            PIXEL_FORMAT_I420, gfx::Size(100, 100), base::Seconds(100)));
+    // We don't care about the encrypted data, just create a simple SHMEM
+    // VideoFrame.
+    auto region = base::ReadOnlySharedMemoryRegion::Create(15000);
+    CHECK(region.IsValid());
+    uint8_t* data = const_cast<uint8_t*>(region.mapping.GetMemoryAs<uint8_t>());
+    scoped_refptr<VideoFrame> frame = VideoFrame::WrapExternalYuvData(
+        PIXEL_FORMAT_I420, gfx::Size(100, 100), gfx::Rect(100, 100),
+        gfx::Size(100, 100), 100, 50, 50, data, data + 100 * 100,
+        data + (100 * 100 * 5 / 4), base::Seconds(100));
+    auto read_only_mapping = region.region.Map();
+    CHECK(read_only_mapping.IsValid());
+    frame->BackWithOwnedSharedMemory(std::move(region.region),
+                                     std::move(read_only_mapping));
     frame->AddDestructionObserver(base::BindOnce(
         &MojoDecryptorTest::OnFrameDestroyed, base::Unretained(this)));
 
-    // Currently freeing buffers only works for MojoSharedMemory, so make
-    // sure |frame| is of that type.
-    EXPECT_EQ(VideoFrame::STORAGE_MOJO_SHARED_BUFFER, frame->storage_type());
     std::move(video_decode_cb).Run(Decryptor::kSuccess, std::move(frame));
   }
 
diff --git a/media/mojo/clients/mojo_video_encode_accelerator.cc b/media/mojo/clients/mojo_video_encode_accelerator.cc
index 93720d6..a321b7d 100644
--- a/media/mojo/clients/mojo_video_encode_accelerator.cc
+++ b/media/mojo/clients/mojo_video_encode_accelerator.cc
@@ -16,7 +16,6 @@
 #include "media/base/video_frame.h"
 #include "media/gpu/gpu_video_accelerator_util.h"
 #include "media/mojo/clients/mojo_media_log_service.h"
-#include "media/mojo/common/mojo_shared_buffer_video_frame.h"
 #include "media/mojo/mojom/video_encoder_info.mojom.h"
 #include "mojo/public/cpp/bindings/associated_receiver.h"
 #include "mojo/public/cpp/bindings/pending_associated_receiver.h"
@@ -159,8 +158,8 @@
                frame->timestamp());
   DVLOG(2) << __func__ << " tstamp=" << frame->timestamp();
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  size_t num_planes = VideoFrame::NumPlanes(frame->format());
-  DCHECK_EQ(num_planes, frame->layout().num_planes());
+  DCHECK_EQ(VideoFrame::NumPlanes(frame->format()),
+            frame->layout().num_planes());
   DCHECK(vea_.is_bound());
 
   if (frame->format() != PIXEL_FORMAT_I420 &&
@@ -170,44 +169,8 @@
     return;
   }
 
-  scoped_refptr<VideoFrame> mojo_frame;
-  switch (frame->storage_type()) {
-    case VideoFrame::VideoFrame::STORAGE_GPU_MEMORY_BUFFER:
-      // GPU memory path: Pass-through.
-      mojo_frame = frame;
-      break;
-    case VideoFrame::STORAGE_SHMEM: {
-      std::vector<uint32_t> offsets(num_planes);
-      std::vector<int32_t> strides(num_planes);
-      for (size_t i = 0; i < num_planes; ++i) {
-        strides[i] = frame->stride(i);
-        // This offset computation is safe because the planes are in the single
-        // buffer, a single SharedMemoryBuffer. The first plane data must lie
-        // in the beginning of the buffer.
-        offsets[i] =
-            base::saturated_cast<uint32_t>(frame->data(i) - frame->data(0));
-      }
-      mojo_frame = MojoSharedBufferVideoFrame::Create(
-          frame->format(), frame->coded_size(), frame->visible_rect(),
-          frame->natural_size(), frame->shm_region()->Duplicate(), offsets,
-          strides, frame->timestamp());
-    } break;
-    case VideoFrame::STORAGE_UNOWNED_MEMORY:
-      mojo_frame = MojoSharedBufferVideoFrame::CreateFromYUVFrame(*frame);
-      break;
-    default:
-      DLOG(ERROR) << "Unexpected storage type: "
-                  << VideoFrame::StorageTypeToString(frame->storage_type());
-      return;
-  }
-
-  if (!mojo_frame) {
-    DLOG(ERROR) << "Failed creating MojoSharedBufferVideoFrame from YUV";
-    return;
-  }
-  vea_->Encode(
-      std::move(mojo_frame), force_keyframe,
-      base::BindOnce([](scoped_refptr<VideoFrame>) {}, std::move(frame)));
+  vea_->Encode(frame, force_keyframe,
+               base::BindOnce([](scoped_refptr<VideoFrame>) {}, frame));
 }
 
 void MojoVideoEncodeAccelerator::UseOutputBitstreamBuffer(
diff --git a/media/mojo/mojom/media_types.mojom b/media/mojo/mojom/media_types.mojom
index 05a647a..6df660c 100644
--- a/media/mojo/mojom/media_types.mojom
+++ b/media/mojo/mojom/media_types.mojom
@@ -383,7 +383,7 @@
 // Possible choices for storing VideoFrame data.
 union VideoFrameData {
   EosVideoFrameData eos_data;
-  SharedBufferVideoFrameData shared_buffer_data;
+  SharedMemoryVideoFrameData shared_memory_data;
   GpuMemoryBufferVideoFrameData gpu_memory_buffer_data;
   MailboxVideoFrameData mailbox_data;
 };
@@ -392,8 +392,8 @@
 struct EosVideoFrameData {
 };
 
-// This defines video frame data stored in a Mojo shared buffer.
-struct SharedBufferVideoFrameData {
+// This defines video frame data for STORAGE_SHMEM VideoFrame.
+struct SharedMemoryVideoFrameData {
   // Shared memory region for the frame data.
   mojo_base.mojom.ReadOnlySharedMemoryRegion frame_data;
 
diff --git a/media/mojo/mojom/video_frame_mojom_traits.cc b/media/mojo/mojom/video_frame_mojom_traits.cc
index fbec2e1..b0f1393e 100644
--- a/media/mojo/mojom/video_frame_mojom_traits.cc
+++ b/media/mojo/mojom/video_frame_mojom_traits.cc
@@ -15,7 +15,6 @@
 #include "gpu/ipc/common/gpu_memory_buffer_support.h"
 #include "media/base/color_plane_layout.h"
 #include "media/base/format_utils.h"
-#include "media/mojo/common/mojo_shared_buffer_video_frame.h"
 #include "media/mojo/mojom/video_frame_metadata_mojom_traits.h"
 #include "mojo/public/cpp/base/time_mojom_traits.h"
 #include "mojo/public/cpp/system/handle.h"
@@ -31,6 +30,73 @@
 
 namespace {
 
+base::ReadOnlySharedMemoryRegion CreateRegion(const media::VideoFrame& frame,
+                                              std::vector<uint32_t>& offsets,
+                                              std::vector<int32_t>& strides) {
+  if (!media::IsYuvPlanar(frame.format()) || !media::IsOpaque(frame.format())) {
+    DLOG(ERROR) << "format is not opaque YUV: "
+                << VideoPixelFormatToString(frame.format());
+    return base::ReadOnlySharedMemoryRegion();
+  }
+
+  size_t num_planes = media::VideoFrame::NumPlanes(frame.format());
+  DCHECK_LE(num_planes, 3u);
+  offsets.resize(num_planes);
+  strides.resize(num_planes);
+  if (frame.storage_type() == media::VideoFrame::STORAGE_SHMEM) {
+    for (size_t i = 0; i < num_planes; ++i) {
+      // This offset computation is safe because the planes are in the single
+      // buffer, a single SharedMemoryBuffer. The first plane data must lie
+      // in the beginning of the buffer.
+      base::CheckedNumeric<intptr_t> offset =
+          reinterpret_cast<intptr_t>(frame.data(i));
+      offset -= reinterpret_cast<intptr_t>(frame.data(0));
+      if (!offset.AssignIfValid(&offsets[i])) {
+        DLOG(ERROR) << "Invalid offset: "
+                    << static_cast<intptr_t>(frame.data(i) - frame.data(0));
+        return base::ReadOnlySharedMemoryRegion();
+      }
+
+      strides[i] = frame.stride(i);
+    }
+    return frame.shm_region()->Duplicate();
+  }
+
+  // |frame| is on-memory based VideoFrame. Creates a ReadOnlySharedMemoryRegion
+  // and copy the frame data to the region. This DCHECK is safe because of the
+  // the conditional in a calling function.
+  DCHECK(frame.storage_type() == media::VideoFrame::STORAGE_UNOWNED_MEMORY ||
+         frame.storage_type() == media::VideoFrame::STORAGE_OWNED_MEMORY);
+  std::vector<size_t> sizes(num_planes);
+  size_t aggregate_size = 0;
+  for (size_t i = 0; i < num_planes; ++i) {
+    strides[i] = frame.stride(i);
+    offsets[i] = aggregate_size;
+    sizes[i] = media::VideoFrame::Rows(i, frame.format(),
+                                       frame.coded_size().height()) *
+               strides[i];
+    aggregate_size += sizes[i];
+  }
+
+  auto mapped_region = base::ReadOnlySharedMemoryRegion::Create(aggregate_size);
+  if (!mapped_region.IsValid()) {
+    DLOG(ERROR) << "Can't create new frame backing memory";
+    return base::ReadOnlySharedMemoryRegion();
+  }
+
+  base::WritableSharedMemoryMapping& dst_mapping = mapped_region.mapping;
+  uint8_t* dst_data = dst_mapping.GetMemoryAs<uint8_t>();
+  // The data from |frame| may not be consecutive between planes. Copy data into
+  // a shared memory buffer which is tightly packed. Padding inside each planes
+  // are preserved.
+  for (size_t i = 0; i < num_planes; ++i) {
+    memcpy(dst_data + offsets[i], static_cast<const void*>(frame.data(i)),
+           sizes[i]);
+  }
+
+  return std::move(mapped_region.region);
+}
+
 media::mojom::VideoFrameDataPtr MakeVideoFrameData(
     const media::VideoFrame* input) {
   if (input->metadata().end_of_stream) {
@@ -38,23 +104,19 @@
         media::mojom::EosVideoFrameData::New());
   }
 
-  if (input->storage_type() == media::VideoFrame::STORAGE_MOJO_SHARED_BUFFER) {
-    const media::MojoSharedBufferVideoFrame* mojo_frame =
-        static_cast<const media::MojoSharedBufferVideoFrame*>(input);
-
-    base::ReadOnlySharedMemoryRegion region =
-        mojo_frame->shmem_region().Duplicate();
-    DCHECK(region.IsValid());
-    size_t num_planes = media::VideoFrame::NumPlanes(mojo_frame->format());
-    std::vector<uint32_t> offsets(num_planes);
-    std::vector<int32_t> strides(num_planes);
-    for (size_t i = 0; i < num_planes; ++i) {
-      offsets[i] = mojo_frame->PlaneOffset(i);
-      strides[i] = mojo_frame->stride(i);
+  if (input->storage_type() == media::VideoFrame::STORAGE_SHMEM ||
+      input->storage_type() == media::VideoFrame::STORAGE_UNOWNED_MEMORY ||
+      input->storage_type() == media::VideoFrame::STORAGE_OWNED_MEMORY) {
+    std::vector<uint32_t> offsets;
+    std::vector<int32_t> strides;
+    auto region = CreateRegion(*input, offsets, strides);
+    if (!region.IsValid()) {
+      DLOG(ERROR) << "Failed to create region from VideoFrame";
+      return nullptr;
     }
 
-    return media::mojom::VideoFrameData::NewSharedBufferData(
-        media::mojom::SharedBufferVideoFrameData::New(
+    return media::mojom::VideoFrameData::NewSharedMemoryData(
+        media::mojom::SharedMemoryVideoFrameData::New(
             std::move(region), std::move(strides), std::move(offsets)));
   }
 
@@ -129,23 +191,54 @@
     return false;
 
   scoped_refptr<media::VideoFrame> frame;
-  if (data.is_shared_buffer_data()) {
-    media::mojom::SharedBufferVideoFrameDataDataView shared_buffer_data;
-    data.GetSharedBufferDataDataView(&shared_buffer_data);
+  if (data.is_shared_memory_data()) {
+    media::mojom::SharedMemoryVideoFrameDataDataView shared_memory_data;
+    data.GetSharedMemoryDataDataView(&shared_memory_data);
 
     base::ReadOnlySharedMemoryRegion region;
-    if (!shared_buffer_data.ReadFrameData(&region))
+    if (!shared_memory_data.ReadFrameData(&region))
       return false;
 
     mojo::ArrayDataView<uint32_t> offsets;
-    shared_buffer_data.GetOffsetsDataView(&offsets);
+    shared_memory_data.GetOffsetsDataView(&offsets);
 
     mojo::ArrayDataView<int32_t> strides;
-    shared_buffer_data.GetStridesDataView(&strides);
+    shared_memory_data.GetStridesDataView(&strides);
 
-    frame = media::MojoSharedBufferVideoFrame::Create(
-        format, coded_size, visible_rect, natural_size, std::move(region),
-        offsets, strides, timestamp);
+    base::ReadOnlySharedMemoryMapping mapping = region.Map();
+    if (!mapping.IsValid()) {
+      DLOG(ERROR) << "Failed to map ReadOnlySharedMemoryRegion";
+      return false;
+    }
+
+    const size_t num_planes = offsets.size();
+    if (num_planes == 0 || num_planes > 3) {
+      DLOG(ERROR) << "Invalid number of planes: " << num_planes;
+      return false;
+    }
+
+    uint8_t* addr[3] = {};
+    std::vector<media::ColorPlaneLayout> planes(num_planes);
+    for (size_t i = 0; i < num_planes; i++) {
+      addr[i] =
+          const_cast<uint8_t*>(mapping.GetMemoryAs<uint8_t>()) + offsets[i];
+      planes[i].stride = strides[i];
+      planes[i].offset = base::strict_cast<size_t>(offsets[i]);
+      planes[i].size = i + 1 < num_planes
+                           ? offsets[i + 1] - offsets[i]
+                           : mapping.size() - offsets[num_planes - 1];
+    }
+
+    auto layout = media::VideoFrameLayout::CreateWithPlanes(format, coded_size,
+                                                            std::move(planes));
+    if (!layout) {
+      DLOG(ERROR) << "Invalid layout";
+      return false;
+    }
+    frame = media::VideoFrame::WrapExternalYuvDataWithLayout(
+        *layout, visible_rect, natural_size, addr[0], addr[1], addr[2],
+        timestamp);
+    frame->BackWithOwnedSharedMemory(std::move(region), std::move(mapping));
   } else if (data.is_gpu_memory_buffer_data()) {
     media::mojom::GpuMemoryBufferVideoFrameDataDataView gpu_memory_buffer_data;
     data.GetGpuMemoryBufferDataDataView(&gpu_memory_buffer_data);
@@ -153,6 +246,7 @@
     gfx::GpuMemoryBufferHandle gpu_memory_buffer_handle;
     if (!gpu_memory_buffer_data.ReadGpuMemoryBufferHandle(
             &gpu_memory_buffer_handle)) {
+      DLOG(ERROR) << "Failed to read GpuMemoryBufferHandle";
       return false;
     }
 
diff --git a/media/mojo/mojom/video_frame_mojom_traits_unittest.cc b/media/mojo/mojom/video_frame_mojom_traits_unittest.cc
index 13864dfe..33e59f8df 100644
--- a/media/mojo/mojom/video_frame_mojom_traits_unittest.cc
+++ b/media/mojo/mojom/video_frame_mojom_traits_unittest.cc
@@ -13,7 +13,6 @@
 #include "gpu/command_buffer/common/sync_token.h"
 #include "media/base/color_plane_layout.h"
 #include "media/base/video_frame.h"
-#include "media/mojo/common/mojo_shared_buffer_video_frame.h"
 #include "media/mojo/mojom/traits_test_service.mojom.h"
 #include "media/video/fake_gpu_memory_buffer.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
@@ -76,25 +75,66 @@
   EXPECT_TRUE(frame->metadata().end_of_stream);
 }
 
-TEST_F(VideoFrameStructTraitsTest, MojoSharedBufferVideoFrame) {
-  VideoPixelFormat formats[] = {PIXEL_FORMAT_I420, PIXEL_FORMAT_NV12};
+TEST_F(VideoFrameStructTraitsTest, MappableVideoFrame) {
+  constexpr VideoFrame::StorageType storage_types[] = {
+      VideoFrame::STORAGE_SHMEM,
+      VideoFrame::STORAGE_OWNED_MEMORY,
+      VideoFrame::STORAGE_UNOWNED_MEMORY,
+  };
+  constexpr VideoPixelFormat formats[] = {PIXEL_FORMAT_I420, PIXEL_FORMAT_NV12};
+  constexpr gfx::Size kCodedSize(100, 100);
+  constexpr gfx::Rect kVisibleRect(kCodedSize);
+  constexpr gfx::Size kNaturalSize = kCodedSize;
+  constexpr double kFrameRate = 42.0;
+  constexpr base::TimeDelta kTimestamp = base::Seconds(100);
   for (auto format : formats) {
-    scoped_refptr<VideoFrame> frame =
-        MojoSharedBufferVideoFrame::CreateDefaultForTesting(
-            format, gfx::Size(100, 100), base::Seconds(100));
-    frame->metadata().frame_rate = 42.0;
+    for (auto storage_type : storage_types) {
+      scoped_refptr<media::VideoFrame> frame;
+      base::MappedReadOnlyRegion region;
+      if (storage_type == VideoFrame::STORAGE_OWNED_MEMORY) {
+        frame = media::VideoFrame::CreateFrame(format, kCodedSize, kVisibleRect,
+                                               kNaturalSize, kTimestamp);
+      } else {
+        std::vector<int32_t> strides =
+            VideoFrame::ComputeStrides(format, kCodedSize);
+        size_t aggregate_size = 0;
+        size_t sizes[3] = {};
+        for (size_t i = 0; i < strides.size(); ++i) {
+          sizes[i] = media::VideoFrame::Rows(i, format, kCodedSize.height()) *
+                     strides[i];
+          aggregate_size += sizes[i];
+        }
+        region = base::ReadOnlySharedMemoryRegion::Create(aggregate_size);
+        ASSERT_TRUE(region.IsValid());
 
-    ASSERT_TRUE(RoundTrip(&frame));
-    ASSERT_TRUE(frame);
-    EXPECT_FALSE(frame->metadata().end_of_stream);
-    EXPECT_EQ(*frame->metadata().frame_rate, 42.0);
-    EXPECT_EQ(frame->coded_size(), gfx::Size(100, 100));
-    EXPECT_EQ(frame->timestamp(), base::Seconds(100));
+        uint8_t* data[3] = {};
+        data[0] = const_cast<uint8_t*>(region.mapping.GetMemoryAs<uint8_t>());
+        for (size_t i = 1; i < strides.size(); ++i)
+          data[i] = data[i - 1] + sizes[i];
 
-    ASSERT_EQ(frame->storage_type(), VideoFrame::STORAGE_MOJO_SHARED_BUFFER);
-    MojoSharedBufferVideoFrame* mojo_shared_buffer_frame =
-        static_cast<MojoSharedBufferVideoFrame*>(frame.get());
-    EXPECT_TRUE(mojo_shared_buffer_frame->shmem_region().IsValid());
+        strides.resize(3, 0);
+        frame = media::VideoFrame::WrapExternalYuvData(
+            format, kCodedSize, kVisibleRect, kNaturalSize, strides[0],
+            strides[1], strides[2], data[0], data[1], data[2], kTimestamp);
+        if (storage_type == VideoFrame::STORAGE_SHMEM)
+          frame->BackWithSharedMemory(&region.region);
+      }
+
+      ASSERT_TRUE(frame);
+      frame->metadata().frame_rate = kFrameRate;
+      ASSERT_EQ(frame->storage_type(), storage_type);
+      ASSERT_TRUE(RoundTrip(&frame));
+      ASSERT_TRUE(frame);
+      EXPECT_FALSE(frame->metadata().end_of_stream);
+      EXPECT_EQ(frame->format(), format);
+      EXPECT_EQ(*frame->metadata().frame_rate, kFrameRate);
+      EXPECT_EQ(frame->coded_size(), kCodedSize);
+      EXPECT_EQ(frame->visible_rect(), kVisibleRect);
+      EXPECT_EQ(frame->natural_size(), kNaturalSize);
+      EXPECT_EQ(frame->timestamp(), kTimestamp);
+      ASSERT_EQ(frame->storage_type(), VideoFrame::STORAGE_SHMEM);
+      EXPECT_TRUE(frame->shm_region()->IsValid());
+    }
   }
 }
 
diff --git a/media/mojo/services/mojo_cdm_allocator.cc b/media/mojo/services/mojo_cdm_allocator.cc
index 120c9e7b..0037bb4 100644
--- a/media/mojo/services/mojo_cdm_allocator.cc
+++ b/media/mojo/services/mojo_cdm_allocator.cc
@@ -10,14 +10,14 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/compiler_specific.h"
+#include "base/memory/read_only_shared_memory_region.h"
 #include "base/memory/shared_memory_mapping.h"
-#include "base/memory/unsafe_shared_memory_region.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/numerics/safe_math.h"
+#include "media/base/video_frame.h"
 #include "media/cdm/api/content_decryption_module.h"
 #include "media/cdm/cdm_helpers.h"
 #include "media/cdm/cdm_type_conversion.h"
-#include "media/mojo/common/mojo_shared_buffer_video_frame.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -25,20 +25,22 @@
 
 namespace {
 
-using RecycleRegionCB = base::OnceCallback<void(base::MappedReadOnlyRegion)>;
+using RecycleRegionCB =
+    base::OnceCallback<void(std::unique_ptr<base::MappedReadOnlyRegion>)>;
 
 // cdm::Buffer implementation that provides access to mojo shared memory.
 // It owns the memory until Destroy() is called.
 class MojoCdmBuffer final : public cdm::Buffer {
  public:
-  MojoCdmBuffer(base::MappedReadOnlyRegion mapped_region,
+  MojoCdmBuffer(std::unique_ptr<base::MappedReadOnlyRegion> mapped_region,
                 RecycleRegionCB recycle_region_cb)
       : mapped_region_(std::move(mapped_region)),
         recycle_region_cb_(std::move(recycle_region_cb)) {
-    DCHECK(mapped_region_.IsValid());
+    DCHECK(mapped_region_);
+    DCHECK(mapped_region_->IsValid());
     DCHECK(recycle_region_cb_);
     // cdm::Buffer interface limits capacity to uint32.
-    CHECK_LE(mapped_region_.region.GetSize(),
+    CHECK_LE(mapped_region_->region.GetSize(),
              std::numeric_limits<uint32_t>::max());
   }
 
@@ -48,7 +50,7 @@
   // cdm::Buffer implementation.
   void Destroy() final {
     // If nobody has claimed the handle, then return it.
-    if (mapped_region_.IsValid()) {
+    if (mapped_region_ && mapped_region_->IsValid()) {
       std::move(recycle_region_cb_).Run(std::move(mapped_region_));
     }
 
@@ -56,10 +58,10 @@
     delete this;
   }
 
-  uint32_t Capacity() const final { return mapped_region_.mapping.size(); }
+  uint32_t Capacity() const final { return mapped_region_->mapping.size(); }
 
   uint8_t* Data() final {
-    return mapped_region_.mapping.GetMemoryAs<uint8_t>();
+    return mapped_region_->mapping.GetMemoryAs<uint8_t>();
   }
 
   void SetSize(uint32_t size) final {
@@ -69,21 +71,23 @@
 
   uint32_t Size() const final { return size_; }
 
-  const base::MappedReadOnlyRegion& Region() const { return mapped_region_; }
-  base::MappedReadOnlyRegion TakeRegion() { return std::move(mapped_region_); }
+  const base::MappedReadOnlyRegion& Region() const { return *mapped_region_; }
+  std::unique_ptr<base::MappedReadOnlyRegion> TakeRegion() {
+    return std::move(mapped_region_);
+  }
 
  private:
   ~MojoCdmBuffer() final {
     // Verify that the buffer has been returned so it can be reused.
-    DCHECK(!mapped_region_.IsValid());
+    DCHECK(!mapped_region_);
   }
 
-  base::MappedReadOnlyRegion mapped_region_;
+  std::unique_ptr<base::MappedReadOnlyRegion> mapped_region_;
   RecycleRegionCB recycle_region_cb_;
   uint32_t size_ = 0;
 };
 
-// VideoFrameImpl that is able to create a MojoSharedBufferVideoFrame
+// VideoFrameImpl that is able to create a STORAGE_SHMEM VideoFrame
 // out of the data.
 class MojoCdmVideoFrame final : public VideoFrameImpl {
  public:
@@ -103,32 +107,37 @@
     MojoCdmBuffer* buffer = static_cast<MojoCdmBuffer*>(FrameBuffer());
     const gfx::Size frame_size(Size().width, Size().height);
 
-    base::MappedReadOnlyRegion mapped_region = buffer->TakeRegion();
-    DCHECK(mapped_region.region.IsValid());
+    std::unique_ptr<base::MappedReadOnlyRegion> mapped_region =
+        buffer->TakeRegion();
+    DCHECK(mapped_region);
+    DCHECK(mapped_region->region.IsValid());
 
     // Clear FrameBuffer so that MojoCdmVideoFrame no longer has a reference
-    // to it (memory will be transferred to MojoSharedBufferVideoFrame).
+    // to it (memory will be transferred to media::VideoFrame).
     SetFrameBuffer(nullptr);
 
     // Destroy the MojoCdmBuffer as it is no longer needed.
     buffer->Destroy();
 
-    const uint32_t offsets[] = {PlaneOffset(cdm::kYPlane),
-                                PlaneOffset(cdm::kUPlane),
-                                PlaneOffset(cdm::kVPlane)};
-    const int32_t strides[] = {static_cast<int32_t>(Stride(cdm::kYPlane)),
-                               static_cast<int32_t>(Stride(cdm::kUPlane)),
-                               static_cast<int32_t>(Stride(cdm::kVPlane))};
-    scoped_refptr<MojoSharedBufferVideoFrame> frame =
-        media::MojoSharedBufferVideoFrame::Create(
-            ToMediaVideoFormat(Format()), frame_size, gfx::Rect(frame_size),
-            natural_size, mapped_region.region.Duplicate(), offsets, strides,
-            base::Microseconds(Timestamp()));
+    uint8_t* data =
+        const_cast<uint8_t*>(mapped_region->mapping.GetMemoryAs<uint8_t>());
+    if (PlaneOffset(cdm::kYPlane) != 0u) {
+      LOG(ERROR) << "The first buffer offset is not 0";
+      return nullptr;
+    }
+    auto frame = media::VideoFrame::WrapExternalYuvData(
+        ToMediaVideoFormat(Format()), frame_size, gfx::Rect(frame_size),
+        natural_size, static_cast<int32_t>(Stride(cdm::kYPlane)),
+        static_cast<int32_t>(Stride(cdm::kUPlane)),
+        static_cast<int32_t>(Stride(cdm::kVPlane)),
+        data + PlaneOffset(cdm::kYPlane), data + PlaneOffset(cdm::kUPlane),
+        data + PlaneOffset(cdm::kVPlane), base::Microseconds(Timestamp()));
 
     // |frame| could fail to be created if the memory can't be mapped into
     // this address space.
     if (frame) {
       frame->set_color_space(MediaColorSpace().ToGfxColorSpace());
+      frame->BackWithSharedMemory(&mapped_region->region);
       frame->AddDestructionObserver(base::BindOnce(
           std::move(recycle_region_cb_), std::move(mapped_region)));
     }
@@ -156,11 +165,11 @@
 
   // Reuse a shmem region in the free map if there is one that fits |capacity|.
   // Otherwise, create a new one.
-  base::MappedReadOnlyRegion mapped_region;
+  std::unique_ptr<base::MappedReadOnlyRegion> mapped_region;
   auto found = available_regions_.lower_bound(capacity);
   if (found == available_regions_.end()) {
     mapped_region = AllocateNewRegion(capacity);
-    if (!mapped_region.IsValid()) {
+    if (!mapped_region->IsValid()) {
       return nullptr;
     }
   } else {
@@ -185,7 +194,7 @@
                      weak_ptr_factory_.GetWeakPtr()));
 }
 
-base::MappedReadOnlyRegion MojoCdmAllocator::AllocateNewRegion(
+std::unique_ptr<base::MappedReadOnlyRegion> MojoCdmAllocator::AllocateNewRegion(
     size_t capacity) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
@@ -207,14 +216,16 @@
   // calls. That's why we try to avoid AllocateNewRegion() as much as we can.
   base::CheckedNumeric<size_t> requested_capacity(capacity);
   requested_capacity += kBufferPadding;
-  return base::ReadOnlySharedMemoryRegion::Create(
-      requested_capacity.ValueOrDie());
+  return std::make_unique<base::MappedReadOnlyRegion>(
+      base::ReadOnlySharedMemoryRegion::Create(
+          requested_capacity.ValueOrDie()));
 }
 
 void MojoCdmAllocator::AddRegionToAvailableMap(
-    base::MappedReadOnlyRegion mapped_region) {
+    std::unique_ptr<base::MappedReadOnlyRegion> mapped_region) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  size_t capacity = mapped_region.region.GetSize();
+  DCHECK(mapped_region);
+  size_t capacity = mapped_region->region.GetSize();
   available_regions_.insert({capacity, std::move(mapped_region)});
 }
 
diff --git a/media/mojo/services/mojo_cdm_allocator.h b/media/mojo/services/mojo_cdm_allocator.h
index 0bc1f31..51ce3cc7 100644
--- a/media/mojo/services/mojo_cdm_allocator.h
+++ b/media/mojo/services/mojo_cdm_allocator.h
@@ -40,14 +40,17 @@
   // Map of available buffers. Done as a mapping of capacity to shmem regions to
   // make it efficient to find an available buffer of a particular size.
   // Regions in the map are unmapped.
-  using AvailableRegionMap = std::multimap<size_t, base::MappedReadOnlyRegion>;
+  using AvailableRegionMap =
+      std::multimap<size_t, std::unique_ptr<base::MappedReadOnlyRegion>>;
 
   // Allocates a shmem region of at least |capacity| bytes.
-  base::MappedReadOnlyRegion AllocateNewRegion(size_t capacity);
+  std::unique_ptr<base::MappedReadOnlyRegion> AllocateNewRegion(
+      size_t capacity);
 
   // Returns |region| to the map of available buffers, ready to be used the
   // next time CreateCdmBuffer() is called.
-  void AddRegionToAvailableMap(base::MappedReadOnlyRegion region);
+  void AddRegionToAvailableMap(
+      std::unique_ptr<base::MappedReadOnlyRegion> region);
 
   // Returns the base::MappedReadOnlyRegion for a cdm::Buffer allocated by this
   // class.
diff --git a/media/mojo/services/mojo_decryptor_service.cc b/media/mojo/services/mojo_decryptor_service.cc
index b95abe3f..eacc965 100644
--- a/media/mojo/services/mojo_decryptor_service.cc
+++ b/media/mojo/services/mojo_decryptor_service.cc
@@ -17,7 +17,6 @@
 #include "media/base/video_frame.h"
 #include "media/mojo/common/media_type_converters.h"
 #include "media/mojo/common/mojo_decoder_buffer_converter.h"
-#include "media/mojo/common/mojo_shared_buffer_video_frame.h"
 #include "media/mojo/mojom/demuxer_stream.mojom.h"
 #include "media/mojo/services/mojo_cdm_service_context.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
@@ -37,7 +36,7 @@
   explicit FrameResourceReleaserImpl(scoped_refptr<VideoFrame> frame)
       : frame_(std::move(frame)) {
     DVLOG(3) << __func__;
-    DCHECK_EQ(VideoFrame::STORAGE_MOJO_SHARED_BUFFER, frame_->storage_type());
+    DCHECK_EQ(VideoFrame::STORAGE_SHMEM, frame_->storage_type());
   }
 
   FrameResourceReleaserImpl(const FrameResourceReleaserImpl&) = delete;
@@ -292,7 +291,7 @@
   // If |frame| has shared memory that will be passed back, keep the reference
   // to it until the other side is done with the memory.
   mojo::PendingRemote<mojom::FrameResourceReleaser> releaser;
-  if (frame->storage_type() == VideoFrame::STORAGE_MOJO_SHARED_BUFFER) {
+  if (frame->storage_type() == VideoFrame::STORAGE_SHMEM) {
     mojo::MakeSelfOwnedReceiver(
         std::make_unique<FrameResourceReleaserImpl>(frame),
         releaser.InitWithNewPipeAndPassReceiver());
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index ed4bbf38a..a941053 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -3380,7 +3380,6 @@
     { "name": "onixcco.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "pctonic.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "photoblogverona.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "pluga.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "prefis.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "prepandgo-euro.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "production.vn", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -4371,7 +4370,6 @@
     { "name": "zoneminder.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "6969.us", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "aaeblog.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "advancis.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "anitube-nocookie.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "anitube.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "appartementhaus-badria.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -17790,7 +17788,6 @@
     { "name": "uk.dating", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "unixforum.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "vinesauce.info", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "tanto259.name", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "vega.dyndns.info", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "vintagetrailerbuyers.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "v-u-z.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -18595,7 +18592,6 @@
     { "name": "digitalarchitecture.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "drupal-expert.it", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "elektro-hofmann-gmbh.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "elhall.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "elektro-rossbach.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "dungeon-bbs.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "elektro-woerdehoff.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -26444,7 +26440,6 @@
     { "name": "nexus-exit.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "nifume.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "nodariweb.com.ar", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "nigger.racing", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "nhimf.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "nodefoo.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "node-core-app.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -31047,7 +31042,6 @@
     { "name": "doopdidoop.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "dora.moe", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "dotbrick.co.th", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "dowc.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "dpwsweeps.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "dr-schuessler.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "dragoncave.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -33338,7 +33332,6 @@
     { "name": "fixeaide.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fjugstad.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fleamarketgoods.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "floridahomesinvest.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "floydm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "flyp.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fognini-depablo.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -37440,7 +37433,6 @@
     { "name": "007kf.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "02dl.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "0o0.edu.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "188da.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "192168ll.repair", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "1aim.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "249cq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -41317,7 +41309,6 @@
     { "name": "humblebee.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "humblebee.com.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "humblebee.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "humblebee.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "i9multiequipamentos.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "iahemobile.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "iamhansen.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -53629,7 +53620,6 @@
     { "name": "sholtowu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "shootingstarmedium.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "shopific.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "shuax.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "shuhacksoc.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "siamdevsqua.re", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "siamdevsquare.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -54154,7 +54144,6 @@
     { "name": "readyrowan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "readyrowan.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "recurrentmeningitis.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "reensshop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "regasportshop.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "regularizaeudora.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "rehabreviews.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -58851,7 +58840,6 @@
     { "name": "diagnoseo.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "diagnoseo.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "die-machons.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "digitise.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "distracteddriving.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "doda.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dollchan.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -60196,7 +60184,6 @@
     { "name": "ag88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ai00.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "aisin.ae", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "akoofs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "alarmat.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "alexjett.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "allbigdicks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -64836,7 +64823,6 @@
     { "name": "carefulcolor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "carloshmoreira.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cartaodigi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "cashflowstrategist.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "casino-cash-flow.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "celiac.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "centricagency.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -65050,7 +65036,6 @@
     { "name": "mikaeljansson.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mipnet.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "missivystorm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "mklenterprises.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mklenterprisesacademy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mklenterprisescoaching.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "momobako.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -65133,7 +65118,6 @@
     { "name": "techdatapark.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "the-alan-parsons-project.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "theoriginalmarkz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "thevirtualbookkeepers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tintoria.roma.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tohofc.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tomasmoberg.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -65706,7 +65690,6 @@
     { "name": "k-sails.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kawaiicon.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kb7373.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "kbcso.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kk575757.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "konfekcjonowanie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "koreanrandom.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -66702,7 +66685,6 @@
     { "name": "qttransformation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "quantumcrypto.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "raydolap.web.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "raydolapfiyat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "rbh.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "rca2015.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "recrea.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -71623,7 +71605,6 @@
     { "name": "freewerkt.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fuuko.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "gadgets-cars.com.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "garbott.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "gerinet.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ghana.bz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "giac.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -71852,7 +71833,6 @@
     { "name": "wlmhtrecoverycollege.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wort.lu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wpsermons.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "xiaocg.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xlem.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xn--matua-n7a.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xn--s-0fa.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -76327,7 +76307,6 @@
     { "name": "atlanticmarina.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "audiclubbahrain.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "augur.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "augustoshoppingnet.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "automentesszolnok.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "axiomeosteopathie.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "b4lint.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -77363,7 +77342,6 @@
     { "name": "bangkokcookingclass.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bavomaes.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "beargoggleson.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "beauty-expert.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "betimely.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bgfix.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bibliotekasnow.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -82719,7 +82697,6 @@
     { "name": "study-support-beans.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "suburbansites.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sunrichtec.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "syncevolution.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tannerdewitt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tea-empire.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tech-mfoda.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -82743,7 +82720,6 @@
     { "name": "vault.investments", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "velocityfiber.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "villagemagazines.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "virostack.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "vnetboard.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "voedselbankmoerwijk.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "vvtv.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -85613,7 +85589,6 @@
     { "name": "mta-sts.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "muneni.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mwr.team", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "mxbids.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mybizzmail.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mycloudbits.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "myid.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -88458,7 +88433,6 @@
     { "name": "nusaceningan.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nybcreative.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "oralee.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "ordr.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pavelich.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pc-master.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "penisenlargementpro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -89559,7 +89533,6 @@
     { "name": "websec.nu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "websitesbywordpress.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "weldonconstruction.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "wikimirror.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wilco-s.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wildmine.su", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wowbabykids.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -97101,7 +97074,6 @@
     { "name": "strassberger.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "straylight.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "stream-box.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "streaminginternacional.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "street-hoops.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "street-legal.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "streetstunters.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -107555,7 +107527,6 @@
     { "name": "readyelec.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "regentinvest.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "reischent.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "relijon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "repaxan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "reveconfort.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "riceteeth.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -113638,7 +113609,6 @@
     { "name": "jack.fr.eu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jacobpleiness.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jamesonmelbye.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "jands.co.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jardinesimperiales.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jci.me.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jci.name", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -116610,7 +116580,6 @@
     { "name": "leeman.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lehokolo.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lenoblpech.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "lepetitsavoyardbio.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lertsiritravel.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "les-mains-daure-creation.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lesbianfacesitting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -117216,7 +117185,6 @@
     { "name": "writestreak.team", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wtfcripto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wum.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "wz8.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "x2ox.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xhci.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xmp3.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -123697,7 +123665,6 @@
     { "name": "dallatana.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "damnkid.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dandymodz.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "daneiakartes.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "danielduran.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dannemora.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "darksideprod.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -125541,7 +125508,6 @@
     { "name": "wideweb.host", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wikispiel.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wikkelweb.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "winners.bet", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wolfdig.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wolfflabs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "workclaims.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -125828,7 +125794,6 @@
     { "name": "corecosmetic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "countingdues.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "countryroadsmotorinn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "couponite.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "covid-19.nhs.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "covid19.nhs.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "crazyfly.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -129064,7 +129029,6 @@
     { "name": "alanyatur.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "albylane.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "alcalainos.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "alcancevalor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "aldiafl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "alelin.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "alexdriving.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -129658,7 +129622,6 @@
     { "name": "janbruckner.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jandroegehoff.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jaumepons.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "javasaranamitrasejati.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "javierjurado.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jaydaklingerman.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jelo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -130935,7 +130898,6 @@
     { "name": "i-li.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "icaleo.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "icon-art.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "ieeeaast.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "igamingdirectory.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "igamingsuppliers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ijmondlijn.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -134700,7 +134662,6 @@
     { "name": "x0r.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xeforce.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xn--80aahvz2a9a.xn--p1acf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "xtspeeder.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "yebkw.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "yellowstrips.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "yifanbian.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -135441,7 +135402,6 @@
     { "name": "finanzwende-recherche.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "finanzwende.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fionna.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "firmaadler.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "firstname.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "firstquarterfinance.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fish-9ri.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -136032,7 +135992,6 @@
     { "name": "50plusdating.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "521.dog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "589team.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "7daystodie.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "81.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "81alarm.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "81klima.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -136823,7 +136782,6 @@
     { "name": "szotkowski.fun", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "szyldmax.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tagid.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "takesrv.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "talktobabes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tamistuff.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tamylove.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -138797,7 +138755,6 @@
     { "name": "nggukbo9lbfadcf5.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ngoresan.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nguyensuu.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "nhakhoahaianh.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nhjvillalmanzo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nick-stone.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nicknames.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -144555,7 +144512,6 @@
     { "name": "photophobia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "photoreal.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "photosight.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "phunami.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "picapollochino.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "piccolino.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pigslv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -147777,7 +147733,6 @@
     { "name": "2357.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "24news.net.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "525olive.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "769sc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "773buy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "83i.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "960server.net.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -149012,7 +148967,6 @@
     { "name": "e-e.icu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "e-gc.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ecopark.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "ecyy.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "eheya.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "electricianssouthafrica.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "eleni.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -149172,7 +149126,6 @@
     { "name": "keishi.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kektime.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "keln.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "kelprof.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kenosishomes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kenzelmann.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kieronbartsch.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -151903,7 +151856,6 @@
     { "name": "nitttrbhopal.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nodewire.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "northtints.store", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "nosoxo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nqesh.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nsics.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nubla.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -152567,7 +152519,6 @@
     { "name": "newcapitaldev.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "newcinema.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "newemage.com.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "nicolemunoz.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "niledevelopmentseg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nimbo.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nipponkaigi.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -153850,7 +153801,6 @@
     { "name": "bdgstore.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bdix.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bdragon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "bdt001.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "be-nice.digital", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "be-wear.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "beachmonster.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -155656,7 +155606,6 @@
     { "name": "hypnotechs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hyze.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "i2itherapy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "i5i5i58.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "iboat.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "icddd.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "iceboxstudio.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -155836,7 +155785,6 @@
     { "name": "ivana-models-escorts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ivana-models-escortservice.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ivana-models-escortservice.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "ivf114.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ivifashion.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ivioschool.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ivo-ouwerkerk.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -156320,7 +156268,6 @@
     { "name": "lovethatmakeup.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lovinator.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "loving-house.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "lowendpay.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lower-level.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lower.nu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lowriderz.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -156752,12 +156699,7 @@
     { "name": "nalogomania.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nameserver.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nametalent.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "nanhuibz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "nanhuigmp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nanhuimed.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "nanhuisoft.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "nanhuistory.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "nanhuitech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nanhuitop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nanofate.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nanomusic.co.kr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -157293,7 +157235,6 @@
     { "name": "rul.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "rultek.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "rumah-tanah-dijual.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "rumdulhospital.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "rumeli.edu.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "runcodefor.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ruseartgallery.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -157316,7 +157257,6 @@
     { "name": "safetygoodsfair.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sahararun.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "saharazik.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "sahpa.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sailarmada.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "saily.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "saimedia.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -157455,7 +157395,6 @@
     { "name": "serkanyigit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "servatmandi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "serveistic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "serviceflow.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "serviceland.am", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "servisin.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "servivum.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -157713,7 +157652,6 @@
     { "name": "stadasverige.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "staging-scholar.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "stakedate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "stand.gg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "startlgvtraining.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "starttoact.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "staticfour.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -157874,7 +157812,6 @@
     { "name": "techvoice.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "techwallet.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "techzant.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "teclys.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tecpartnership.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tecsar.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "teczero.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -158264,7 +158201,6 @@
     { "name": "urlauthority.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "urlauthority.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "usa10.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "uselys.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "usenethd.li", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "usor.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "usvisallc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -158424,7 +158360,6 @@
     { "name": "webrats.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "webstar.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "webtech.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "webtorrent.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "webwweb.com.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wecareplatform.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wedcha.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -158566,7 +158501,6 @@
     { "name": "yiguan.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "yjz.hk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ylromania.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "ympifa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "yobify.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "yohannes.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "yonetilenhizmetler.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -162964,7 +162898,6 @@
     { "name": "jasomill.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jeney.hopto.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jin-design.si", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "jiseigames.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "joaosampaio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jobverse.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jointheunseen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -173109,14 +173042,12 @@
     { "name": "how-to-use-elementor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "howwhy.tw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hybrid-hippie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "hyperion-project.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hyperreal.chat", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hyunbridge.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "i-am-seo.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "iacee.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ibargain.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ici.ms", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "icieducation.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "icims.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "icpe.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "icsolutions.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -174550,6 +174481,991 @@
     { "name": "younglabour.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "yovada.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zeeshan.website", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "1001fonts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "21appart.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "21kampus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "2345.lgbt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3dinosaurs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3newsnow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3niu770.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3niu880.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "4dstyle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "4freeprintable.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "511in.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "5thfloormedia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "761link.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "8bitpickle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "a-louest.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aayan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aboutyou.hr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aboutyou.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "abpmuhendislik.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "academiacomercialalpina.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "acpny.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "action.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "actzero.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "addownit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "adulteducation.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aeradoresgaivota.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "air-swift.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "airbnb.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aircleansystems.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aisklabs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aiskskin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aka.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "akrzon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "alandoyle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "albaform.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "allaboutcovers.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "allchan.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "alle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "allegromicro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "allstatedealerservices.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "almudenallacer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aloro.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "alp1ne.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "alphaassurances.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "alternativewireless.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "altospam.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ambujagold.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ameripacfund.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "amessage.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "amessage.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "amessage.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ametrin.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "amigoenergy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "amplifiedit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "amzn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "anar.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "andrecarvalho.net.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "angelvisionary.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "anikschwall.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "anymuscle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "apeironassets.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "appunwrapped.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "apruvd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aptos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aqdance.com.sg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "argico.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "argos.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "arma3.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "artgaragecrewe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "artofgears.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "as203145.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "askcustomboxes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "askllp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aten.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "athens-escorts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "auburnpub.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "autocheck.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aveloair.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "awac.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "awakenaija.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ba7jcm.live", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ba7jcm.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "backyardbella.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "balingwiredirect.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bamboohr.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bamboohr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "barry-callebaut.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "basket-malaunay.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "basse-chaine.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bazel.build", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "beautyspaceshop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bedful.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "beepcar.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "benjaminfulford.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bepersia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "berkadia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "berkshireesupply.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bestparking.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bgoewert.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bibimanga.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "biigtigconsulting.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bioreference.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitdefender.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "blackchrome.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "blackheartbar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bloomberglp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "blorbo.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bluegolf.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bluejeans.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bmak.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bnpparibas.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "boden.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "borderlessmigration.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "borntoraid.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bourrasque-info.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "boutiquedoartista.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "brickzfinance.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "brinker.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "brueggers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "brunobertini.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "brunswick.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "budokan-essen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "builtinboston.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "builtinla.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bullfrogpooltilecleaning.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "businessinsider.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cabenoap.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "calendarinspiration.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "callbell.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "canadapost-postescanada.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "canal4.com.ni", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "canalconfidencial.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "candyflavor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cantongroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "capellacapital.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "capital2020.cat", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "capitalendurancegroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "capitalsejours.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "capro.global", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "captainsonic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "careerfoundry.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "carfaxcanadaappgateway.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cariproperti.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "casinonieuws.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "casinosnederland.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "centerenergytherapy.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "centralbank.ae", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cgsociety.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chaturbate.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "childrensmentalhealthcampaign.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chorleycaninesolutions.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "christianreimold.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chsi-kenya.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cirkelinecocodesign.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ck12.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "clearbit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "click2bet.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "clicksacolas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "climeradar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "clocklink.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cloud24x7.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cloudengage.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cloyes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "co3app.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "coco-apo.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "coco.one", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "codero.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "coffeeplazahamburg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "coinjar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "columbiathreadneedle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "comenityremediation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "commodore-rekord.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "communityflow.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "complianz.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "comsolibrasil.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "coresystems.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cosuno.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "countingup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "covo.one", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "coyo.tl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cpstest.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "craft.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "creativenz.govt.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cremicro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "crewpictures.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cric-grenoble.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cronobox.one", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cruiseamerica.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cryptii.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cryptoruay.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "csper.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ct-static.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "culturagenial.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "curiocity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cwtrade.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "d2evs.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "d4insight.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dailyprogress.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "daresay.games", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "daresay.studio", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "daresaygames.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dartmouth-health.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dasabeauty.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "davelbostoncoach.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "davidalbert.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "davidtorres4congress.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "deaecom.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "debtpaypro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "deckshop.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "decor-essentials.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "deeds.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "deephousex.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "defence.pk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "deimos.ws", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "delavska-hranilnica.si", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "delavska.si", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "demeubelmakelaar.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "derivative-calculator.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "designcrowd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "destinypedia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "destock-poitou.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "detectagro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "devalbert.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "devilishsecurity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dfpg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dhr-rgv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "diamwall.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "digitalhack.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "digitalis.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "digityza.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dijoncter.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "disaana.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "distribuidorguarani.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "divorcemortgage.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "divviup.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dksh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "docguide.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dockinabsolute.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dodgersway.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "domainoo.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "donat.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "donquix.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dosequis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dot.la", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dploy.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dreistaxservices.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dresscodeny.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "drivebespokelab.media", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "driveincleveland.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "drought.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "drwongsuni.com.sg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dynasend.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dzogchentoday.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "earthjustice.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "easybank.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "easygenerator.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ebay-kleinanzeigen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "echosearch.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "edb.gov.sg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eddi.org.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "edelweissalternatives.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "edit.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eduium.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eduspiresolutions.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ee.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eennieuwepc.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "effectualness.web.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ekamfoundationmumbai.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "electroschematics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eletom.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eliotchs.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "elvtr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "emechternach.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "emed.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "emlcloud.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "emporioguarani.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "emrawi.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "energylink.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "enfusion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "entertainment-nation.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "epsilonhomebasedqualitycare.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eshappy.tours", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eskandarient.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "espaciohebe.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "estetica.host", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eternl.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eurekapools.com.my", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eurofins.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eventdata.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eventpark.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "everfreecoloring.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "examgraduate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "excelindonesia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "exclusiveresorts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "expansive.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "expensify.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "experience.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eyoo.mayfirst.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "f1nn.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "f2pool.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fabconvert.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "falconicapital.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "falcoz.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "familiasempresariaspanama.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "familyandpets.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fanbolt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fanshenzhiyi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fashionsista.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "festgeldanlagen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fewo.plus", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fewo.reise", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fiberland.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "financialexecutives.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "firstbus.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "firstcommunity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fishingzone.bg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fius.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fixturemundial.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fluidattacks.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fluidsignal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fnpvenues.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fogcreek.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fontsinuse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "foodo.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fordservicetraining.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "forexallday.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "formsite.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "forwardadvantage.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fox47news.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fox4now.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fpcdn.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fracturedperspective.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "freehorseracingtv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "freeride-dragobrat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "freewayinsurance.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "freeyourmusic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "freitas.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "freshporno.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fruitbouquets.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ftth.eu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fumotousa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "furniture-warehouse.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "futurecharcoal.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "futurefund.gov.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "galaxialejana.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gaoice.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gatewayfurniture.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gdacs.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gear4music.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "generalshale.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "georges-sadeler.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "getbodysmart.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "getdirectcredit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "getstream.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "giamcanhieuqua.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "giaohangtietkiem.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gigantron.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gitsr.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gkdforum.eu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gls-spain.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gmkdetailing.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "godsunchained.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gokhangumus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "goldoniclothing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gonitro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "goodcas.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "goodcas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gotravel.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gpnotebook.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gps-coordinates.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "grafana.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "grundschulratgeber.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gtc.com.gt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "guilded.gg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "guzgu.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gw-uks-app-test-coreapi-02.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hairs.london", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "handelsbanken.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "handelsbanken.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hardzone.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hawle-service.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hc-sc.gc.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hcahealthcare.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "headbox.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "heart-valve-surgery.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "heart2heartcpr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hentairead.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hentaishit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "herculesslr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hexagonitsolutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hexil.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "heyfiesta.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hiddenremote.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hinit.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hkp-usa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "holmeslaw.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "homeprotech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hostboxonline.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hostvn.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hotelandplace.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hotlinenum.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hozkomurcu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hpsldc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "htm-partners.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "huis-en-tuin.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hyundaifinance.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "iaata.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "iafd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ibex.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ibk.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ibpservice.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ice.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ictfreak.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ideloving.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ihonk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "iks.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ilmanifesto.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "imagetostl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "imaginethatevent.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "impact.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "impalaparts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "inbrain-api-v2.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "inclassnow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "infinityels.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "inkforall.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "insono.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "intercom-attachments.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "intercom-mail.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "intercomcdn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "intimmix.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "inventoseinventores.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "investire.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "iorn.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "iqredirect.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "irchat.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "isabelladeroldao.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "isoauditr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "issaquah.cam", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "italia-facile.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "itradenetwork.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "itsgottabedark.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ixn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jamiesnape.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jelocalise.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jiji.co.ci", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jiji.sn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jmn.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jmservices.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "join.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jordanmlu.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "josestiller.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "joshthewanderer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "josprox.ovh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "journalstar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jqpowerwash.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jqrecycling.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jso-crescendo.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "julieskitchensf.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jumpseller.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "justaisk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "justgiving.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "justknit.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jyprj.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "k2track.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kadenhealth.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kadifeli.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kahoot.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kaikrups.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "katnip.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kawigraphics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kdo-vola.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "keke125.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "keysix.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "khronos.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kiinde.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kisytech.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "koko.today", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "konsultacje-elektryczne.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "koszmetics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "krabbit.tw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "krimisound.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kvmcloud.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kyaba-kura.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kymta.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "laptop-sewamurah.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "laquintaresort.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "larotative.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lassencanyonnursery.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lastnighton.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "laurenslatest.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "le-clos-st-loup.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "learnosity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lechrismaran.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lemmamedia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lepressoir-info.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lezzetyurdu.com.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lhm.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "libcal.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "libertyreverse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "life360.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "linearb.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "link.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "liveradios.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "livestreamtvbox.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "llcig.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "loirevalley.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lojistaguarani.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lpnm.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lpwb.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lrn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "luncfreak.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lusart.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "m1-garand-rifle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "maastery.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "madaboutsports.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "madcloud.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "madhon.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "madhon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "magic-city.quest", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mailwala.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "makefreecallsonline.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mancaverevolution.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mangakio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "manh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "maniac.msk.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "manif-est.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "manualowl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "martinsvillebulletin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "masinaspalat.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "masqueless.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mat6tube.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mazcue.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mccannhealth.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mcdean.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mcnav.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "meatybubbles.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "media-fleet.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "medmark.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "meetmarlo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "melkboshigh.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "merck-animal-health-usa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mercode.eu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "messemakine.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "metacritic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "metfolio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mg-culture.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mha.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "michaelgijselhart.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "michiganrebates.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "micromicro.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "millennialmoney.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "millenniumhotels.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "milmesetas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "milvus.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "minebbs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "minewiki.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "missoulian.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mobile-discothek.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mobilosoft.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "modernize.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mogbox.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "moneymorning.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "monrasp.ddns.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "morebus.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mote.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "moxfield.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "moyens.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mozo.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "msgr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mspcc.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "munihei.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "muscleandrecovery.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "musecal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "my-how-to-draw.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "my-woodcraft.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "my1login.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mychekker.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "myconradsiegel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mycyberspace.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "myglobalhost.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "myhomice.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "myhu.bz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mykoreankitchen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mymedicareaccount.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "myorders.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "myprivatedns.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mystream.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "myunitypoint.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "naboplastic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nadoba-msk.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "naildesignsjournal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nanjie.com.tw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "narayanahealth.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "naturalreaders.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "navoto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nc3rs.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nceahelp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nederlandmobiel.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "needmytranscript.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "negociosdigitales.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nelsonworldwide.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nema.gov.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "neocirc.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nerdyspace.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "netirio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "networkclear.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "neuca24.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "newplxx.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "newpointeg-broker.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "newpointeg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "newportit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "next-tms.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nightflow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nkghas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nokoshop.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "norebase.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "notebooksteurer.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "novakola.bg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "novy.software", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nurkamol.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nutriklin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nyap.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nyheter24.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nzb.su", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "oanow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "obagg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "oceanfirst.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "odishatv.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "odoranswers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "odzyskiwanie.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "officeguide.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ofisas.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ofpad.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ogilvy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "oier-meet.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ojp.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "oldvps.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "olsenban.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "on-tandemdrive.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "on3static.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "online-content.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "onlineunionbankph.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "opengameart.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "opssurvey.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "orbita.zp.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "organicsearcher.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "osohq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "otng.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ourhr.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "overflow.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "overlooklakeaustin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "owln.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "paintscratch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pandadoc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "panelbear.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "panoramo.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "parkwhiz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "parroquiadelpilarpamplona.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "parsec.app", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pascosheriff.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "passivebook.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "passportunlimited.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "payboy.click", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "paydollar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "payfit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "payproglobal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pband.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pbbm.com.ph", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pcrobot.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pcsoft.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pcstonks.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "peanutbutter.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "peerview.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "people.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "people.deloitte", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "perennialwomens.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pesterchum.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "petyolo.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "phonex.bg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "piizapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pinterest.com.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pinterst.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pitbullinu.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pittohio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "plaid.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "planbase.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "planningcenter.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "platinumkids.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "plooij.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "plumbking.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "positivecoach.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "postnet.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "powercv.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "powertofly.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "prd-use-device-api.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "prebas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "premstarinc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pressed.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pressidium.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "printtolife.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "productive.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "profithuntershub.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "prohashing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "projektanfrage24.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "projektanfragen24.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "proofpointessentials.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "protecht.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "protechtgroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "protenus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "psihiatrice.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "psychologlodz.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pundak.games", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "purchasingpower.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "quotescover.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rainbowlaserspewpew.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "randomactsofkindness.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "readycentral.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "recollective.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "redditinc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "refbanners.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "refpanjoke.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "refpaydc.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "regpacks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "reichelt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "reichelt.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "reimsmediaslibres.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "reisdemuthwiltgen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "reisuke.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "remontstrong.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "reserveandreceive.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "resumidus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "returnly.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "revionics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rhdiscovery.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ripplematch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ritepriceheatingcooling.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "roc.gov.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rosacosmos.tn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rosty.sh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "royal880.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "royal8800.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "royal8811.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "royal8822.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "royal8881.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rqfperformancehorses.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rumaillah.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "run.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ryancompanies.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "s3waas.gov.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sacredmessages.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sanasport.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sanasport.bg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sanasport.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sanasport.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sanasport.si", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sanitaer-heinze.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sanjaymenon.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sanray73.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sarahtamsin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "schlager.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "schlepaaz.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "schnism.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "scientific-editing.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "screeningxchange.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "scributors.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "se.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "seasonsof.berlin", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "seefeldbilder.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "seeme.baby", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "semestaindovest.co.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "serwis-militarny.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "shanyi.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sharkstriker.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "shinycleankitchen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "showsnob.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "siberianhealth.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sidefx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "signrequest.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sikkasoft.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "simplymeatsmoking.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "simulus.hr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "skiff.city", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "skiff.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "skydivegeronimo.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "skyscanner.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "skyscanner.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "skyscanner.com.hk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "skyscanner.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "smithikakart.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "snsp.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "snsp.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sodexoclub.com.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "softonic.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "softwaresecurity2dezit.herokuapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "softwaresecurity2dezitapi.herokuapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "solium.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sorunrehberi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sparklabs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "spiderprotect.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "springbaystudio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sss.red", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stadiamaps.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "startinganllcbusiness.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "statesville.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "statusmicro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stedelijkorkestpurmerend.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stillcurtain.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stmarys-ca.edu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stormininnorman.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "storytel.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "streetwitnessingchurch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "striata.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "striata.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "strosebelmar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "studiofutbol.com.ec", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "style4d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stylight.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stylight.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "suhost.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sunho.net.tw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "supasomsak.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "super365aa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sustainalytics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sv1862ruesselsheim.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "svportalframe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "swedbank.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sweet64.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sydneyvangelder.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "syska.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "t3concrete.my", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tadaimajp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tailorbrands.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "talent-safari.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tangentnetworks.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tarnkappe.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tatemode.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tatewake.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tavola-cescato.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tdn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "teamhealth.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "techalert.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "techgup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "techonline.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "techpedia.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "teebyhuman.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "telfas.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tellimer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "termine.tel", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ternakbisnis.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "teva.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thedelightfuldiet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thedowlinggroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "themologroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "theniska.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thenudge.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "theretailbulletin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "theskiweek.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thesunrisepatisserie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thetechnicaldost.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thethaoso247.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "theyachtweek.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thunderstruckfestival.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tivit-focus-partners.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tjgrant.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "toilet-guru.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "totalexpert.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "touristsense.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "traceyjsvorusphd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "transcendcareers.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "translations.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "travelup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "trawox.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "traxpayroll.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "trendcreate.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "trib.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "trikuj.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "truecrimedaily.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "trustpixel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "trustpoint.one", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "trustzone.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tsw.ovh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tunad.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tunda.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tvguide.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tw-louis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ubereatspos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ukrainianwall.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ulsterbank.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ultimatebattles.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "umami.vercel.app", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "uniforms.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "unilinkbus.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "uniserve.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "universityhealthplans.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "up-schaltanlagen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "upenergy.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "upviral.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ustc.fun", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "uweier.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vakat.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "validation.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "valleesenlutte.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "valnetcdn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vascularlaser.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "venndy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ventanillaproveedorespit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vermo.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "veronicasuperguide.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vertigomassage.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vihtahousu.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "viktoria-stube.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vilabin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vincentvdsluijs.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "virbex.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "virtuology.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vitacellbiologics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vpn-suomi.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wallpaperspeed.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "waxcollectibles.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wcfcourier.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wcsportsmed.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "web-stories.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "webapps-conception.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "webi.ms", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "webi.sh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "weddingbells.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "weddingz.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wellthy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wernerco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wiccanwicks.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wifi.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wilkushka.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wimmer-informatik.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wimmer-musik.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wimmer.green", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "windowsindonesia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wiriamu.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wjec.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wood4heat.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "woodsconsulting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "woohoo.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wordindonesia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wordsinarow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "worldwidescience.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wpguvenlik.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wpmet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wsodownloads.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wtxl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "x17.ink", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xboxplay.games", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn----7sbc3abak3afteia.xn--p1ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn--3btta.xn--fiqs8s", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn--3btta.xn--fiqz9s", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn--6btn.xn--fiqs8s", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn--6btn.xn--fiqz9s", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn--7tq776cdf4a.xn--fiqs8s", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn--7tq776cdf4a.xn--fiqz9s", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn--7tqp36c113a.xn--fiqs8s", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn--7tqp36c113a.xn--fiqz9s", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn--ee-zja.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn--mnich-7ua.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xtralis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xuan.com.my", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xuewen.ink", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yellowfolder.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yeri.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yggdrasil.ws", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yodocon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "youla.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yuliana-hotel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yuucdn.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "z-e.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zandu360.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zapier-staging.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zarabotok24obzor.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zawodowe-szkolenia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zaxbys-web-backend.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zenideen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zhouyipro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ziftone.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zio-enzo.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zipjobs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zscaler.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zylo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zymewire.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     // END OF 1-YEAR BULK HSTS ENTRIES
 
     // Only eTLD+1 domains can be submitted automatically to hstspreload.org,
diff --git a/remoting/codec/webrtc_video_encoder_av1.cc b/remoting/codec/webrtc_video_encoder_av1.cc
index fa3df8c..779d99bf 100644
--- a/remoting/codec/webrtc_video_encoder_av1.cc
+++ b/remoting/codec/webrtc_video_encoder_av1.cc
@@ -10,6 +10,7 @@
 #include "base/system/sys_info.h"
 #include "remoting/base/cpu_utils.h"
 #include "remoting/base/util.h"
+#include "third_party/libaom/source/libaom/aom/aom_image.h"
 #include "third_party/libaom/source/libaom/aom/aomcx.h"
 #include "third_party/libyuv/include/libyuv/convert_from_argb.h"
 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
@@ -48,7 +49,10 @@
 }
 
 void WebrtcVideoEncoderAV1::SetLosslessColor(bool want_lossless) {
-  NOTIMPLEMENTED();
+  if (want_lossless != lossless_color_) {
+    lossless_color_ = want_lossless;
+    codec_.reset();
+  }
 }
 
 bool WebrtcVideoEncoderAV1::InitializeCodec(const webrtc::DesktopSize& size) {
@@ -63,6 +67,9 @@
   // values based on the frame dimensions later on.
   config_.g_threads = GetEncoderThreadCount(std::max(config_.g_w, config_.g_h));
 
+  // Choose a profile based on whether we should provide frames in I420 or I444.
+  config_.g_profile = lossless_color_ ? 1 : 0;
+
   // Initialize an encoder instance.
   scoped_aom_codec codec(new aom_codec_ctx_t, DestroyAomCodecContext);
   codec->name = nullptr;
@@ -198,7 +205,8 @@
     updated_region.IntersectWith(
         webrtc::DesktopRect::MakeWH(image_->d_w, image_->d_h));
   } else {
-    image_.reset(aom_img_alloc(nullptr, AOM_IMG_FMT_I420, frame->size().width(),
+    aom_img_fmt_t fmt = lossless_color_ ? AOM_IMG_FMT_I444 : AOM_IMG_FMT_I420;
+    image_.reset(aom_img_alloc(nullptr, fmt, frame->size().width(),
                                frame->size().height(),
                                GetSimdMemoryAlignment()));
     updated_region.AddRect(
@@ -215,18 +223,37 @@
   uint8_t* u_data = image_->planes[1];
   uint8_t* v_data = image_->planes[2];
 
-  CHECK_EQ(image_->fmt, AOM_IMG_FMT_I420);
-  for (webrtc::DesktopRegion::Iterator r(updated_region); !r.IsAtEnd();
-       r.Advance()) {
-    webrtc::DesktopRect rect = GetRowAlignedRect(r.rect(), image_->d_w);
-    int rgb_offset = rgb_stride * rect.top() +
-                     rect.left() * webrtc::DesktopFrame::kBytesPerPixel;
-    int y_offset = y_stride * rect.top() + rect.left();
-    int uv_offset = uv_stride * rect.top() / 2 + rect.left() / 2;
-    libyuv::ARGBToI420(rgb_data + rgb_offset, rgb_stride, y_data + y_offset,
-                       y_stride, u_data + uv_offset, uv_stride,
-                       v_data + uv_offset, uv_stride, rect.width(),
-                       rect.height());
+  switch (image_->fmt) {
+    case AOM_IMG_FMT_I420:
+      for (webrtc::DesktopRegion::Iterator r(updated_region); !r.IsAtEnd();
+           r.Advance()) {
+        webrtc::DesktopRect rect = GetRowAlignedRect(r.rect(), image_->d_w);
+        int rgb_offset = rgb_stride * rect.top() +
+                         rect.left() * webrtc::DesktopFrame::kBytesPerPixel;
+        int y_offset = y_stride * rect.top() + rect.left();
+        int uv_offset = uv_stride * rect.top() / 2 + rect.left() / 2;
+        libyuv::ARGBToI420(rgb_data + rgb_offset, rgb_stride, y_data + y_offset,
+                           y_stride, u_data + uv_offset, uv_stride,
+                           v_data + uv_offset, uv_stride, rect.width(),
+                           rect.height());
+      }
+      break;
+    case AOM_IMG_FMT_I444:
+      for (webrtc::DesktopRegion::Iterator r(updated_region); !r.IsAtEnd();
+           r.Advance()) {
+        webrtc::DesktopRect rect = GetRowAlignedRect(r.rect(), image_->d_w);
+        int rgb_offset = rgb_stride * rect.top() +
+                         rect.left() * webrtc::DesktopFrame::kBytesPerPixel;
+        int yuv_offset = uv_stride * rect.top() + rect.left();
+        libyuv::ARGBToI444(rgb_data + rgb_offset, rgb_stride,
+                           y_data + yuv_offset, y_stride, u_data + yuv_offset,
+                           uv_stride, v_data + yuv_offset, uv_stride,
+                           rect.width(), rect.height());
+      }
+      break;
+    default:
+      NOTREACHED();
+      break;
   }
 }
 
@@ -240,6 +267,8 @@
 
   // Encoder config values are defined in:
   // //third_party/libaom/source/libaom/aom/aom_encoder.h
+
+  // Default to profile 0 and update later if lossless color is requested.
   config_.g_profile = 0;
   // Width, height, and thread count are set once the frame size is known.
   config_.g_w = 0;
diff --git a/remoting/codec/webrtc_video_encoder_av1.h b/remoting/codec/webrtc_video_encoder_av1.h
index b4b454fa..bdb9dad 100644
--- a/remoting/codec/webrtc_video_encoder_av1.h
+++ b/remoting/codec/webrtc_video_encoder_av1.h
@@ -53,6 +53,10 @@
   using scoped_aom_image = std::unique_ptr<aom_image_t, void (*)(aom_image_t*)>;
   scoped_aom_image image_;
 
+  // Indicates whether the frames provided to the encoder will use I420 (lossy)
+  // or I444 (lossless) format.
+  bool lossless_color_ = false;
+
   // Active map used to optimize out processing of unchanged macroblocks.
   VideoEncoderActiveMap active_map_;
   // Disable |active_map_| until we've verified it improves performance.
diff --git a/remoting/host/disconnect_window_mac.mm b/remoting/host/disconnect_window_mac.mm
index baf5ee9..8246994 100644
--- a/remoting/host/disconnect_window_mac.mm
+++ b/remoting/host/disconnect_window_mac.mm
@@ -59,12 +59,10 @@
       override;
 
  private:
-  DisconnectWindowController* window_controller_;
+  DisconnectWindowController* window_controller_ = nil;
 };
 
-DisconnectWindowMac::DisconnectWindowMac()
-    : window_controller_(nil) {
-}
+DisconnectWindowMac::DisconnectWindowMac() = default;
 
 DisconnectWindowMac::~DisconnectWindowMac() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -164,40 +162,39 @@
   self.disconnectButton.target = self;
   [self.window.contentView addSubview:self.disconnectButton];
 
-  [_connectedToField setStringValue:l10n_util::GetNSStringF(IDS_MESSAGE_SHARED,
-                                                            _username)];
-  [_disconnectButton setTitle:l10n_util::GetNSString(IDS_STOP_SHARING_BUTTON)];
+  self.connectedToField.stringValue =
+      l10n_util::GetNSStringF(IDS_MESSAGE_SHARED, _username);
+  self.disconnectButton.title = l10n_util::GetNSString(IDS_STOP_SHARING_BUTTON);
 
   // Resize the window dynamically based on the content.
-  CGFloat oldConnectedWidth = NSWidth([_connectedToField bounds]);
-  [_connectedToField sizeToFit];
-  NSRect connectedToFrame = [_connectedToField frame];
+  CGFloat oldConnectedWidth = NSWidth(self.connectedToField.bounds);
+  [self.connectedToField sizeToFit];
+  NSRect connectedToFrame = self.connectedToField.frame;
   CGFloat newConnectedWidth = NSWidth(connectedToFrame);
 
   // Set a max width for the connected to text field.
   if (newConnectedWidth > kMaximumConnectedNameWidthInPixels) {
     newConnectedWidth = kMaximumConnectedNameWidthInPixels;
     connectedToFrame.size.width = newConnectedWidth;
-    [_connectedToField setFrame:connectedToFrame];
+    self.connectedToField.frame = connectedToFrame;
   }
 
-  CGFloat oldDisconnectWidth = NSWidth([_disconnectButton bounds]);
-  [_disconnectButton sizeToFit];
-  NSRect disconnectFrame = [_disconnectButton frame];
+  CGFloat oldDisconnectWidth = NSWidth(self.disconnectButton.bounds);
+  [self.disconnectButton sizeToFit];
+  NSRect disconnectFrame = self.disconnectButton.frame;
   CGFloat newDisconnectWidth = NSWidth(disconnectFrame);
 
   // Move the disconnect button appropriately.
   disconnectFrame.origin.x += newConnectedWidth - oldConnectedWidth;
   disconnectFrame.origin.y =
       (NSHeight(self.window.contentView.frame) - NSHeight(disconnectFrame)) / 2;
-  [_disconnectButton setFrame:disconnectFrame];
+  self.disconnectButton.frame = disconnectFrame;
 
   // Then resize the window appropriately
-  NSWindow *window = [self window];
-  NSRect windowFrame = [window frame];
+  NSRect windowFrame = self.window.frame;
   windowFrame.size.width += (newConnectedWidth - oldConnectedWidth +
                              newDisconnectWidth - oldDisconnectWidth);
-  [window setFrame:windowFrame display:NO];
+  [self.window setFrame:windowFrame display:NO];
 
   if ([self isRToL]) {
     // Handle right to left case
@@ -206,16 +203,16 @@
         = NSMinX(disconnectFrame) - NSMaxX(connectedToFrame);
     disconnectFrame.origin.x = buttonInset;
     connectedToFrame.origin.x = NSMaxX(disconnectFrame) + buttonTextSpacing;
-    [_connectedToField setFrame:connectedToFrame];
-    [_disconnectButton setFrame:disconnectFrame];
+    self.connectedToField.frame = connectedToFrame;
+    self.disconnectButton.frame = disconnectFrame;
   }
 
   // Center the window at the bottom of the screen, above the dock (if present).
-  NSRect desktopRect = [[NSScreen mainScreen] visibleFrame];
-  NSRect windowRect = [[self window] frame];
+  NSRect desktopRect = NSScreen.mainScreen.visibleFrame;
+  NSRect windowRect = self.window.frame;
   CGFloat x = (NSWidth(desktopRect) - NSWidth(windowRect)) / 2;
   CGFloat y = NSMinY(desktopRect);
-  [[self window] setFrameOrigin:NSMakePoint(x, y)];
+  [self.window setFrameOrigin:NSMakePoint(x, y)];
 }
 
 - (void)windowWillClose:(NSNotification*)notification {
diff --git a/remoting/protocol/webrtc_video_encoder_factory.cc b/remoting/protocol/webrtc_video_encoder_factory.cc
index e27f10a..e7a032fe 100644
--- a/remoting/protocol/webrtc_video_encoder_factory.cc
+++ b/remoting/protocol/webrtc_video_encoder_factory.cc
@@ -9,6 +9,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "remoting/protocol/video_channel_state_observer.h"
 #include "remoting/protocol/webrtc_video_encoder_wrapper.h"
+#include "third_party/webrtc/api/video_codecs/av1_profile.h"
 #include "third_party/webrtc/api/video_codecs/sdp_video_format.h"
 #include "third_party/webrtc/api/video_codecs/video_codec.h"
 #include "third_party/webrtc/api/video_codecs/vp9_profile.h"
@@ -35,6 +36,10 @@
   }
 #endif
   formats_.emplace_back(webrtc::SdpVideoFormat("AV1"));
+  formats_.emplace_back(webrtc::SdpVideoFormat(
+      "AV1",
+      {{webrtc::kAV1FmtpProfile,
+        webrtc::AV1ProfileToString(webrtc::AV1Profile::kProfile1).data()}}));
 }
 
 WebrtcVideoEncoderFactory::~WebrtcVideoEncoderFactory() = default;
diff --git a/remoting/protocol/webrtc_video_encoder_wrapper.cc b/remoting/protocol/webrtc_video_encoder_wrapper.cc
index e50cd14..af0f984 100644
--- a/remoting/protocol/webrtc_video_encoder_wrapper.cc
+++ b/remoting/protocol/webrtc_video_encoder_wrapper.cc
@@ -25,6 +25,7 @@
 #include "remoting/codec/webrtc_video_encoder_vpx.h"
 #include "remoting/protocol/video_channel_state_observer.h"
 #include "remoting/protocol/webrtc_video_frame_adapter.h"
+#include "third_party/webrtc/api/video_codecs/av1_profile.h"
 #include "third_party/webrtc/api/video_codecs/sdp_video_format.h"
 #include "third_party/webrtc/api/video_codecs/vp9_profile.h"
 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
@@ -143,6 +144,17 @@
       }
       break;
     }
+    case webrtc::kVideoCodecAV1: {
+      absl::optional<webrtc::AV1Profile> profile =
+          webrtc::ParseSdpForAV1Profile(format.parameters);
+      bool lossless_color = profile.has_value() &&
+                            profile.value() == webrtc::AV1Profile::kProfile1;
+      VLOG(0) << "Creating AV1 encoder, lossless_color="
+              << (lossless_color ? "true" : "false");
+      encoder_ = std::make_unique<WebrtcVideoEncoderAV1>();
+      encoder_->SetLosslessColor(lossless_color);
+      break;
+    }
     case webrtc::kVideoCodecH264:
 #if defined(USE_H264_ENCODER)
       VLOG(0) << "Creating H264 encoder.";
@@ -151,10 +163,6 @@
       NOTIMPLEMENTED();
 #endif
       break;
-    case webrtc::kVideoCodecAV1:
-      VLOG(0) << "Creating AV1 encoder.";
-      encoder_ = std::make_unique<WebrtcVideoEncoderAV1>();
-      break;
     default:
       LOG(FATAL) << "Unknown codec type: " << codec_type_;
   }
diff --git a/services/device/compute_pressure/cpu_probe_win.cc b/services/device/compute_pressure/cpu_probe_win.cc
index d014065..b6937e8 100644
--- a/services/device/compute_pressure/cpu_probe_win.cc
+++ b/services/device/compute_pressure/cpu_probe_win.cc
@@ -25,13 +25,8 @@
 void CpuProbeWin::Update() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  const auto& result = GetPdhData();
-  if (result.has_value()) {
-    last_sample_ = std::move(result.value());
-  } else {
-    last_sample_ = kUnsupportedValue;
-    LOG(ERROR) << result.error();
-  }
+  auto result = GetPdhData();
+  last_sample_ = result ? *result : kUnsupportedValue;
 }
 
 PressureSample CpuProbeWin::LastSample() {
@@ -40,7 +35,7 @@
   return last_sample_;
 }
 
-base::expected<PressureSample, std::string> CpuProbeWin::GetPdhData() {
+absl::optional<PressureSample> CpuProbeWin::GetPdhData() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   PDH_STATUS pdh_status;
@@ -48,26 +43,34 @@
   if (!cpu_query_.is_valid()) {
     cpu_query_ = ScopedPdhQuery::Create();
     if (!cpu_query_.is_valid())
-      return base::unexpected("PdhOpenQuery failed.");
+      return absl::nullopt;
 
     pdh_status = PdhAddEnglishCounter(cpu_query_.get(),
                                       L"\\Processor(_Total)\\% Processor Time",
                                       NULL, &cpu_percent_utilization_);
     if (pdh_status != ERROR_SUCCESS) {
       cpu_query_.reset();
-      return base::unexpected("PdhAddEnglishCounter failed.");
+      LOG(ERROR) << "PdhAddEnglishCounter failed: "
+                 << logging::SystemErrorCodeToString(pdh_status);
+      return absl::nullopt;
     }
   }
 
   pdh_status = PdhCollectQueryData(cpu_query_.get());
-  if (pdh_status != ERROR_SUCCESS)
-    return base::unexpected("PdhCollectQueryData failed.");
+  if (pdh_status != ERROR_SUCCESS) {
+    LOG(ERROR) << "PdhCollectQueryData failed: "
+               << logging::SystemErrorCodeToString(pdh_status);
+    return absl::nullopt;
+  }
 
   PDH_FMT_COUNTERVALUE counter_value;
   pdh_status = PdhGetFormattedCounterValue(
       cpu_percent_utilization_, PDH_FMT_DOUBLE, NULL, &counter_value);
-  if (pdh_status != ERROR_SUCCESS)
-    return base::unexpected("PdhGetFormattedCounterValue failed.");
+  if (pdh_status != ERROR_SUCCESS) {
+    LOG(ERROR) << "PdhGetFormattedCounterValue failed: "
+               << logging::SystemErrorCodeToString(pdh_status);
+    return absl::nullopt;
+  }
 
   return PressureSample{counter_value.doubleValue / 100.0};
 }
diff --git a/services/device/compute_pressure/cpu_probe_win.h b/services/device/compute_pressure/cpu_probe_win.h
index 148f5e4..004cf37 100644
--- a/services/device/compute_pressure/cpu_probe_win.h
+++ b/services/device/compute_pressure/cpu_probe_win.h
@@ -6,14 +6,13 @@
 #define SERVICES_DEVICE_COMPUTE_PRESSURE_CPU_PROBE_WIN_H_
 
 #include <memory>
-#include <string>
 
 #include "base/sequence_checker.h"
 #include "base/thread_annotations.h"
-#include "base/types/expected.h"
 #include "services/device/compute_pressure/cpu_probe.h"
 #include "services/device/compute_pressure/pressure_sample.h"
 #include "services/device/compute_pressure/scoped_pdh_query.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace device {
 
@@ -34,7 +33,7 @@
  private:
   CpuProbeWin();
 
-  base::expected<PressureSample, std::string> GetPdhData();
+  absl::optional<PressureSample> GetPdhData();
 
   SEQUENCE_CHECKER(sequence_checker_);
 
diff --git a/services/device/compute_pressure/scoped_pdh_query.cc b/services/device/compute_pressure/scoped_pdh_query.cc
index 79bef64..1f80ce0 100644
--- a/services/device/compute_pressure/scoped_pdh_query.cc
+++ b/services/device/compute_pressure/scoped_pdh_query.cc
@@ -4,6 +4,8 @@
 
 #include "services/device/compute_pressure/scoped_pdh_query.h"
 
+#include "base/logging.h"
+
 namespace device {
 
 ScopedPdhQuery::ScopedPdhQuery() = default;
@@ -15,9 +17,13 @@
 ScopedPdhQuery ScopedPdhQuery::Create() {
   PDH_HQUERY pdh_query;
   PDH_STATUS pdh_status = PdhOpenQuery(NULL, NULL, &pdh_query);
-  if (pdh_status == ERROR_SUCCESS)
+  if (pdh_status == ERROR_SUCCESS) {
     return ScopedPdhQuery(std::move(pdh_query));
-  return ScopedPdhQuery();
+  } else {
+    LOG(ERROR) << "PdhOpenQuery failed: "
+               << logging::SystemErrorCodeToString(pdh_status);
+    return ScopedPdhQuery();
+  }
 }
 
 }  // namespace device
diff --git a/services/device/serial/bluetooth_serial_device_enumerator.cc b/services/device/serial/bluetooth_serial_device_enumerator.cc
index 195d67d..fb28756 100644
--- a/services/device/serial/bluetooth_serial_device_enumerator.cc
+++ b/services/device/serial/bluetooth_serial_device_enumerator.cc
@@ -6,6 +6,7 @@
 
 #include "base/command_line.h"
 #include "base/containers/contains.h"
+#include "base/scoped_observation.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/unguessable_token.h"
@@ -35,6 +36,16 @@
   // The enumerator that owns this instance.
   base::WeakPtr<BluetoothSerialDeviceEnumerator> enumerator_;
   scoped_refptr<base::SequencedTaskRunner> enumerator_runner_;
+
+  // scoped_refptr<BluetoothAdapter> is required to ensure that this object
+  // actually has a reference to the BluetoothAdapter when the call to
+  // RemoveObserver() happens.
+  scoped_refptr<BluetoothAdapter> adapter_;
+
+  // |observation_| needs to be after |adapter_| to ensure it is reset before
+  // |adapter_|'s reset during destruction.
+  base::ScopedObservation<BluetoothAdapter, BluetoothAdapter::Observer>
+      observation_{this};
   SEQUENCE_CHECKER(sequence_checker_);
   base::WeakPtrFactory<AdapterHelper> weak_ptr_factory_{this};
 };
@@ -53,16 +64,17 @@
     scoped_refptr<device::BluetoothAdapter> adapter) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(adapter);
+  adapter_ = std::move(adapter);
 
-  BluetoothAdapter::DeviceList devices = adapter->GetDevices();
+  BluetoothAdapter::DeviceList devices = adapter_->GetDevices();
   for (auto* device : devices) {
-    DeviceAdded(adapter.get(), device);
+    DeviceAdded(adapter_.get(), device);
   }
-  adapter->AddObserver(this);
+  observation_.Observe(adapter_.get());
   enumerator_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&BluetoothSerialDeviceEnumerator::SetClassicAdapter,
-                     enumerator_, std::move(adapter)));
+                     enumerator_, adapter_));
 }
 
 void BluetoothSerialDeviceEnumerator::AdapterHelper::DeviceAdded(
diff --git a/services/device/serial/bluetooth_serial_device_enumerator_unittests.cc b/services/device/serial/bluetooth_serial_device_enumerator_unittests.cc
index d0a1fb7b..13ac3d6 100644
--- a/services/device/serial/bluetooth_serial_device_enumerator_unittests.cc
+++ b/services/device/serial/bluetooth_serial_device_enumerator_unittests.cc
@@ -198,4 +198,38 @@
   enumerator.SynchronouslyResetHelperForTesting();
 }
 
+TEST_F(BluetoothSerialDeviceEnumeratorTest,
+       RemoveObserverIsCalledWhenAdapterHelperDestruct) {
+  auto mock_adapter =
+      base::MakeRefCounted<NiceMock<device::MockBluetoothAdapter>>();
+  {
+    base::RunLoop run_loop;
+    mock_adapter->Initialize(run_loop.QuitClosure());
+    run_loop.Run();
+    EXPECT_TRUE(mock_adapter->IsInitialized());
+  }
+
+  device::BluetoothAdapterFactory::Get()->SetAdapterForTesting(mock_adapter);
+  std::unique_ptr<BluetoothSerialDeviceEnumerator> enumerator;
+  {
+    base::RunLoop run_loop;
+    EXPECT_CALL(*mock_adapter, AddObserver)
+        .WillOnce([&run_loop](BluetoothAdapter::Observer* observer) {
+          run_loop.Quit();
+        });
+    enumerator =
+        std::make_unique<BluetoothSerialDeviceEnumerator>(adapter_runner());
+    run_loop.Run();
+  }
+  {
+    base::RunLoop run_loop;
+    EXPECT_CALL(*mock_adapter, RemoveObserver)
+        .WillOnce([&run_loop](BluetoothAdapter::Observer* observer) {
+          run_loop.Quit();
+        });
+    enumerator->SynchronouslyResetHelperForTesting();
+    run_loop.Run();
+  }
+}
+
 }  // namespace device
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index a85cd8b1..2798c2a 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -13148,7 +13148,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M105",
-              "revision": "version:105.0.5195.77"
+              "revision": "version:105.0.5195.99"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -13573,7 +13573,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M105",
-              "revision": "version:105.0.5195.77"
+              "revision": "version:105.0.5195.99"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index f7c32380..055fbde2 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -45950,7 +45950,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M105",
-              "revision": "version:105.0.5195.77"
+              "revision": "version:105.0.5195.99"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -46375,7 +46375,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M105",
-              "revision": "version:105.0.5195.77"
+              "revision": "version:105.0.5195.99"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -46804,7 +46804,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M105",
-              "revision": "version:105.0.5195.77"
+              "revision": "version:105.0.5195.99"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -47229,7 +47229,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M105",
-              "revision": "version:105.0.5195.77"
+              "revision": "version:105.0.5195.99"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -47726,7 +47726,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M105",
-              "revision": "version:105.0.5195.77"
+              "revision": "version:105.0.5195.99"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -48151,7 +48151,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M105",
-              "revision": "version:105.0.5195.77"
+              "revision": "version:105.0.5195.99"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -48648,7 +48648,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M105",
-              "revision": "version:105.0.5195.77"
+              "revision": "version:105.0.5195.99"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -49073,7 +49073,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M105",
-              "revision": "version:105.0.5195.77"
+              "revision": "version:105.0.5195.99"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 4e94a0f..e29e6e2 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -481,7 +481,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M105',
-          'revision': 'version:105.0.5195.77',
+          'revision': 'version:105.0.5195.99',
         }
       ],
     },
@@ -601,7 +601,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M105',
-          'revision': 'version:105.0.5195.77',
+          'revision': 'version:105.0.5195.99',
         }
       ],
     },
@@ -721,7 +721,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M105',
-          'revision': 'version:105.0.5195.77',
+          'revision': 'version:105.0.5195.99',
         }
       ],
     },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 7d2b764..a8b09ad 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -3333,20 +3333,35 @@
                     "enable_features": [
                         "CriticalPersistedTabData"
                     ]
-                }
-            ]
-        }
-    ],
-    "CrosCellularUseAttachApn": [
-        {
-            "platforms": [
-                "chromeos"
-            ],
-            "experiments": [
+                },
                 {
-                    "name": "Enabled_20210713",
+                    "name": "Enabled_Save_On_Deferred_Startup",
+                    "params": {
+                        "critical_persisted_tab_data_save_only": "false",
+                        "delay_saves_until_deferred_startup": "true"
+                    },
                     "enable_features": [
-                        "CellularUseAttachApn"
+                        "CriticalPersistedTabData"
+                    ]
+                },
+                {
+                    "name": "Enabled_Save_And_Restore",
+                    "params": {
+                        "critical_persisted_tab_data_save_only": "false",
+                        "delay_saves_until_deferred_startup": "false"
+                    },
+                    "enable_features": [
+                        "CriticalPersistedTabData"
+                    ]
+                },
+                {
+                    "name": "Enabled_Save_Only",
+                    "params": {
+                        "critical_persisted_tab_data_save_only": "true",
+                        "delay_saves_until_deferred_startup": "false"
+                    },
+                    "enable_features": [
+                        "CriticalPersistedTabData"
                     ]
                 }
             ]
@@ -3612,10 +3627,7 @@
                     "name": "Enabled",
                     "params": {
                         "AutocompleteStabilityAsyncProvidersFirst": "true",
-                        "AutocompleteStabilityDontCopyDoneProviders": "true",
-                        "AutocompleteStabilityPreserveDefaultAfterTransfer": "true",
-                        "AutocompleteStabilityPreserveDefaultForAsyncUpdates": "false",
-                        "AutocompleteStabilityPreserveDefaultForSyncUpdates": "true"
+                        "AutocompleteStabilityDontCopyDoneProviders": "true"
                     },
                     "enable_features": [
                         "OmniboxAutocompleteStability",
@@ -3626,6 +3638,32 @@
             ]
         }
     ],
+    "DesktopOmniboxPostAutocompletionPreserveDefault": [
+        {
+            "platforms": [
+                "android",
+                "chromeos_lacros",
+                "chromeos",
+                "ios",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "params": {
+                        "AutocompleteStabilityPreserveDefaultAfterTransfer": "true",
+                        "AutocompleteStabilityPreserveDefaultForAsyncUpdates": "true",
+                        "AutocompleteStabilityPreserveDefaultForSyncUpdatesMinInputLength": "3"
+                    },
+                    "enable_features": [
+                        "OmniboxPreserveDefault"
+                    ]
+                }
+            ]
+        }
+    ],
     "DesktopOmniboxRichAutocompletion": [
         {
             "platforms": [
@@ -7564,6 +7602,27 @@
             ]
         }
     ],
+    "PretokenizeCSS": [
+        {
+            "platforms": [
+                "android",
+                "android_webview",
+                "chromeos",
+                "chromeos_lacros",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "PretokenizeCSS"
+                    ]
+                }
+            ]
+        }
+    ],
     "PriceDropNtpIPH": [
         {
             "platforms": [
@@ -11294,5 +11353,20 @@
                 }
             ]
         }
+    ],
+    "ZeroCopyTabCaptureExperiment": [
+        {
+            "platforms": [
+                "mac"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "ZeroCopyTabCapture"
+                    ]
+                }
+            ]
+        }
     ]
 }
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 8fd468b..2901c79 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -1648,5 +1648,8 @@
 const base::Feature kWebRtcMetronome{"WebRtcMetronome",
                                      base::FEATURE_ENABLED_BY_DEFAULT};
 
+const base::Feature kSyncAccessHandleAllSyncSurface{
+    "SyncAccessHandleAllSyncSurface", base::FEATURE_DISABLED_BY_DEFAULT};
+
 }  // namespace features
 }  // namespace blink
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index daab1c8..5b3939b 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -904,6 +904,9 @@
 
 BLINK_COMMON_EXPORT extern const base::Feature kWebRtcMetronome;
 
+// If enabled, all of FileSystemAccessSyncAccessHandle methods are synchronous.
+BLINK_COMMON_EXPORT extern const base::Feature kSyncAccessHandleAllSyncSurface;
+
 }  // namespace features
 }  // namespace blink
 
diff --git a/third_party/blink/public/mojom/frame/viewport_intersection_state.mojom b/third_party/blink/public/mojom/frame/viewport_intersection_state.mojom
index 069ed37c..b4f5dc1 100644
--- a/third_party/blink/public/mojom/frame/viewport_intersection_state.mojom
+++ b/third_party/blink/public/mojom/frame/viewport_intersection_state.mojom
@@ -41,11 +41,13 @@
   // Occlusion state, as described above.
   FrameOcclusionState occlusion_state = FrameOcclusionState.kUnknown;
 
-  // Main frame's size.
-  gfx.mojom.Size main_frame_viewport_size;
+  // Outermost main frame's size. Is not affected by
+  // pinch-zoom/visual-viewport.
+  gfx.mojom.Size outermost_main_frame_size;
 
-  // Main frame's scrolling position.
-  gfx.mojom.Point main_frame_scroll_position;
+  // Outermost main frame's scroll position. Is not affected by
+  // pinch-zoom/visual-viewport.
+  gfx.mojom.Point outermost_main_frame_scroll_position;
 
   // Child frame's transform to the coordinate system of the main frame.
   gfx.mojom.Transform main_frame_transform;
diff --git a/third_party/blink/public/mojom/speculation_rules/speculation_rules.mojom b/third_party/blink/public/mojom/speculation_rules/speculation_rules.mojom
index b719e57..9fc848d 100644
--- a/third_party/blink/public/mojom/speculation_rules/speculation_rules.mojom
+++ b/third_party/blink/public/mojom/speculation_rules/speculation_rules.mojom
@@ -31,8 +31,17 @@
   kPrerender,
 };
 
+// The target hint that is proposed.
+enum SpeculationTargetHint {
+  kNoHint,
+  kBlank,
+  kSelf,
+};
+
 // A single candidate: a URL, an action, a referrer, and any associated
 // metadata that might be needed to make a decision.
+// https://wicg.github.io/nav-speculation/speculation-rules.html#prefetch-candidate
+// https://wicg.github.io/nav-speculation/speculation-rules.html#prerender-candidate
 struct SpeculationCandidate {
   // The URL which is eligible for some action.
   url.mojom.Url url;
@@ -47,4 +56,8 @@
   // made in a manner which anonymizes the client IP. If this is not possible,
   // this candidate must be discarded.
   bool requires_anonymous_client_ip_when_cross_origin = false;
+
+  // The hint to be used to decide a target browsing context where preloaded
+  // resource will be used. This is kNoHint for actions other than `kPrerender`.
+  SpeculationTargetHint target_browsing_context_name_hint = kNoHint;
 };
diff --git a/third_party/blink/renderer/core/frame/frame.h b/third_party/blink/renderer/core/frame/frame.h
index 8e9d56f..0feb433d 100644
--- a/third_party/blink/renderer/core/frame/frame.h
+++ b/third_party/blink/renderer/core/frame/frame.h
@@ -354,8 +354,8 @@
   // Called when the focus controller changes the focus to this frame.
   virtual void DidFocus() = 0;
 
-  virtual gfx::Size GetMainFrameViewportSize() const = 0;
-  virtual gfx::Point GetMainFrameScrollPosition() const = 0;
+  virtual gfx::Size GetOutermostMainFrameSize() const = 0;
+  virtual gfx::Point GetOutermostMainFrameScrollPosition() const = 0;
 
   // Sets this frame's opener to another frame, or disowned the opener
   // if opener is null. See http://html.spec.whatwg.org/#dom-opener.
diff --git a/third_party/blink/renderer/core/frame/frame_view.cc b/third_party/blink/renderer/core/frame/frame_view.cc
index 5e8f4bb..2474ee6 100644
--- a/third_party/blink/renderer/core/frame/frame_view.cc
+++ b/third_party/blink/renderer/core/frame/frame_view.cc
@@ -195,7 +195,7 @@
     // TODO: Should this be IsOutermostMainFrame()?
     if (owner_document.GetFrame()->LocalFrameRoot().IsMainFrame()) {
       child_frame_to_root_frame.Move(PhysicalOffset::FromPointFRound(
-          gfx::PointF(frame.GetMainFrameScrollPosition())));
+          gfx::PointF(frame.GetOutermostMainFrameScrollPosition())));
     }
     if (owner_layout_object) {
       owner_layout_object->MapAncestorToLocal(
@@ -221,8 +221,8 @@
 
   SetViewportIntersection(mojom::blink::ViewportIntersectionState(
       viewport_intersection, mainframe_intersection, gfx::Rect(),
-      occlusion_state, frame.GetMainFrameViewportSize(),
-      frame.GetMainFrameScrollPosition(), main_frame_gfx_transform));
+      occlusion_state, frame.GetOutermostMainFrameSize(),
+      frame.GetOutermostMainFrameScrollPosition(), main_frame_gfx_transform));
 
   UpdateFrameVisibility(!viewport_intersection.IsEmpty());
 
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index fd2b76e..b19001d 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -2131,22 +2131,20 @@
   }
 }
 
-gfx::Size LocalFrame::GetMainFrameViewportSize() const {
+gfx::Size LocalFrame::GetOutermostMainFrameSize() const {
   LocalFrame& local_root = LocalFrameRoot();
-  return local_root.IsMainFrame()
-             ? local_root.View()
-                   ->GetScrollableArea()
-                   ->VisibleContentRect()
-                   .size()
-             : local_root.intersection_state_.main_frame_viewport_size;
+  return local_root.IsOutermostMainFrame()
+             ? local_root.View()->LayoutViewport()->VisibleContentRect().size()
+             : local_root.intersection_state_.outermost_main_frame_size;
 }
 
-gfx::Point LocalFrame::GetMainFrameScrollPosition() const {
+gfx::Point LocalFrame::GetOutermostMainFrameScrollPosition() const {
   LocalFrame& local_root = LocalFrameRoot();
-  return local_root.IsMainFrame()
+  return local_root.IsOutermostMainFrame()
              ? gfx::ToFlooredPoint(
                    local_root.View()->LayoutViewport()->ScrollPosition())
-             : local_root.intersection_state_.main_frame_scroll_position;
+             : local_root.intersection_state_
+                   .outermost_main_frame_scroll_position;
 }
 
 void LocalFrame::SetOpener(Frame* opener_frame) {
diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h
index e1d6f20..57bf12214 100644
--- a/third_party/blink/renderer/core/frame/local_frame.h
+++ b/third_party/blink/renderer/core/frame/local_frame.h
@@ -497,8 +497,8 @@
   void SetViewportIntersectionFromParent(
       const mojom::blink::ViewportIntersectionState& intersection_state);
 
-  gfx::Size GetMainFrameViewportSize() const override;
-  gfx::Point GetMainFrameScrollPosition() const override;
+  gfx::Size GetOutermostMainFrameSize() const override;
+  gfx::Point GetOutermostMainFrameScrollPosition() const override;
 
   void SetOpener(Frame* opener) override;
 
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index 5906f7f5a..252f70a 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -795,6 +795,7 @@
       }
       for (auto& root : layout_subtree_root_list_.Ordered()) {
         bool should_rebuild_fragments = false;
+        LayoutObject& root_layout_object = *root;
         LayoutBlock* cb = root->ContainingNGBlock();
         if (cb) {
           auto it = fragment_tree_spines.find(cb);
@@ -814,7 +815,7 @@
         // We need to ensure that we mark up all layoutObjects up to the
         // LayoutView for paint invalidation. This simplifies our code as we
         // just always do a full tree walk.
-        if (LayoutObject* container = root->Container())
+        if (LayoutObject* container = root_layout_object.Container())
           container->SetShouldCheckForPaintInvalidation();
       }
       layout_subtree_root_list_.Clear();
@@ -1065,8 +1066,8 @@
         To<LayoutBox>(layout_object)->PhysicalLayoutOverflowRect().size));
     GetFrame().Client()->OnMainFrameIntersectionChanged(main_frame_dimensions);
     GetFrame().Client()->OnMainFrameViewportRectangleChanged(
-        gfx::Rect(frame_->GetMainFrameScrollPosition(),
-                  frame_->GetMainFrameViewportSize()));
+        gfx::Rect(frame_->GetOutermostMainFrameScrollPosition(),
+                  frame_->GetOutermostMainFrameSize()));
   }
 
   TRACE_EVENT0("blink,benchmark",
diff --git a/third_party/blink/renderer/core/frame/overlay_interstitial_ad_detector.cc b/third_party/blink/renderer/core/frame/overlay_interstitial_ad_detector.cc
index dd87e1b..f66ec91 100644
--- a/third_party/blink/renderer/core/frame/overlay_interstitial_ad_detector.cc
+++ b/third_party/blink/renderer/core/frame/overlay_interstitial_ad_detector.cc
@@ -88,8 +88,10 @@
   started_detection_ = true;
   last_detection_time_ = current_time;
 
-  gfx::Size outermost_main_frame_size =
-      outermost_main_frame->GetMainFrameViewportSize();
+  gfx::Size outermost_main_frame_size = outermost_main_frame->View()
+                                            ->LayoutViewport()
+                                            ->VisibleContentRect()
+                                            .size();
 
   if (outermost_main_frame_size != last_detection_outermost_main_frame_size_) {
     // Reset the candidate when the the viewport size has changed. Changing
@@ -148,7 +150,7 @@
     // If the main frame scrolling position hasn't changed since the candidate's
     // appearance, we consider it to be a overlay interstitial; otherwise, we
     // skip that candidate because it could be a parallax/scroller ad.
-    if (outermost_main_frame->GetMainFrameScrollPosition().y() ==
+    if (outermost_main_frame->GetOutermostMainFrameScrollPosition().y() ==
         candidate_start_outermost_main_frame_scroll_position_) {
       OnPopupDetected(outermost_main_frame, candidate_is_ad_);
     }
@@ -205,7 +207,7 @@
     candidate_id_ = element_id;
     candidate_is_ad_ = is_ad;
     candidate_start_outermost_main_frame_scroll_position_ =
-        outermost_main_frame->GetMainFrameScrollPosition().y();
+        outermost_main_frame->GetOutermostMainFrameScrollPosition().y();
   } else {
     last_unqualified_element_id_ = element_id;
   }
diff --git a/third_party/blink/renderer/core/frame/remote_frame.cc b/third_party/blink/renderer/core/frame/remote_frame.cc
index 32d0404..b22d6eb 100644
--- a/third_party/blink/renderer/core/frame/remote_frame.cc
+++ b/third_party/blink/renderer/core/frame/remote_frame.cc
@@ -780,18 +780,18 @@
   }
 }
 
-gfx::Size RemoteFrame::GetMainFrameViewportSize() const {
+gfx::Size RemoteFrame::GetOutermostMainFrameSize() const {
   HTMLFrameOwnerElement* owner = DeprecatedLocalOwner();
   DCHECK(owner);
   DCHECK(owner->GetDocument().GetFrame());
-  return owner->GetDocument().GetFrame()->GetMainFrameViewportSize();
+  return owner->GetDocument().GetFrame()->GetOutermostMainFrameSize();
 }
 
-gfx::Point RemoteFrame::GetMainFrameScrollPosition() const {
+gfx::Point RemoteFrame::GetOutermostMainFrameScrollPosition() const {
   HTMLFrameOwnerElement* owner = DeprecatedLocalOwner();
   DCHECK(owner);
   DCHECK(owner->GetDocument().GetFrame());
-  return owner->GetDocument().GetFrame()->GetMainFrameScrollPosition();
+  return owner->GetDocument().GetFrame()->GetOutermostMainFrameScrollPosition();
 }
 
 void RemoteFrame::SetOpener(Frame* opener_frame) {
diff --git a/third_party/blink/renderer/core/frame/remote_frame.h b/third_party/blink/renderer/core/frame/remote_frame.h
index 23560ddc..23e1cf96 100644
--- a/third_party/blink/renderer/core/frame/remote_frame.h
+++ b/third_party/blink/renderer/core/frame/remote_frame.h
@@ -210,8 +210,8 @@
       override;
 
   // Called only when this frame has a local frame owner.
-  gfx::Size GetMainFrameViewportSize() const override;
-  gfx::Point GetMainFrameScrollPosition() const override;
+  gfx::Size GetOutermostMainFrameSize() const override;
+  gfx::Point GetOutermostMainFrameScrollPosition() const override;
 
   void SetOpener(Frame* opener) override;
 
diff --git a/third_party/blink/renderer/core/frame/sticky_ad_detector.cc b/third_party/blink/renderer/core/frame/sticky_ad_detector.cc
index 1b83d9b6..f417fcc3 100644
--- a/third_party/blink/renderer/core/frame/sticky_ad_detector.cc
+++ b/third_party/blink/renderer/core/frame/sticky_ad_detector.cc
@@ -77,8 +77,10 @@
 
   TRACE_EVENT0("blink,benchmark", "StickyAdDetector::MaybeFireDetection");
 
-  gfx::Size outermost_main_frame_size =
-      outermost_main_frame->GetMainFrameViewportSize();
+  gfx::Size outermost_main_frame_size = outermost_main_frame->View()
+                                            ->LayoutViewport()
+                                            ->VisibleContentRect()
+                                            .size();
 
   // Hit test the bottom center of the viewport.
   HitTestLocation location(
@@ -101,8 +103,9 @@
     // If the main frame scrolling position has changed by a distance greater
     // than the height of the candidate, and the candidate is still at the
     // bottom center, then we record the use counter.
-    if (std::abs(candidate_start_outermost_main_frame_scroll_position_ -
-                 outermost_main_frame->GetMainFrameScrollPosition().y()) >
+    if (std::abs(
+            candidate_start_outermost_main_frame_scroll_position_ -
+            outermost_main_frame->GetOutermostMainFrameScrollPosition().y()) >
         candidate_height_) {
       OnLargeStickyAdDetected(outermost_main_frame);
     }
@@ -133,7 +136,7 @@
     candidate_id_ = element_id;
     candidate_height_ = overlay_rect.size().height();
     candidate_start_outermost_main_frame_scroll_position_ =
-        outermost_main_frame->GetMainFrameScrollPosition().y();
+        outermost_main_frame->GetOutermostMainFrameScrollPosition().y();
   }
 }
 
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc
index 2702890..f04a503a 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc
@@ -140,7 +140,7 @@
   // |OffsetFromOwnerLayoutBox| is not needed here, because the block offset of
   // all fragments are 0 for multicol.
   for (const NGPhysicalBoxFragment& fragment : Base::PhysicalFragments()) {
-    if (const absl::optional<LayoutUnit> offset = fragment.Baseline())
+    if (const absl::optional<LayoutUnit> offset = fragment.FirstBaseline())
       return *offset;
   }
 
@@ -173,7 +173,7 @@
   if (Base::PhysicalFragmentCount()) {
     const NGPhysicalBoxFragment* fragment = Base::GetPhysicalFragment(0);
     DCHECK(fragment);
-    if (absl::optional<LayoutUnit> offset = fragment->Baseline())
+    if (absl::optional<LayoutUnit> offset = fragment->FirstBaseline())
       return *offset;
   }
 
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
index a22a730..74ce92c 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
@@ -453,7 +453,7 @@
   // The baseline of SVG <text> doesn't affect other boxes.
   if (is_layout_root && previous_result && !Base::IsNGSVGText()) {
     if (To<NGPhysicalBoxFragment>(previous_result->PhysicalFragment())
-            .Baseline() != physical_fragment.Baseline()) {
+            .FirstBaseline() != physical_fragment.FirstBaseline()) {
       if (auto* containing_block = Base::ContainingBlock()) {
         containing_block->SetNeedsLayout(
             layout_invalidation_reason::kChildChanged, kMarkContainerChain);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_anchor_query.cc b/third_party/blink/renderer/core/layout/ng/ng_anchor_query.cc
index 7204c52..ebc56c1 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_anchor_query.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_anchor_query.cc
@@ -166,10 +166,17 @@
     WritingDirectionMode writing_direction) {
   // This struct is a variation of |NGAnchorReference|, using the stitched
   // coordinate system for the block-fragmented out-of-flow positioned objects.
-  struct NGStitchedAnchorReference {
-    STACK_ALLOCATED();
+  struct NGStitchedAnchorReference
+      : public GarbageCollected<NGStitchedAnchorReference> {
+    NGStitchedAnchorReference(NGPhysicalAnchorReference* reference,
+                              const LogicalRect& rect,
+                              LogicalOffset first_container_offset,
+                              LayoutUnit first_container_stitched_offset)
+        : reference(reference),
+          rect(rect),
+          first_container_offset(first_container_offset),
+          first_container_stitched_offset(first_container_stitched_offset) {}
 
-   public:
     LogicalRect StitchedRect() const {
       LogicalRect stitched_rect = rect;
       stitched_rect.offset.block_offset += first_container_stitched_offset;
@@ -191,30 +198,46 @@
       rect.Unite(other_rect_in_first_container);
     }
 
+    void Trace(Visitor* visitor) const { visitor->Trace(reference); }
+
     // The |rect| is relative to the first container, so that it can a) unite
     // following fragments in the physical coordinate system, and b) compute the
     // result in the stitched coordinate system.
-    NGPhysicalAnchorReference* reference;
+    Member<NGPhysicalAnchorReference> reference;
     LogicalRect rect;
     LogicalOffset first_container_offset;
     LayoutUnit first_container_stitched_offset;
   };
-  HashMap<AtomicString, NGStitchedAnchorReference> anchors;
-  LayoutUnit stitched_offset;
-  for (const NGLogicalLink& child : children) {
-    if (const NGPhysicalAnchorQuery* child_anchor_query =
-            child->AnchorQuery()) {
+
+  struct NGStitchedAnchorQuery
+      : public GarbageCollected<NGStitchedAnchorQuery> {
+    void AddChild(const NGLogicalLink& child,
+                  const LayoutUnit stitched_offset,
+                  WritingDirectionMode writing_direction) {
+      const NGPhysicalAnchorQuery* anchor_query = child->AnchorQuery();
+      if (!anchor_query)
+        return;
       DCHECK_EQ(child->Style().GetWritingDirection(), writing_direction);
       const WritingModeConverter converter(writing_direction, child->Size());
-      for (const auto& it : *child_anchor_query) {
+      for (const auto& it : *anchor_query) {
         const LogicalRect rect = converter.ToLogical(it.value->rect);
-        const auto result = anchors.insert(
-            it.key, NGStitchedAnchorReference{it.value.Get(), rect,
-                                              child.offset, stitched_offset});
+        const auto result = references.insert(
+            it.key, MakeGarbageCollected<NGStitchedAnchorReference>(
+                        it.value, rect, child.offset, stitched_offset));
         if (!result.is_new_entry)
-          result.stored_value->value.Unite(rect, child.offset);
+          result.stored_value->value->Unite(rect, child.offset);
       }
     }
+
+    void Trace(Visitor* visitor) const { visitor->Trace(references); }
+
+    HeapHashMap<AtomicString, Member<NGStitchedAnchorReference>> references;
+  };
+
+  auto* stitched_anchor_query = MakeGarbageCollected<NGStitchedAnchorQuery>();
+  LayoutUnit stitched_offset;
+  for (const NGLogicalLink& child : children) {
+    stitched_anchor_query->AddChild(child, stitched_offset, writing_direction);
     stitched_offset += child->Size()
                            .ConvertToLogical(writing_direction.GetWritingMode())
                            .block_size;
@@ -222,8 +245,8 @@
 
   // Convert the united anchor references to the stitched coordinate system.
   DCHECK(IsEmpty());
-  for (const auto& it : anchors)
-    Set(it.key, it.value.StitchedAnchorReference());
+  for (const auto& it : stitched_anchor_query->references)
+    Set(it.key, it.value->StitchedAnchorReference());
 }
 
 absl::optional<LayoutUnit> NGLogicalAnchorQuery::EvaluateAnchor(
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
index 1eddf0b..4ea7093 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
@@ -666,7 +666,9 @@
   // to perform a full layout.
   if (old_fragment.Size() != new_fragment.Size())
     return nullptr;
-  if (old_fragment.Baseline() != new_fragment.Baseline())
+  if (old_fragment.FirstBaseline() != new_fragment.FirstBaseline())
+    return nullptr;
+  if (old_fragment.LastBaseline() != new_fragment.LastBaseline())
     return nullptr;
 
 #if DCHECK_IS_ON()
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h
index ebc9ed3..40e1816 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h
@@ -29,7 +29,7 @@
         physical_fragment_.Style().GetWritingMode())
       return absl::nullopt;
 
-    return PhysicalBoxFragment().Baseline();
+    return PhysicalBoxFragment().FirstBaseline();
   }
 
   LayoutUnit FirstBaselineOrSynthesize(FontBaseline baseline_type) const {
@@ -37,7 +37,7 @@
       return *first_baseline;
 
     if (baseline_type == kAlphabeticBaseline)
-      return BlockSize();
+      return writing_direction_.IsFlippedLines() ? LayoutUnit() : BlockSize();
 
     return BlockSize() / 2;
   }
@@ -54,7 +54,7 @@
     if (auto last_baseline = PhysicalBoxFragment().LastBaseline())
       return last_baseline;
 
-    return PhysicalBoxFragment().Baseline();
+    return PhysicalBoxFragment().FirstBaseline();
   }
 
   LayoutUnit BaselineOrSynthesize(FontBaseline baseline_type) const {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
index 7377cf4..d1541bb6 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
@@ -362,8 +362,8 @@
   if (delta == LayoutUnit())
     return;
 
-  if (baseline_)
-    *baseline_ += delta;
+  if (first_baseline_)
+    *first_baseline_ += delta;
   if (last_baseline_)
     *last_baseline_ += delta;
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
index e5d6bc3d..edc1b7e 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
@@ -549,9 +549,9 @@
     custom_layout_data_ = std::move(custom_layout_data);
   }
 
-  // Sets the alignment baseline for this fragment.
-  void SetBaseline(LayoutUnit baseline) { baseline_ = baseline; }
-  absl::optional<LayoutUnit> Baseline() const { return baseline_; }
+  // Sets the first baseline for this fragment.
+  void SetBaseline(LayoutUnit baseline) { first_baseline_ = baseline; }
+  absl::optional<LayoutUnit> Baseline() const { return first_baseline_; }
 
   // Sets the last baseline for this fragment.
   void SetLastBaseline(LayoutUnit baseline) {
@@ -757,7 +757,7 @@
   // The appeal of breaking inside this container.
   NGBreakAppeal break_appeal_ = kBreakAppealPerfect;
 
-  absl::optional<LayoutUnit> baseline_;
+  absl::optional<LayoutUnit> first_baseline_;
   absl::optional<LayoutUnit> last_baseline_;
   LayoutUnit math_italic_correction_;
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc
index ec7aa654..0672310 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc
@@ -412,8 +412,8 @@
 
     const auto& fragment =
         To<NGPhysicalBoxFragment>(result->PhysicalFragment());
-    if (auto baseline = fragment.Baseline())
-      container_builder_.SetBaseline(offset.block_offset + *baseline);
+    if (auto first_baseline = fragment.FirstBaseline())
+      container_builder_.SetBaseline(offset.block_offset + *first_baseline);
     if (auto last_baseline = fragment.LastBaseline())
       container_builder_.SetLastBaseline(offset.block_offset + *last_baseline);
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_layout_utils.cc
index 10f163a..fb5bd74 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_utils.cc
@@ -382,7 +382,7 @@
         // We've been provided a new alignment baseline, just check that it
         // matches the previously generated baseline.
         if (!old_alignment_baseline) {
-          if (*new_alignment_baseline != physical_fragment.Baseline())
+          if (*new_alignment_baseline != physical_fragment.FirstBaseline())
             return NGLayoutCacheStatus::kNeedsLayout;
           break;
         }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
index d859115..931f74c 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
@@ -421,12 +421,12 @@
 
   const bool allow_baseline = !layout_object_->ShouldApplyLayoutContainment() ||
                               layout_object_->IsTableCell();
-  if (allow_baseline && builder->baseline_.has_value()) {
-    has_baseline_ = true;
-    baseline_ = *builder->baseline_;
+  if (allow_baseline && builder->first_baseline_.has_value()) {
+    has_first_baseline_ = true;
+    first_baseline_ = *builder->first_baseline_;
   } else {
-    has_baseline_ = false;
-    baseline_ = LayoutUnit::Min();
+    has_first_baseline_ = false;
+    first_baseline_ = LayoutUnit::Min();
   }
   if (allow_baseline && builder->last_baseline_.has_value()) {
     has_last_baseline_ = true;
@@ -466,7 +466,7 @@
       has_descendants_for_table_part_(other.has_descendants_for_table_part_),
       is_fragmentation_context_root_(other.is_fragmentation_context_root_),
       const_num_children_(other.const_num_children_),
-      baseline_(other.baseline_),
+      first_baseline_(other.first_baseline_),
       last_baseline_(other.last_baseline_),
       ink_overflow_(other.InkOverflowType(), other.ink_overflow_) {
   // Shallow-clone the children.
@@ -1757,7 +1757,7 @@
 
   // Legacy layout can (incorrectly) shift baseline position(s) during
   // "simplified" layout.
-  DCHECK(IsLegacyLayoutRoot() || Baseline() == other.Baseline());
+  DCHECK(IsLegacyLayoutRoot() || FirstBaseline() == other.FirstBaseline());
   if (check_same_block_size) {
     DCHECK(IsLegacyLayoutRoot() || LastBaseline() == other.LastBaseline());
   } else {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
index acdb22d..f166aebd 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
@@ -133,9 +133,9 @@
     return const_has_fragment_items_ ? ComputeItemsAddress() : nullptr;
   }
 
-  absl::optional<LayoutUnit> Baseline() const {
-    if (has_baseline_)
-      return baseline_;
+  absl::optional<LayoutUnit> FirstBaseline() const {
+    if (has_first_baseline_)
+      return first_baseline_;
     return absl::nullopt;
   }
 
@@ -617,7 +617,7 @@
 
   const wtf_size_t const_num_children_;
 
-  LayoutUnit baseline_;
+  LayoutUnit first_baseline_;
   LayoutUnit last_baseline_;
   NGInkOverflow ink_overflow_;
   NGLink children_[];
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
index 9959ee20..78e4970 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
@@ -356,7 +356,7 @@
       is_legacy_layout_root_(false),
       is_painted_atomically_(false),
       has_collapsed_borders_(builder->has_collapsed_borders_),
-      has_baseline_(false),
+      has_first_baseline_(false),
       has_last_baseline_(false),
       has_fragmented_out_of_flow_data_(
           !builder->oof_positioned_fragmentainer_descendants_.IsEmpty() ||
@@ -445,7 +445,7 @@
       is_legacy_layout_root_(other.is_legacy_layout_root_),
       is_painted_atomically_(other.is_painted_atomically_),
       has_collapsed_borders_(other.has_collapsed_borders_),
-      has_baseline_(other.has_baseline_),
+      has_first_baseline_(other.has_first_baseline_),
       has_last_baseline_(other.has_last_baseline_),
       has_fragmented_out_of_flow_data_(other.has_fragmented_out_of_flow_data_),
       has_out_of_flow_fragment_child_(other.has_out_of_flow_fragment_child_),
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
index 6f7ddc80..42d48d6 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
@@ -725,7 +725,7 @@
   unsigned is_legacy_layout_root_ : 1;
   unsigned is_painted_atomically_ : 1;
   unsigned has_collapsed_borders_ : 1;
-  unsigned has_baseline_ : 1;
+  unsigned has_first_baseline_ : 1;
   unsigned has_last_baseline_ : 1;
   const unsigned has_fragmented_out_of_flow_data_ : 1;
   const unsigned has_out_of_flow_fragment_child_ : 1;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc
index c5ab6353..af96f893 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc
@@ -156,8 +156,8 @@
   if (physical_fragment.IsHiddenForPaint())
     container_builder_.SetIsHiddenForPaint(true);
 
-  if (auto baseline = physical_fragment.Baseline())
-    container_builder_.SetBaseline(*baseline);
+  if (auto first_baseline = physical_fragment.FirstBaseline())
+    container_builder_.SetBaseline(*first_baseline);
   if (auto last_baseline = physical_fragment.LastBaseline())
     container_builder_.SetLastBaseline(*last_baseline);
   if (physical_fragment.IsTableNGPart())
diff --git a/third_party/blink/renderer/core/loader/prerender_handle.cc b/third_party/blink/renderer/core/loader/prerender_handle.cc
index 599fb1d..cb0357a 100644
--- a/third_party/blink/renderer/core/loader/prerender_handle.cc
+++ b/third_party/blink/renderer/core/loader/prerender_handle.cc
@@ -61,7 +61,13 @@
   attributes->trigger_type = trigger_type;
   attributes->referrer = mojom::blink::Referrer::New(
       KURL(NullURL(), referrer.referrer), referrer.referrer_policy);
-  attributes->view_size = document.GetFrame()->GetMainFrameViewportSize();
+  // TODO(bokan): This is the _frame_ size, which is affected by the viewport
+  // <meta> tag, and is likely not what we want to use here. For example, if a
+  // page sets <meta name="viewport" content="width=42"> the frame size will
+  // have width=42. The prerendered page is unlikely to share the same
+  // viewport. I think this wants the size of the outermost WebView but that's
+  // not currently plumbed into child renderers AFAICT.
+  attributes->view_size = document.GetFrame()->GetOutermostMainFrameSize();
 
   HeapMojoRemote<mojom::blink::NoStatePrefetchProcessor> prefetch_processor(
       context);
diff --git a/third_party/blink/renderer/core/paint/ng/ng_mathml_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_mathml_painter.cc
index 99de6ef..2cffd3e 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_mathml_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_mathml_painter.cc
@@ -59,7 +59,7 @@
   if (!line_thickness)
     return;
   LayoutUnit axis_height = MathAxisHeight(style);
-  if (auto baseline = box_fragment_.Baseline()) {
+  if (auto baseline = box_fragment_.FirstBaseline()) {
     auto borders = box_fragment_.Borders();
     auto padding = box_fragment_.Padding();
     PhysicalRect bar_rect = {
@@ -119,10 +119,10 @@
   auto vertical = GetRadicalVerticalParameters(style, has_index);
 
   auto radical_base_ascent =
-      base_child.Baseline().value_or(base_child.Size().height) +
+      base_child.FirstBaseline().value_or(base_child.Size().height) +
       parameters.radical_base_margins.inline_start;
   LayoutUnit block_offset =
-      box_fragment_.Baseline().value_or(box_fragment_.Size().height) -
+      box_fragment_.FirstBaseline().value_or(box_fragment_.Size().height) -
       vertical.vertical_gap - radical_base_ascent;
 
   auto borders = box_fragment_.Borders();
diff --git a/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc b/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc
index 8d20f3d0..b3f480a 100644
--- a/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc
+++ b/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc
@@ -1464,7 +1464,7 @@
 
   mojom::blink::ViewportIntersectionState intersection;
   intersection.main_frame_intersection = gfx::Rect(0, 0, 100, 100);
-  intersection.main_frame_viewport_size = gfx::Size(100, 100);
+  intersection.outermost_main_frame_size = gfx::Size(100, 100);
   intersection.viewport_intersection = gfx::Rect(0, 0, 100, 100);
   LocalFrameRoot().FrameWidget()->Resize(gfx::Size(300, 200));
   static_cast<WebFrameWidgetImpl*>(LocalFrameRoot().FrameWidget())
diff --git a/third_party/blink/renderer/core/speculation_rules/document_speculation_rules.cc b/third_party/blink/renderer/core/speculation_rules/document_speculation_rules.cc
index 29c96a9..e49f6e5 100644
--- a/third_party/blink/renderer/core/speculation_rules/document_speculation_rules.cc
+++ b/third_party/blink/renderer/core/speculation_rules/document_speculation_rules.cc
@@ -104,7 +104,9 @@
             KURL(referrer.referrer), referrer.referrer_policy);
         candidates.push_back(mojom::blink::SpeculationCandidate::New(
             url, action, std::move(referrer_ptr),
-            rule->requires_anonymous_client_ip_when_cross_origin()));
+            rule->requires_anonymous_client_ip_when_cross_origin(),
+            rule->target_browsing_context_name_hint().value_or(
+                mojom::blink::SpeculationTargetHint::kNoHint)));
       }
     }
   };
diff --git a/third_party/blink/renderer/core/speculation_rules/speculation_rule.cc b/third_party/blink/renderer/core/speculation_rules/speculation_rule.cc
index 950c701..bc3e509 100644
--- a/third_party/blink/renderer/core/speculation_rules/speculation_rule.cc
+++ b/third_party/blink/renderer/core/speculation_rules/speculation_rule.cc
@@ -8,9 +8,11 @@
 
 SpeculationRule::SpeculationRule(
     Vector<KURL> urls,
-    RequiresAnonymousClientIPWhenCrossOrigin requires_anonymous_client_ip)
-    : urls_(urls),
-      requires_anonymous_client_ip_(requires_anonymous_client_ip) {}
+    RequiresAnonymousClientIPWhenCrossOrigin requires_anonymous_client_ip,
+    absl::optional<mojom::blink::SpeculationTargetHint> target_hint)
+    : urls_(std::move(urls)),
+      requires_anonymous_client_ip_(requires_anonymous_client_ip),
+      target_browsing_context_name_hint_(target_hint) {}
 
 SpeculationRule::~SpeculationRule() = default;
 
diff --git a/third_party/blink/renderer/core/speculation_rules/speculation_rule.h b/third_party/blink/renderer/core/speculation_rules/speculation_rule.h
index fc32843..bff737d 100644
--- a/third_party/blink/renderer/core/speculation_rules/speculation_rule.h
+++ b/third_party/blink/renderer/core/speculation_rules/speculation_rule.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_SPECULATION_RULES_SPECULATION_RULE_H_
 
 #include "base/types/strong_alias.h"
+#include "third_party/blink/public/mojom/speculation_rules/speculation_rules.mojom-blink.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
@@ -23,19 +24,28 @@
       base::StrongAlias<class RequiresAnonymousClientIPWhenCrossOriginTag,
                         bool>;
 
-  SpeculationRule(Vector<KURL>, RequiresAnonymousClientIPWhenCrossOrigin);
+  SpeculationRule(
+      Vector<KURL>,
+      RequiresAnonymousClientIPWhenCrossOrigin,
+      absl::optional<mojom::blink::SpeculationTargetHint> target_hint);
   ~SpeculationRule();
 
   const Vector<KURL>& urls() const { return urls_; }
   bool requires_anonymous_client_ip_when_cross_origin() const {
     return requires_anonymous_client_ip_.value();
   }
+  absl::optional<mojom::blink::SpeculationTargetHint>
+  target_browsing_context_name_hint() const {
+    return target_browsing_context_name_hint_;
+  }
 
   void Trace(Visitor*) const;
 
  private:
-  Vector<KURL> urls_;
-  RequiresAnonymousClientIPWhenCrossOrigin requires_anonymous_client_ip_;
+  const Vector<KURL> urls_;
+  const RequiresAnonymousClientIPWhenCrossOrigin requires_anonymous_client_ip_;
+  const absl::optional<mojom::blink::SpeculationTargetHint>
+      target_browsing_context_name_hint_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/speculation_rules/speculation_rule_set.cc b/third_party/blink/renderer/core/speculation_rules/speculation_rule_set.cc
index 26852698..a2f7cea 100644
--- a/third_party/blink/renderer/core/speculation_rules/speculation_rule_set.cc
+++ b/third_party/blink/renderer/core/speculation_rules/speculation_rule_set.cc
@@ -5,20 +5,51 @@
 #include "third_party/blink/renderer/core/speculation_rules/speculation_rule_set.h"
 
 #include "base/containers/contains.h"
+#include "third_party/blink/public/mojom/speculation_rules/speculation_rules.mojom-blink.h"
 #include "third_party/blink/renderer/platform/json/json_parser.h"
 #include "third_party/blink/renderer/platform/json/json_values.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_view.h"
 
 namespace blink {
 
 namespace {
 
+// https://html.spec.whatwg.org/C/#valid-browsing-context-name
+bool IsValidContextName(const String& name_or_keyword) {
+  // "A valid browsing context name is any string with at least one character
+  // that does not start with a U+005F LOW LINE character. (Names starting with
+  // an underscore are reserved for special keywords.)"
+  if (name_or_keyword.IsEmpty())
+    return false;
+  if (name_or_keyword.StartsWith("_"))
+    return false;
+  return true;
+}
+
+// https://html.spec.whatwg.org/C/#valid-browsing-context-name-or-keyword
+bool IsValidBrowsingContextNameOrKeyword(const String& name_or_keyword) {
+  // "A valid browsing context name or keyword is any string that is either a
+  // valid browsing context name or that is an ASCII case-insensitive match for
+  // one of: _blank, _self, _parent, or _top."
+  String canonicalized_name_or_keyword = name_or_keyword.LowerASCII();
+  if (IsValidContextName(name_or_keyword) ||
+      EqualIgnoringASCIICase(name_or_keyword, "_blank") ||
+      EqualIgnoringASCIICase(name_or_keyword, "_self") ||
+      EqualIgnoringASCIICase(name_or_keyword, "_parent") ||
+      EqualIgnoringASCIICase(name_or_keyword, "_top")) {
+    return true;
+  }
+  return false;
+}
+
 SpeculationRule* ParseSpeculationRule(JSONObject* input, const KURL& base_url) {
   // https://wicg.github.io/nav-speculation/speculation-rules.html#parse-a-speculation-rule
 
-  // If input has any key other than "source", "urls" and "requires", then
-  // return null.
-  const char* const kKnownKeys[] = {"source", "urls", "requires"};
+  // If input has any key other than "source", "urls", "requires", and
+  // "target_hint", then return null.
+  const char* const kKnownKeys[] = {"source", "urls", "requires",
+                                    "target_hint"};
   for (wtf_size_t i = 0; i < input->size(); ++i) {
     if (!base::Contains(kKnownKeys, input->at(i).first))
       return nullptr;
@@ -78,8 +109,34 @@
     }
   }
 
-  return MakeGarbageCollected<SpeculationRule>(std::move(urls),
-                                               requires_anonymous_client_ip);
+  // Let targetHint be null.
+  absl::optional<mojom::blink::SpeculationTargetHint> target_hint;
+
+  // If input["target_hint"] exists:
+  JSONValue* target_hint_value = input->Get("target_hint");
+  if (target_hint_value) {
+    // If input["target_hint"] is not a valid browsing context name or keyword,
+    // then return null.
+    // Set targetHint to input["target_hint"].
+    String target_hint_str;
+    if (!target_hint_value->AsString(&target_hint_str))
+      return nullptr;
+    if (!IsValidBrowsingContextNameOrKeyword(target_hint_str))
+      return nullptr;
+    // Currently only "_blank" and "_self" are supported.
+    // TODO(https://crbug.com/1354049): Support more browsing context names and
+    // keywords.
+    if (EqualIgnoringASCIICase(target_hint_str, "_blank")) {
+      target_hint = mojom::blink::SpeculationTargetHint::kBlank;
+    } else if (EqualIgnoringASCIICase(target_hint_str, "_self")) {
+      target_hint = mojom::blink::SpeculationTargetHint::kSelf;
+    } else {
+      target_hint = mojom::blink::SpeculationTargetHint::kNoHint;
+    }
+  }
+
+  return MakeGarbageCollected<SpeculationRule>(
+      std::move(urls), requires_anonymous_client_ip, target_hint);
 }
 
 }  // namespace
@@ -88,7 +145,7 @@
 SpeculationRuleSet* SpeculationRuleSet::ParseInline(const String& source_text,
                                                     const KURL& base_url,
                                                     String* out_error) {
-  // https://wicg.github.io/nav-speculation/prerendering.html#parse-speculation-rules
+  // https://wicg.github.io/nav-speculation/speculation-rules.html#parse-speculation-rules
 
   // Let parsed be the result of parsing a JSON string to an Infra value given
   // input.
@@ -109,31 +166,49 @@
   SpeculationRuleSet* result = MakeGarbageCollected<SpeculationRuleSet>();
 
   const auto parse_for_action =
-      [&](const char* key, HeapVector<Member<SpeculationRule>>& destination) {
+      [&](const char* key, HeapVector<Member<SpeculationRule>>& destination,
+          bool allow_target_hint) {
         JSONArray* array = parsed->GetArray(key);
         if (!array)
           return;
 
         for (wtf_size_t i = 0; i < array->size(); ++i) {
+          // If prefetch/prerenderRule is not a map, then continue.
           JSONObject* input_rule = JSONObject::Cast(array->at(i));
           if (!input_rule)
             continue;
 
-          if (SpeculationRule* r = ParseSpeculationRule(input_rule, base_url))
-            destination.push_back(r);
+          // Let rule be the result of parsing a speculation rule given
+          // prefetch/prerenderRule and baseURL.
+          SpeculationRule* rule = ParseSpeculationRule(input_rule, base_url);
+
+          // If rule is null, then continue.
+          if (!rule)
+            continue;
+
+          // If rule's target browsing context name hint is not null, then
+          // continue.
+          if (!allow_target_hint &&
+              rule->target_browsing_context_name_hint().has_value()) {
+            continue;
+          }
+
+          // Append rule to result's prefetch/prerender rules.
+          destination.push_back(rule);
         }
       };
 
   // If parsed["prefetch"] exists and is a list, then for each...
-  parse_for_action("prefetch", result->prefetch_rules_);
+  parse_for_action("prefetch", result->prefetch_rules_, false);
 
   // If parsed["prefetch_with_subresources"] exists and is a list, then for
   // each...
   parse_for_action("prefetch_with_subresources",
-                   result->prefetch_with_subresources_rules_);
+                   result->prefetch_with_subresources_rules_, false);
 
   // If parsed["prerender"] exists and is a list, then for each...
-  parse_for_action("prerender", result->prerender_rules_);
+  parse_for_action("prerender", result->prerender_rules_, true);
+
   return result;
 }
 
diff --git a/third_party/blink/renderer/core/speculation_rules/speculation_rule_set_test.cc b/third_party/blink/renderer/core/speculation_rules/speculation_rule_set_test.cc
index b3ba4a8..69bed1d 100644
--- a/third_party/blink/renderer/core/speculation_rules/speculation_rule_set_test.cc
+++ b/third_party/blink/renderer/core/speculation_rules/speculation_rule_set_test.cc
@@ -86,6 +86,30 @@
   return arg->requires_anonymous_client_ip_when_cross_origin();
 }
 
+SpeculationRuleSet* CreateSpeculationRuleSetWithTargetHint(
+    const char* target_hint) {
+  return SpeculationRuleSet::ParseInline(
+      String::Format(R"({
+        "prefetch": [{
+          "source": "list",
+          "urls": ["https://example.com/hint.html"],
+          "target_hint": "%s"
+        }],
+        "prefetch_with_subresources": [{
+          "source": "list",
+          "urls": ["https://example.com/hint.html"],
+          "target_hint": "%s"
+        }],
+        "prerender": [{
+          "source": "list",
+          "urls": ["https://example.com/hint.html"],
+          "target_hint": "%s"
+        }]
+      })",
+                     target_hint, target_hint, target_hint),
+      KURL("https://example.com/"));
+}
+
 class SpeculationRuleSetTest : public ::testing::Test {
  private:
   ScopedSpeculationRulesPrefetchProxyForTest enable_prefetch_{true};
@@ -256,6 +280,106 @@
               ElementsAre(MatchesListOfURLs("https://example.com/valid.html")));
 }
 
+// Test that only prerender rule can process a "_blank" target hint.
+TEST_F(SpeculationRuleSetTest, RulesWithTargetHint_Blank) {
+  auto* rule_set = CreateSpeculationRuleSetWithTargetHint("_blank");
+  ASSERT_TRUE(rule_set);
+  EXPECT_THAT(rule_set->prefetch_rules(), ElementsAre());
+  EXPECT_THAT(rule_set->prefetch_with_subresources_rules(), ElementsAre());
+  EXPECT_THAT(rule_set->prerender_rules(),
+              ElementsAre(MatchesListOfURLs("https://example.com/hint.html")));
+  EXPECT_EQ(rule_set->prerender_rules()[0]->target_browsing_context_name_hint(),
+            mojom::blink::SpeculationTargetHint::kBlank);
+}
+
+// Test that only prerender rule can process a "_self" target hint.
+TEST_F(SpeculationRuleSetTest, RulesWithTargetHint_Self) {
+  auto* rule_set = CreateSpeculationRuleSetWithTargetHint("_self");
+  ASSERT_TRUE(rule_set);
+  EXPECT_THAT(rule_set->prefetch_rules(), ElementsAre());
+  EXPECT_THAT(rule_set->prefetch_with_subresources_rules(), ElementsAre());
+  EXPECT_THAT(rule_set->prerender_rules(),
+              ElementsAre(MatchesListOfURLs("https://example.com/hint.html")));
+  EXPECT_EQ(rule_set->prerender_rules()[0]->target_browsing_context_name_hint(),
+            mojom::blink::SpeculationTargetHint::kSelf);
+}
+
+// Test that only prerender rule can process a "_parent" target hint but treat
+// it as no hint.
+// TODO(https://crbug.com/1354049): Support the "_parent" keyword for
+// prerendering.
+TEST_F(SpeculationRuleSetTest, RulesWithTargetHint_Parent) {
+  auto* rule_set = CreateSpeculationRuleSetWithTargetHint("_parent");
+  ASSERT_TRUE(rule_set);
+  EXPECT_THAT(rule_set->prefetch_rules(), ElementsAre());
+  EXPECT_THAT(rule_set->prefetch_with_subresources_rules(), ElementsAre());
+  EXPECT_THAT(rule_set->prerender_rules(),
+              ElementsAre(MatchesListOfURLs("https://example.com/hint.html")));
+  EXPECT_EQ(rule_set->prerender_rules()[0]->target_browsing_context_name_hint(),
+            mojom::blink::SpeculationTargetHint::kNoHint);
+}
+
+// Test that only prerender rule can process a "_top" target hint but treat it
+// as no hint.
+// Test that rules with a "_top" hint are ignored.
+// TODO(https://crbug.com/1354049): Support the "_top" keyword for prerendering.
+TEST_F(SpeculationRuleSetTest, RulesWithTargetHint_Top) {
+  auto* rule_set = CreateSpeculationRuleSetWithTargetHint("_top");
+  ASSERT_TRUE(rule_set);
+  EXPECT_THAT(rule_set->prefetch_rules(), ElementsAre());
+  EXPECT_THAT(rule_set->prefetch_with_subresources_rules(), ElementsAre());
+  EXPECT_THAT(rule_set->prerender_rules(),
+              ElementsAre(MatchesListOfURLs("https://example.com/hint.html")));
+  EXPECT_EQ(rule_set->prerender_rules()[0]->target_browsing_context_name_hint(),
+            mojom::blink::SpeculationTargetHint::kNoHint);
+}
+
+// Test that rules with an empty target hint are ignored.
+TEST_F(SpeculationRuleSetTest, RulesWithTargetHint_EmptyString) {
+  auto* rule_set = CreateSpeculationRuleSetWithTargetHint("");
+  ASSERT_TRUE(rule_set);
+  EXPECT_THAT(rule_set->prefetch_rules(), ElementsAre());
+  EXPECT_THAT(rule_set->prefetch_with_subresources_rules(), ElementsAre());
+  EXPECT_THAT(rule_set->prerender_rules(), ElementsAre());
+}
+
+// Test that only prerender rule can process a browsing context name target hint
+// but treat it as no hint.
+// TODO(https://crbug.com/1354049): Support valid browsing context names.
+TEST_F(SpeculationRuleSetTest, RulesWithTargetHint_ValidBrowsingContextName) {
+  auto* rule_set = CreateSpeculationRuleSetWithTargetHint("valid");
+  ASSERT_TRUE(rule_set);
+  EXPECT_THAT(rule_set->prefetch_rules(), ElementsAre());
+  EXPECT_THAT(rule_set->prefetch_with_subresources_rules(), ElementsAre());
+  EXPECT_THAT(rule_set->prerender_rules(),
+              ElementsAre(MatchesListOfURLs("https://example.com/hint.html")));
+  EXPECT_EQ(rule_set->prerender_rules()[0]->target_browsing_context_name_hint(),
+            mojom::blink::SpeculationTargetHint::kNoHint);
+}
+
+// Test that rules with an invalid browsing context name target hint are
+// ignored.
+TEST_F(SpeculationRuleSetTest, RulesWithTargetHint_InvalidBrowsingContextName) {
+  auto* rule_set = CreateSpeculationRuleSetWithTargetHint("_invalid");
+  ASSERT_TRUE(rule_set);
+  EXPECT_THAT(rule_set->prefetch_rules(), ElementsAre());
+  EXPECT_THAT(rule_set->prefetch_with_subresources_rules(), ElementsAre());
+  EXPECT_THAT(rule_set->prerender_rules(), ElementsAre());
+}
+
+// Test that the the validation of the browsing context keywords runs an ASCII
+// case-insensitive match.
+TEST_F(SpeculationRuleSetTest, RulesWithTargetHint_CaseInsensitive) {
+  auto* rule_set = CreateSpeculationRuleSetWithTargetHint("_BlAnK");
+  ASSERT_TRUE(rule_set);
+  EXPECT_THAT(rule_set->prefetch_rules(), ElementsAre());
+  EXPECT_THAT(rule_set->prefetch_with_subresources_rules(), ElementsAre());
+  EXPECT_THAT(rule_set->prerender_rules(),
+              ElementsAre(MatchesListOfURLs("https://example.com/hint.html")));
+  EXPECT_EQ(rule_set->prerender_rules()[0]->target_browsing_context_name_hint(),
+            mojom::blink::SpeculationTargetHint::kBlank);
+}
+
 TEST_F(SpeculationRuleSetTest, PropagatesToDocument) {
   // A <script> with a case-insensitive type match should be propagated to the
   // document.
diff --git a/third_party/blink/renderer/modules/mediarecorder/audio_track_opus_encoder.cc b/third_party/blink/renderer/modules/mediarecorder/audio_track_opus_encoder.cc
index 9fc99b1f..4aa873bc 100644
--- a/third_party/blink/renderer/modules/mediarecorder/audio_track_opus_encoder.cc
+++ b/third_party/blink/renderer/modules/mediarecorder/audio_track_opus_encoder.cc
@@ -110,7 +110,7 @@
   // opus_encoder_create()): force |converted_params_| to at most those.
   converted_params_ = media::AudioParameters(
       media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
-      media::GuessChannelLayout(std::min(input_params_.channels(), 2)),
+      media::ChannelLayoutConfig::Guess(std::min(input_params_.channels(), 2)),
       kOpusPreferredSamplingRate, kOpusPreferredFramesPerBuffer);
   DVLOG(1) << "|input_params_|:" << input_params_.AsHumanReadableString()
            << " -->|converted_params_|:"
diff --git a/third_party/blink/renderer/modules/mediarecorder/audio_track_recorder_unittest.cc b/third_party/blink/renderer/modules/mediarecorder/audio_track_recorder_unittest.cc
index 0fe32e1..e0691b3 100644
--- a/third_party/blink/renderer/modules/mediarecorder/audio_track_recorder_unittest.cc
+++ b/third_party/blink/renderer/modules/mediarecorder/audio_track_recorder_unittest.cc
@@ -49,7 +49,7 @@
 
 struct ATRTestParams {
   const media::AudioParameters::Format input_format;
-  const media::ChannelLayout channel_layout;
+  const media::ChannelLayoutConfig channel_layout;
   const int sample_rate;
   const AudioTrackRecorder::CodecId codec;
   const AudioTrackRecorder::BitrateMode bitrateMode;
@@ -58,45 +58,52 @@
 const ATRTestParams kATRTestParams[] = {
     // Equivalent to default settings:
     {media::AudioParameters::AUDIO_PCM_LOW_LATENCY, /* input format */
-     media::CHANNEL_LAYOUT_STEREO,                  /* channel layout */
+     media::ChannelLayoutConfig::Stereo(),          /* channel layout */
      kDefaultSampleRate,                            /* sample rate */
      AudioTrackRecorder::CodecId::kOpus,            /* codec for encoding */
      AudioTrackRecorder::BitrateMode::kVariable},   /* constant/variable rate */
 
     // Change to mono:
-    {media::AudioParameters::AUDIO_PCM_LOW_LATENCY, media::CHANNEL_LAYOUT_MONO,
-     kDefaultSampleRate, AudioTrackRecorder::CodecId::kOpus,
+    {media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
+     media::ChannelLayoutConfig::Mono(), kDefaultSampleRate,
+     AudioTrackRecorder::CodecId::kOpus,
      AudioTrackRecorder::BitrateMode::kVariable},
 
     // Different sampling rate as well:
-    {media::AudioParameters::AUDIO_PCM_LOW_LATENCY, media::CHANNEL_LAYOUT_MONO,
-     24000, AudioTrackRecorder::CodecId::kOpus,
+    {media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
+     media::ChannelLayoutConfig::Mono(), 24000,
+     AudioTrackRecorder::CodecId::kOpus,
      AudioTrackRecorder::BitrateMode::kVariable},
     {media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
-     media::CHANNEL_LAYOUT_STEREO, 8000, AudioTrackRecorder::CodecId::kOpus,
+     media::ChannelLayoutConfig::Stereo(), 8000,
+     AudioTrackRecorder::CodecId::kOpus,
      AudioTrackRecorder::BitrateMode::kVariable},
 
     // Using a non-default Opus sampling rate (48, 24, 16, 12, or 8 kHz).
-    {media::AudioParameters::AUDIO_PCM_LOW_LATENCY, media::CHANNEL_LAYOUT_MONO,
-     22050, AudioTrackRecorder::CodecId::kOpus,
+    {media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
+     media::ChannelLayoutConfig::Mono(), 22050,
+     AudioTrackRecorder::CodecId::kOpus,
      AudioTrackRecorder::BitrateMode::kVariable},
     {media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
-     media::CHANNEL_LAYOUT_STEREO, 44100, AudioTrackRecorder::CodecId::kOpus,
+     media::ChannelLayoutConfig::Stereo(), 44100,
+     AudioTrackRecorder::CodecId::kOpus,
      AudioTrackRecorder::BitrateMode::kVariable},
     {media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
-     media::CHANNEL_LAYOUT_STEREO, 96000, AudioTrackRecorder::CodecId::kOpus,
-     AudioTrackRecorder::BitrateMode::kVariable},
-    {media::AudioParameters::AUDIO_PCM_LOW_LATENCY, media::CHANNEL_LAYOUT_MONO,
-     kDefaultSampleRate, AudioTrackRecorder::CodecId::kPcm,
+     media::ChannelLayoutConfig::Stereo(), 96000,
+     AudioTrackRecorder::CodecId::kOpus,
      AudioTrackRecorder::BitrateMode::kVariable},
     {media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
-     media::CHANNEL_LAYOUT_STEREO, kDefaultSampleRate,
+     media::ChannelLayoutConfig::Mono(), kDefaultSampleRate,
+     AudioTrackRecorder::CodecId::kPcm,
+     AudioTrackRecorder::BitrateMode::kVariable},
+    {media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
+     media::ChannelLayoutConfig::Stereo(), kDefaultSampleRate,
      AudioTrackRecorder::CodecId::kPcm,
      AudioTrackRecorder::BitrateMode::kVariable},
 
     // Use Opus in constatnt bitrate mode:
     {media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
-     media::CHANNEL_LAYOUT_STEREO, kDefaultSampleRate,
+     media::ChannelLayoutConfig::Stereo(), kDefaultSampleRate,
      AudioTrackRecorder::CodecId::kOpus,
      AudioTrackRecorder::BitrateMode::kConstant},
 };
@@ -117,7 +124,7 @@
                       GetParam().sample_rate,
                       FramesPerBuffer(GetParam().sample_rate)),
         second_params_(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
-                       media::CHANNEL_LAYOUT_STEREO,
+                       media::ChannelLayoutConfig::Stereo(),
                        kDefaultSampleRate,
                        FramesPerBuffer(kDefaultSampleRate)),
         first_source_(first_params_.channels(),     /* # channels */
diff --git a/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler_unittest.cc b/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler_unittest.cc
index e1e3e658..e710b2d 100644
--- a/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler_unittest.cc
+++ b/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler_unittest.cc
@@ -432,8 +432,8 @@
   const std::unique_ptr<media::AudioBus> audio_bus2 = NextAudioBus();
 
   media::AudioParameters params(
-      media::AudioParameters::AUDIO_PCM_LINEAR, media::CHANNEL_LAYOUT_STEREO,
-      kTestAudioSampleRate,
+      media::AudioParameters::AUDIO_PCM_LINEAR,
+      media::ChannelLayoutConfig::Stereo(), kTestAudioSampleRate,
       kTestAudioSampleRate * kTestAudioBufferDurationMs / 1000);
   SetAudioFormatForTesting(params);
 
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.cc b/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.cc
index 5e0b888..6dfa7545 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.cc
@@ -15,6 +15,7 @@
   X(maxTextureDimension3D)                     \
   X(maxTextureArrayLayers)                     \
   X(maxBindGroups)                             \
+  X(maxBindingsPerBindGroup)                   \
   X(maxDynamicUniformBuffersPerPipelineLayout) \
   X(maxDynamicStorageBuffersPerPipelineLayout) \
   X(maxSampledTexturesPerShaderStage)          \
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.h b/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.h
index 149cde41..a43cdb4 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.h
+++ b/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.h
@@ -34,6 +34,7 @@
   unsigned maxTextureDimension3D() const;
   unsigned maxTextureArrayLayers() const;
   unsigned maxBindGroups() const;
+  unsigned maxBindingsPerBindGroup() const;
   unsigned maxDynamicUniformBuffersPerPipelineLayout() const;
   unsigned maxDynamicStorageBuffersPerPipelineLayout() const;
   unsigned maxSampledTexturesPerShaderStage() const;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.idl b/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.idl
index c6c19bf..a94ae285 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.idl
@@ -13,6 +13,7 @@
     readonly attribute unsigned long maxTextureDimension3D;
     readonly attribute unsigned long maxTextureArrayLayers;
     readonly attribute unsigned long maxBindGroups;
+    readonly attribute unsigned long maxBindingsPerBindGroup;
     readonly attribute unsigned long maxDynamicUniformBuffersPerPipelineLayout;
     readonly attribute unsigned long maxDynamicStorageBuffersPerPipelineLayout;
     readonly attribute unsigned long maxSampledTexturesPerShaderStage;
diff --git a/third_party/blink/tools/blinkpy/common/config/builders.json b/third_party/blink/tools/blinkpy/common/config/builders.json
index c29489c..baefe06d 100644
--- a/third_party/blink/tools/blinkpy/common/config/builders.json
+++ b/third_party/blink/tools/blinkpy/common/config/builders.json
@@ -60,10 +60,26 @@
         "specifiers": ["Fuchsia", "Release"],
         "steps": {
             "blink_web_tests (with patch)": {},
-	    "blink_wpt_tests (with patch)": {}
+            "blink_wpt_tests (with patch)": {}
         },
         "is_try_builder": true
     },
+    "linux-wpt-fyi-rel": {
+        "main": "chromium.fyi",
+        "port_name": "linux-trusty",
+        "specifiers": ["Trusty", "Release"],
+        "steps": {
+            "wpt_tests_suite (experimental)": {}
+        }
+    },
+    "linux-wpt-content-shell-fyi-rel": {
+        "main": "chromium.fyi",
+        "port_name": "linux-trusty",
+        "specifiers": ["Trusty", "Release"],
+        "steps": {
+            "wpt_tests_suite (experimental)": {}
+        }
+    },
     "linux-wpt-identity-fyi-rel": {
         "main": "tryserver.chromium.linux",
         "port_name": "linux-trusty",
@@ -247,17 +263,19 @@
         "is_try_builder": true,
         "is_cq_builder":true
     },
+    "android-webview-pie-x86-wpt-fyi-rel": {
+        "port_name": "android-android-pie",
+        "main": "chromium.android.fyi",
+        "specifiers": ["Android", "android_webview", "Release"]
+    },
     "android-weblayer-pie-x86-wpt-fyi-rel": {
         "port_name": "android-android-pie",
         "main": "chromium.android.fyi",
-        "specifiers": [
-            "Android", "android_weblayer", "Release"
-        ]
+        "specifiers": ["Android", "android_weblayer", "Release"]
     },
     "android-chrome-pie-x86-wpt-fyi-rel": {
         "port_name": "android-android-pie",
         "main": "chromium.android.fyi",
-        "specifiers": [
-            "Android", "chrome_android", "Release"]
+        "specifiers": ["Android", "chrome_android", "Release"]
     }
 }
diff --git a/third_party/blink/tools/blinkpy/tool/commands/update_metadata.py b/third_party/blink/tools/blinkpy/tool/commands/update_metadata.py
index 7628a3d..ed4cad0 100644
--- a/third_party/blink/tools/blinkpy/tool/commands/update_metadata.py
+++ b/third_party/blink/tools/blinkpy/tool/commands/update_metadata.py
@@ -178,14 +178,23 @@
                 test_files_to_stage.append(test_file)
 
         if not dry_run:
-            paths = self._metadata_paths(test_files_to_stage)
+            unstaged_changes = {
+                self._path_finder.path_from_chromium_base(path)
+                for path in self.git.unstaged_changes()
+            }
+            # Filter out all-pass metadata files marked as "modified" that
+            # already do not exist on disk or in the index. Otherwise, `git add`
+            # will fail.
+            paths = [
+                path for path in self._metadata_paths(test_files_to_stage)
+                if path in unstaged_changes
+            ]
             # Stage the files in chunks to avoid a Windows command line length
             # limit. The chunk size was picked heuristically.
             for chunk_start in range(0, len(paths), chunk_size):
                 self.git.add_list(paths[chunk_start:chunk_start + chunk_size])
-            _log.info(
-                'Staged %s.',
-                grammar.pluralize('metadata file', len(test_files_to_stage)))
+            _log.info('Staged %s.',
+                      grammar.pluralize('metadata file', len(paths)))
 
     def _filter_unchanged_test_files(
             self,
diff --git a/third_party/blink/tools/blinkpy/tool/commands/update_metadata_unittest.py b/third_party/blink/tools/blinkpy/tool/commands/update_metadata_unittest.py
index 3f06f5f9..bcfae9e6 100644
--- a/third_party/blink/tools/blinkpy/tool/commands/update_metadata_unittest.py
+++ b/third_party/blink/tools/blinkpy/tool/commands/update_metadata_unittest.py
@@ -147,8 +147,16 @@
             }],
         }).encode()
 
+    def _unstaged_changes(self):
+        wpt_glob = self.finder.path_from_web_tests('external', 'wpt', '*.ini')
+        return patch.object(
+            self.command.git,
+            'unstaged_changes',
+            side_effect=lambda: self.tool.filesystem.glob(wpt_glob))
+
     def test_execute_all(self):
-        with self._patch_builtins():
+        with self._patch_builtins() as stack:
+            stack.enter_context(self._unstaged_changes())
             exit_code = self.command.main([])
         self.assertEqual(exit_code, 0)
         # Even tests that pass may require an update if a subtest was added or
@@ -271,14 +279,15 @@
         self.assertEqual(self.tool.git().added_paths, set())
 
     def test_execute_only_changed_tests(self):
-        changed_files = [
-            'third_party/blink/web_tests/external/wpt/crash.html',
-        ]
         with self._patch_builtins() as stack:
             stack.enter_context(
-                patch.object(self.command.git,
-                             'changed_files',
-                             return_value=changed_files))
+                patch.object(
+                    self.command.git,
+                    'changed_files',
+                    return_value=[
+                        'third_party/blink/web_tests/external/wpt/crash.html',
+                    ]))
+            stack.enter_context(self._unstaged_changes())
             exit_code = self.command.main(['--only-changed-tests'])
         self.assertEqual(exit_code, 0)
         self.assertLog([
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 664e62a..0bc4e17 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -6851,7 +6851,7 @@
 virtual/plz-dedicated-worker/external/wpt/resource-timing/no-entries-for-cross-origin-css-fetched-memory-cache.sub.html [ Skip ]
 
 # Disable step failure trigger flaky tests   
-crbug.com/1351571 [ Mac12-arm64 ] http/tests/devtools/persistence/automapping-bind-committed-network-sourcecode.js [ Failure Timeout Pass ]
+crbug.com/1351571 [ Mac12-arm64 ] http/tests/devtools/persistence/automapping-bind-committed-network-sourcecode.js [ Failure Pass Timeout ]
 crbug.com/1358333 [ Mac10.15 ] external/wpt/webmessaging/event.origin.sub.htm [ Failure Pass ]
 
 # Sheriff 2022-08-31
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index 3fe6247..6e7a916 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -296343,6 +296343,20 @@
       "c0e56dc051000b907d5c7b66f9a014470c14c685",
       []
      ],
+     "historical": {
+      "webkit-user-modify-01-expected.txt": [
+       "8f93a5c5662d136930da6394bc25a2455fa131c2",
+       []
+      ],
+      "webkit-user-modify-02-expected.txt": [
+       "d17d1d2212af371013c5943f2964742039204edb",
+       []
+      ],
+      "webkit-user-modify-03-expected.txt": [
+       "6a8ec669e7c045645360223257c63f94dc3e021b",
+       []
+      ]
+     },
      "inheritance-expected.txt": [
       "548a76a3407ac8a48f9f108559957cf061f20a19",
       []
@@ -337821,7 +337835,7 @@
      []
     ],
     "enrollment.https-expected.txt": [
-     "d3dd35b3578b4f5bdc3c43348a36f99a572f1e7f",
+     "f9c50fc46685b90a6540ae85112dd061f30ace1a",
      []
     ],
     "resources": {
@@ -345921,7 +345935,7 @@
      []
     ],
     "helpers.js": [
-     "4fb1904b45340efe1f9efdee1c3a236689f7fa4f",
+     "efe3537e4f82926a447287f38b1d3bd434613e3f",
      []
     ],
     "idlharness.https.window-expected.txt": [
@@ -384228,7 +384242,7 @@
      ]
     ],
     "otpcredential-get-basics.https.html": [
-     "c0cac166de91c242a16bd4d6fc2edfa93aa37680",
+     "3907f85450fe4642720b2c8ec374f7f689bfbdd1",
      [
       null,
       {}
@@ -409807,6 +409821,71 @@
        {}
       ]
      ],
+     "historical": {
+      "moz-user-modify-01.html": [
+       "595df9440e523fc371cf55975e4042d569163136",
+       [
+        null,
+        {}
+       ]
+      ],
+      "moz-user-modify-02.html": [
+       "e284d0c4751c09be559a133869edf2dedd9805dc",
+       [
+        null,
+        {}
+       ]
+      ],
+      "moz-user-modify-03.html": [
+       "e827b404e9462b19a456b2c8c6bea35e3cbe8ac1",
+       [
+        null,
+        {}
+       ]
+      ],
+      "user-modify-01.html": [
+       "dee93a618f2538e1a06191d818589dfda788431b",
+       [
+        null,
+        {}
+       ]
+      ],
+      "user-modify-02.html": [
+       "2a96871d90bc5f157c3c9d19bced34a3f206fd20",
+       [
+        null,
+        {}
+       ]
+      ],
+      "user-modify-03.html": [
+       "8d47e5259f759db50f40a0163c2ecef9153f460a",
+       [
+        null,
+        {}
+       ]
+      ],
+      "webkit-user-modify-01.html": [
+       "f756274d472ec1a833944528c39a935f373a83a2",
+       [
+        null,
+        {}
+       ]
+      ],
+      "webkit-user-modify-02.html": [
+       "9db2567467fb91d44e264a3200b58aef8f357235",
+       [
+        null,
+        {}
+       ]
+      ],
+      "webkit-user-modify-03.html": [
+       "e82ceffc37013e74a73eaabb5371268c1640215b",
+       [
+        null,
+        {}
+       ]
+      ]
+     },
      "inheritance.html": [
       "c2aab07a23b9502353c7c3bbe798963442c651fe",
       [
@@ -537814,7 +537893,7 @@
      ]
     ],
     "enrollment.https.html": [
-     "7a370aa7b7ebecdcebb832f8e54f284ac5011b85",
+     "b93822c7f18e5d265499ade28a254cf85cf5fe1a",
      [
       null,
       {
@@ -564693,6 +564772,16 @@
       }
      ]
     ],
+    "createcredential-abort.https.html": [
+     "d175e660e71821509045528e8cb026967e594f1a",
+     [
+      null,
+      {
+       "testdriver": true,
+       "timeout": "long"
+      }
+     ]
+    ],
     "createcredential-attachment.https.html": [
      "e9458ad5604875e2ba430647cd434e561556a675",
      [
@@ -564863,6 +564952,15 @@
       }
      ]
     ],
+    "getcredential-abort.https.html": [
+     "958f65daf1bccfe6200bb4a06e9cd75e06f4346d",
+     [
+      null,
+      {
+       "timeout": "long"
+      }
+     ]
+    ],
     "getcredential-attachment.https.html": [
      "7ab7235af501287bd9bc96d09ec549702e359dce",
      [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/historical/moz-user-modify-01.html b/third_party/blink/web_tests/external/wpt/css/css-ui/historical/moz-user-modify-01.html
new file mode 100644
index 0000000..595df94
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/historical/moz-user-modify-01.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>-moz-user-modify should be unsupported in author origin</title>
+<link rel="help" href="https://developer.mozilla.org/en-US/docs/Web/CSS/user-modify">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+#modified {
+    -moz-user-modify: read-write;
+}
+</style>
+<div id="inherited"></div>
+<div id="modified"></div>
+<script>
+    test(function() {
+        for (const el of [inherited, modified]) {
+            assert_equals(el.style.MozUserModify, undefined);
+            assert_equals(el.style.mozUserModify, undefined);
+            assert_equals(getComputedStyle(el).getPropertyValue('-moz-user-modify'), '');
+        }
+    }, '-moz-user-modify is not supported');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/historical/moz-user-modify-02.html b/third_party/blink/web_tests/external/wpt/css/css-ui/historical/moz-user-modify-02.html
new file mode 100644
index 0000000..e284d0c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/historical/moz-user-modify-02.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>-moz-user-modify should be unsupported in contenteditable</title>
+<link rel="help" href="https://developer.mozilla.org/en-US/docs/Web/CSS/user-modify">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="contentEditableTrue" contenteditable="true"></div>
+<div id="contentEditablePlainText" contenteditable="plaintext-only"></div>
+<script>
+    test(function() {
+        const contentEditableTrue = document.getElementById('contentEditableTrue');
+        assert_equals(getComputedStyle(contentEditableTrue).getPropertyValue('-moz-user-modify'), '');
+    }, 'contenteditable="true" doesn\'t use unsupported -moz-user-modify property');
+
+    test(function() {
+        const contentEditablePlainText = document.getElementById('contentEditablePlainText');
+        assert_equals(getComputedStyle(contentEditablePlainText).getPropertyValue('-moz-user-modify'), '');
+    }, 'contenteditable="plaintext-only" doesn\'t use unsupported -moz-user-modify property');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/historical/moz-user-modify-03.html b/third_party/blink/web_tests/external/wpt/css/css-ui/historical/moz-user-modify-03.html
new file mode 100644
index 0000000..e827b40
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/historical/moz-user-modify-03.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>-moz-user-modify should be unsupported in CSS.supports</title>
+<link rel="help" href="https://developer.mozilla.org/en-US/docs/Web/CSS/user-modify">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+@supports (-moz-user-modify: read-only) {
+    #content {
+        width: 10px;
+        height: 10px;
+        background-color: red;
+    }
+}
+</style>
+<div id="content"></div>
+<script>
+    test(function() {
+        const content = document.getElementById('content');
+        assert_not_equals(getComputedStyle(content).getPropertyValue('background-color'), 'rgb(255, 0, 0)');
+    }, '@supports doesn\'t use unsupported -moz-user-modify property');
+
+    test(function() {
+        const supportsMozUserModifyProperty = CSS.supports(`(-moz-user-modify: read-only) or
+            (-moz-user-modify: read-write) or
+            (-moz-user-modify: write-only)`);
+        assert_equals(supportsMozUserModifyProperty, false);
+    }, 'CSS.supports doesn\'t use unsupported -moz-user-modify property');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/historical/user-modify-01.html b/third_party/blink/web_tests/external/wpt/css/css-ui/historical/user-modify-01.html
new file mode 100644
index 0000000..dee93a6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/historical/user-modify-01.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>user-modify should be unsupported in author origin</title>
+<link rel="help" href="https://developer.mozilla.org/en-US/docs/Web/CSS/user-modify">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+#modified {
+    user-modify: read-write;
+}
+</style>
+<div id="inherited"></div>
+<div id="modified"></div>
+<script>
+    test(function() {
+        for (const el of [inherited, modified]) {
+            assert_equals(el.style.userModify, undefined);
+            assert_equals(el.style.UserModify, undefined);
+            assert_equals(getComputedStyle(el).getPropertyValue('user-modify'), '');
+        }
+    }, 'user-modify is not supported');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/historical/user-modify-02.html b/third_party/blink/web_tests/external/wpt/css/css-ui/historical/user-modify-02.html
new file mode 100644
index 0000000..2a96871
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/historical/user-modify-02.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>user-modify should be unsupported in contenteditable</title>
+<link rel="help" href="https://developer.mozilla.org/en-US/docs/Web/CSS/user-modify">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="contentEditableTrue" contenteditable="true"></div>
+<div id="contentEditablePlainText" contenteditable="plaintext-only"></div>
+<script>
+    test(function() {
+        const contentEditableTrue = document.getElementById('contentEditableTrue');
+        assert_equals(getComputedStyle(contentEditableTrue).getPropertyValue('user-modify'), '');
+    }, 'contenteditable="true" doesn\'t use unsupported user-modify property');
+
+    test(function() {
+        const contentEditablePlainText = document.getElementById('contentEditablePlainText');
+        assert_equals(getComputedStyle(contentEditablePlainText).getPropertyValue('user-modify'), '');
+    }, 'contenteditable="plaintext-only" doesn\'t use unsupported user-modify property');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/historical/user-modify-03.html b/third_party/blink/web_tests/external/wpt/css/css-ui/historical/user-modify-03.html
new file mode 100644
index 0000000..8d47e525
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/historical/user-modify-03.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>user-modify should be unsupported in CSS.supports</title>
+<link rel="help" href="https://developer.mozilla.org/en-US/docs/Web/CSS/user-modify">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+@supports (user-modify: read-only) {
+    #content {
+        width: 10px;
+        height: 10px;
+        background-color: red;
+    }
+}
+</style>
+<div id="content"></div>
+<script>
+    test(function() {
+        const content = document.getElementById('content');
+        assert_not_equals(getComputedStyle(content).getPropertyValue('background-color'), 'rgb(255, 0, 0)');
+    }, '@supports doesn\'t use unsupported user-modify property');
+
+    test(function() {
+        const supportsUserModifyProperty = CSS.supports(`(user-modify: read-only) or
+            (user-modify: read-write) or
+            (user-modify: write-only)`);
+        assert_equals(supportsUserModifyProperty, false);
+    }, 'CSS.supports doesn\'t use unsupported user-modify property');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/historical/webkit-user-modify-01-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-ui/historical/webkit-user-modify-01-expected.txt
new file mode 100644
index 0000000..8f93a5c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/historical/webkit-user-modify-01-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL -webkit-user-modify is not supported assert_equals: expected (undefined) undefined but got (string) ""
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/historical/webkit-user-modify-01.html b/third_party/blink/web_tests/external/wpt/css/css-ui/historical/webkit-user-modify-01.html
new file mode 100644
index 0000000..f756274
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/historical/webkit-user-modify-01.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>-webkit-user-modify should be unsupported in author origin</title>
+<link rel="help" href="https://developer.mozilla.org/en-US/docs/Web/CSS/user-modify">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+#modified {
+    -webkit-user-modify: read-write-plaintext-only;
+}
+</style>
+<div id="inherited"></div>
+<div id="modified"></div>
+<script>
+    test(function() {
+        for (const el of [inherited, modified]) {
+            assert_equals(el.style.WebkitUserModify, undefined);
+            assert_equals(el.style.webkitUserModify, undefined);
+            assert_equals(getComputedStyle(el).getPropertyValue('-webkit-user-modify'), '');
+        }
+    }, '-webkit-user-modify is not supported');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/historical/webkit-user-modify-02-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-ui/historical/webkit-user-modify-02-expected.txt
new file mode 100644
index 0000000..d17d1d2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/historical/webkit-user-modify-02-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL contenteditable="true" doesn't use unsupported -webkit-user-modify property assert_equals: expected "" but got "read-write"
+FAIL contenteditable="plaintext-only" doesn't use unsupported -webkit-user-modify property assert_equals: expected "" but got "read-write-plaintext-only"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/historical/webkit-user-modify-02.html b/third_party/blink/web_tests/external/wpt/css/css-ui/historical/webkit-user-modify-02.html
new file mode 100644
index 0000000..9db2567
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/historical/webkit-user-modify-02.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>-webkit-user-modify should be unsupported in contenteditable</title>
+<link rel="help" href="https://developer.mozilla.org/en-US/docs/Web/CSS/user-modify">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="contentEditableTrue" contenteditable="true"></div>
+<div id="contentEditablePlainText" contenteditable="plaintext-only"></div>
+<script>
+    test(function() {
+        const contentEditableTrue = document.getElementById('contentEditableTrue');
+        assert_equals(getComputedStyle(contentEditableTrue).getPropertyValue('-webkit-user-modify'), '');
+    }, 'contenteditable="true" doesn\'t use unsupported -webkit-user-modify property');
+
+    test(function() {
+        const contentEditablePlainText = document.getElementById('contentEditablePlainText');
+        assert_equals(getComputedStyle(contentEditablePlainText).getPropertyValue('-webkit-user-modify'), '');
+    }, 'contenteditable="plaintext-only" doesn\'t use unsupported -webkit-user-modify property');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/historical/webkit-user-modify-03-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-ui/historical/webkit-user-modify-03-expected.txt
new file mode 100644
index 0000000..6a8ec669
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/historical/webkit-user-modify-03-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL @supports doesn't use unsupported -webkit-user-modify property assert_not_equals: got disallowed value "rgb(255, 0, 0)"
+FAIL CSS.supports doesn't use unsupported -webkit-user-modify property assert_equals: expected false but got true
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/historical/webkit-user-modify-03.html b/third_party/blink/web_tests/external/wpt/css/css-ui/historical/webkit-user-modify-03.html
new file mode 100644
index 0000000..e82ceff
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/historical/webkit-user-modify-03.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>-webkit-user-modify should be unsupported in CSS.supports</title>
+<link rel="help" href="https://developer.mozilla.org/en-US/docs/Web/CSS/user-modify">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+@supports (-webkit-user-modify: read-only) {
+    #content {
+        width: 10px;
+        height: 10px;
+        background-color: red;
+    }
+}
+</style>
+<div id="content"></div>
+<script>
+    test(function() {
+        const content = document.getElementById('content');
+        assert_not_equals(getComputedStyle(content).getPropertyValue('background-color'), 'rgb(255, 0, 0)');
+    }, '@supports doesn\'t use unsupported -webkit-user-modify property');
+
+    test(function() {
+        const supportsWebkitUserModifyProperty = CSS.supports(`(-webkit-user-modify: read-only) or
+            (-webkit-user-modify: read-write) or
+            (-webkit-user-modify: read-write-plaintext-only) or
+            (-webkit-user-modify: write-only)`);
+        assert_equals(supportsWebkitUserModifyProperty, false);
+    }, 'CSS.supports doesn\'t use unsupported -webkit-user-modify property');
+</script>
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/prerender/report-prerender-resent-activation-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/prerender/report-prerender-resent-activation-expected.txt
new file mode 100644
index 0000000..549faa6
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/prerender/report-prerender-resent-activation-expected.txt
@@ -0,0 +1,20 @@
+Test that prerender navigations report the resent activation.
+{
+    method : Page.prerenderAttemptCompleted
+    params : {
+        finalStatus : Activated
+        initiatingFrameId : <string>
+        prerenderingUrl : http://127.0.0.1:8000/inspector-protocol/prerender/resources/empty.html
+    }
+    sessionId : <string>
+}
+{
+    method : Page.prerenderAttemptCompleted
+    params : {
+        finalStatus : Activated
+        initiatingFrameId : <string>
+        prerenderingUrl : http://127.0.0.1:8000/inspector-protocol/prerender/resources/empty.html
+    }
+    sessionId : <string>
+}
+
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/prerender/report-prerender-resent-activation.js b/third_party/blink/web_tests/http/tests/inspector-protocol/prerender/report-prerender-resent-activation.js
new file mode 100644
index 0000000..187596d
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/prerender/report-prerender-resent-activation.js
@@ -0,0 +1,17 @@
+(async function(testRunner) {
+  const {page, session, dp} = await testRunner.startBlank(
+      `Test that prerender navigations report the resent activation.`);
+  await dp.Page.enable();
+
+  // Navigate to speculation rules Prerender Page.
+  await page.navigate('resources/simple-prerender.html');
+  session.evaluate(`document.getElementById('link').click()`);
+  const statusReport = await dp.Page.oncePrerenderAttemptCompleted();
+  testRunner.log(statusReport, '', ['initiatingFrameId', 'sessionId']);
+  await dp.Page.disable();
+  dp.Page.enable();
+  const resentStatusReport = await dp.Page.oncePrerenderAttemptCompleted();
+  testRunner.log(resentStatusReport, '', ['initiatingFrameId', 'sessionId']);
+
+  testRunner.completeTest();
+});
diff --git a/third_party/nearby/README.chromium b/third_party/nearby/README.chromium
index 7fceb92d6..84cf23b 100644
--- a/third_party/nearby/README.chromium
+++ b/third_party/nearby/README.chromium
@@ -1,7 +1,7 @@
 Name: Nearby Connections Library
 Short Name: Nearby
 URL: https://github.com/google/nearby
-Version: 408900e702103c8ed39af851aae3095da03c076f
+Version: 525283a166274480d842fb6104074337c6ec8727
 License: Apache 2.0
 License File: LICENSE
 Security Critical: yes
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index f709529..55d2e0f 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -23418,6 +23418,11 @@
   <int value="6" label="Failure: Invalid referrer for the calling session"/>
 </enum>
 
+<enum name="CustomTabsResizeType">
+  <int value="0" label="Partial Custom Tab is expanded"/>
+  <int value="1" label="Partial Custom Tab is minimized"/>
+</enum>
+
 <enum name="CustomTabsSpeculationStatusOnStart">
   <int value="0"
       label="Speculation allowed. If started, the kind will also be recorded"/>
@@ -24476,6 +24481,7 @@
   <int value="49" label="Projector"/>
   <int value="50" label="Calculator"/>
   <int value="51" label="FirmwareUpdateApp"/>
+  <int value="52" label="Google TV"/>
 </enum>
 
 <enum name="DefaultBrowserAsyncAttemptResult">
@@ -54065,7 +54071,7 @@
     Hash values of language codes that correspond to a Language Pack. The hash
     is created by computing base::PersistentHash() of the label, then cast to
     int32. To generate new values in a way that is consistent, use the unit test
-    at chromeos/language/language_packs/metrics_unittest.cc.
+    at chromeos/ash/components/language/language_packs/metrics_unittest.cc.
   </summary>
   <int value="-1954182822" label="et"/>
   <int value="-1902856059" label="tr"/>
@@ -56255,6 +56261,7 @@
   <int value="-1993730028" label="CrostiniPortForwarding:enabled"/>
   <int value="-1992999120" label="composite-after-paint"/>
   <int value="-1992488524" label="AutofillAcrossIframes:disabled"/>
+  <int value="-1991935790" label="ShareCrowLaunchTab:enabled"/>
   <int value="-1990614981" label="StoragePressureUI:disabled"/>
   <int value="-1990238241" label="ChromeOSHWVBREncoding:enabled"/>
   <int value="-1989747818" label="TabStripKeyboardFocus:disabled"/>
@@ -56564,6 +56571,7 @@
   <int value="-1823073826" label="TabGroupsSave:disabled"/>
   <int value="-1822825246" label="DragFromShelfToHomeOrOverview:enabled"/>
   <int value="-1821058653" label="enable-delay-agnostic-aec"/>
+  <int value="-1819497481" label="TouchTextEditingRedesign:disabled"/>
   <int value="-1818947212" label="OutOfBlinkCors:disabled"/>
   <int value="-1818565030"
       label="AutofillUseConsistentPopupSettingsIcons:disabled"/>
@@ -58398,6 +58406,7 @@
   <int value="-714710496" label="VideoFullscreenOrientationLock:disabled"/>
   <int value="-714543772" label="enable-gpu-service-logging"/>
   <int value="-714043324" label="OutOfBlinkCORS:enabled"/>
+  <int value="-713770286" label="VmPerBootShaderCache:enabled"/>
   <int value="-713705575" label="PhoneHubCallNotification:enabled"/>
   <int value="-713136799" label="NearbySharingOnePageOnboarding:disabled"/>
   <int value="-713104676"
@@ -59110,6 +59119,7 @@
   <int value="-265697837" label="PhoneHub:disabled"/>
   <int value="-263645996" label="InteractiveWindowCycleList:enabled"/>
   <int value="-263150202" label="BundledConnectionHelp:disabled"/>
+  <int value="-262768194" label="TouchTextEditingRedesign:enabled"/>
   <int value="-262368430" label="PersistShareHubOnAppSwitch:enabled"/>
   <int value="-262122630" label="ArcEnableDocumentsProviderInFilesApp:enabled"/>
   <int value="-261398170" label="ChromeLabs:enabled"/>
@@ -59553,6 +59563,7 @@
       label="AutofillEnableUpdateVirtualCardEnrollment:enabled"/>
   <int value="12016364" label="OmniboxBubbleUrlSuggestions:enabled"/>
   <int value="15614295" label="Portals:enabled"/>
+  <int value="18571458" label="VmPerBootShaderCache:disabled"/>
   <int value="19629326" label="OmniboxExperimentalKeywordMode:enabled"/>
   <int value="19780991" label="CrosLanguageSettingsUpdateJapanese:enabled"/>
   <int value="19815558" label="EnableSettingsShortcutSearch:disabled"/>
@@ -60338,6 +60349,7 @@
   <int value="504994663" label="GenericSensor:disabled"/>
   <int value="505381354" label="FastCheckout:enabled"/>
   <int value="505561325" label="OpenXR:disabled"/>
+  <int value="505804530" label="SyncAccessHandleAllSyncSurface:disabled"/>
   <int value="506015849" label="OmniboxFuzzyUrlSuggestions:disabled"/>
   <int value="506680761" label="WebNFC:disabled"/>
   <int value="508272289" label="SharedHighlightingAmp:disabled"/>
@@ -61518,6 +61530,7 @@
   <int value="1235940786" label="ChromeHomePersistentIph:enabled"/>
   <int value="1236772382" label="BiometricAuthenticationInSettings:disabled"/>
   <int value="1237297772" label="no-pings"/>
+  <int value="1237574783" label="SyncAccessHandleAllSyncSurface:enabled"/>
   <int value="1237659269"
       label="OmniboxHistoryQuickProviderAllowButDoNotScoreMidwordTerms:enabled"/>
   <int value="1238190462" label="PerDeskShelf:disabled"/>
@@ -62685,6 +62698,7 @@
   <int value="1978548617" label="FilesZipMount:enabled"/>
   <int value="1978570295" label="RawDraw:disabled"/>
   <int value="1979222611" label="XRSandbox:disabled"/>
+  <int value="1979252604" label="ShareCrowLaunchTab:disabled"/>
   <int value="1979472169" label="TabGroupsFeedback:disabled"/>
   <int value="1979536751" label="lacros-availability-policy"/>
   <int value="1980011075" label="debug-packed-apps"/>
diff --git a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
index 10dbfbb..3a191c0 100644
--- a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
+++ b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
@@ -361,6 +361,16 @@
   </summary>
 </histogram>
 
+<histogram name="CustomTabs.ResizeType" enum="CustomTabsResizeType"
+    expires_after="2022-12-15">
+  <owner>kgrosu@google.com</owner>
+  <owner>chrome-connective-tissue@google.com</owner>
+  <summary>
+    When a Partial Custom Tab has been resized by the user log if it is an
+    expansion or a minimization of the tab.
+  </summary>
+</histogram>
+
 <histogram
     name="CustomTabs.RetainableSessions.TimeBetweenLaunch{IdentifierType}"
     units="seconds" expires_after="2022-11-03">
diff --git a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
index 74acb37..dbeb98e 100644
--- a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
+++ b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
@@ -1975,7 +1975,7 @@
 
 <histogram
     name="SafeBrowsing.TailoredSecurity.ConsentedDesktopDialogDisabledOutcome"
-    enum="SafeBrowsingTailoredSecurityOutcome" expires_after="2022-10-01">
+    enum="SafeBrowsingTailoredSecurityOutcome" expires_after="2023-02-12">
   <owner>jacastro@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
diff --git a/ui/accessibility/ax_node.cc b/ui/accessibility/ax_node.cc
index 1bebc3e1..1077ffd6 100644
--- a/ui/accessibility/ax_node.cc
+++ b/ui/accessibility/ax_node.cc
@@ -106,7 +106,7 @@
     DCHECK_EQ(index, 0u)
         << "A node cannot be hosting both a child tree and other nodes as "
            "children.";
-    return child_tree_manager->GetRootAsAXNode();
+    return child_tree_manager->GetRoot();
   }
 
   return GetChildAtIndex(index);
@@ -136,7 +136,7 @@
         << "A node cannot be hosting both a child tree and other nodes as "
            "children.";
     // A child tree is never ignored.
-    return child_tree_manager->GetRootAsAXNode();
+    return child_tree_manager->GetRoot();
   }
 
   return GetUnignoredChildAtIndex(index);
@@ -216,7 +216,7 @@
 
   const AXTreeManager* child_tree_manager = AXTreeManager::ForChildTree(*this);
   if (child_tree_manager)
-    return child_tree_manager->GetRootAsAXNode();
+    return child_tree_manager->GetRoot();
 
   return ComputeFirstUnignoredChildRecursive();
 }
@@ -247,7 +247,7 @@
 
   const AXTreeManager* child_tree_manager = AXTreeManager::ForChildTree(*this);
   if (child_tree_manager)
-    return child_tree_manager->GetRootAsAXNode();
+    return child_tree_manager->GetRoot();
 
   return ComputeLastUnignoredChildRecursive();
 }
@@ -960,7 +960,7 @@
     const AXTreeManager* child_tree_manager =
         AXTreeManager::ForChildTree(*this);
     if (child_tree_manager)
-      node = child_tree_manager->GetRootAsAXNode();
+      node = child_tree_manager->GetRoot();
   }
 
   return node->GetStringAttribute(ax::mojom::StringAttribute::kName);
diff --git a/ui/accessibility/ax_node_position_unittest.cc b/ui/accessibility/ax_node_position_unittest.cc
index 07cc05b..1841575 100644
--- a/ui/accessibility/ax_node_position_unittest.cc
+++ b/ui/accessibility/ax_node_position_unittest.cc
@@ -7857,7 +7857,7 @@
       AXNodePosition::BEFORE_TEXT /* child_index */);
   ASSERT_NE(nullptr, tree_position);
   TestPositionType ancestor_position = tree_position->CreateAncestorPosition(
-      GetRootAsAXNode(), ax::mojom::MoveDirection::kForward);
+      GetRoot(), ax::mojom::MoveDirection::kForward);
   ASSERT_NE(nullptr, ancestor_position);
   EXPECT_TRUE(ancestor_position->IsTreePosition());
   EXPECT_EQ(root_1.id, ancestor_position->anchor_id());
@@ -7874,7 +7874,7 @@
       AXNodePosition::BEFORE_TEXT /* child_index */);
   ASSERT_NE(nullptr, tree_position);
   ancestor_position = tree_position->CreateAncestorPosition(
-      GetRootAsAXNode(), ax::mojom::MoveDirection::kBackward);
+      GetRoot(), ax::mojom::MoveDirection::kBackward);
   ASSERT_NE(nullptr, ancestor_position);
   EXPECT_TRUE(ancestor_position->IsTreePosition());
   EXPECT_EQ(root_1.id, ancestor_position->anchor_id());
@@ -7890,7 +7890,7 @@
       GetTreeID(), inline_box_4.id, 0 /* child_index */);
   ASSERT_NE(nullptr, tree_position);
   ancestor_position = tree_position->CreateAncestorPosition(
-      GetRootAsAXNode(), ax::mojom::MoveDirection::kForward);
+      GetRoot(), ax::mojom::MoveDirection::kForward);
   ASSERT_NE(nullptr, ancestor_position);
   EXPECT_TRUE(ancestor_position->IsTreePosition());
   EXPECT_EQ(root_1.id, ancestor_position->anchor_id());
@@ -7905,7 +7905,7 @@
       GetTreeID(), inline_box_4.id, 0 /* child_index */);
   ASSERT_NE(nullptr, tree_position);
   ancestor_position = tree_position->CreateAncestorPosition(
-      GetRootAsAXNode(), ax::mojom::MoveDirection::kBackward);
+      GetRoot(), ax::mojom::MoveDirection::kBackward);
   ASSERT_NE(nullptr, ancestor_position);
   EXPECT_TRUE(ancestor_position->IsTreePosition());
   EXPECT_EQ(root_1.id, ancestor_position->anchor_id());
@@ -7920,7 +7920,7 @@
       GetTreeID(), inline_box_7.id, 0 /* child_index */);
   ASSERT_NE(nullptr, tree_position);
   ancestor_position = tree_position->CreateAncestorPosition(
-      GetRootAsAXNode(), ax::mojom::MoveDirection::kForward);
+      GetRoot(), ax::mojom::MoveDirection::kForward);
   ASSERT_NE(nullptr, ancestor_position);
   EXPECT_TRUE(ancestor_position->IsTreePosition());
   EXPECT_EQ(root_1.id, ancestor_position->anchor_id());
@@ -7936,7 +7936,7 @@
       GetTreeID(), inline_box_7.id, 0 /* child_index */);
   ASSERT_NE(nullptr, tree_position);
   ancestor_position = tree_position->CreateAncestorPosition(
-      GetRootAsAXNode(), ax::mojom::MoveDirection::kBackward);
+      GetRoot(), ax::mojom::MoveDirection::kBackward);
   ASSERT_NE(nullptr, ancestor_position);
   EXPECT_TRUE(ancestor_position->IsTreePosition());
   EXPECT_EQ(root_1.id, ancestor_position->anchor_id());
@@ -7957,7 +7957,7 @@
       ax::mojom::TextAffinity::kDownstream);
   ASSERT_NE(nullptr, text_position);
   ancestor_position = text_position->CreateAncestorPosition(
-      GetRootAsAXNode(), ax::mojom::MoveDirection::kForward);
+      GetRoot(), ax::mojom::MoveDirection::kForward);
   ASSERT_NE(nullptr, ancestor_position);
   EXPECT_TRUE(ancestor_position->IsTextPosition());
   EXPECT_EQ(root_1.id, ancestor_position->anchor_id());
@@ -7976,7 +7976,7 @@
       ax::mojom::TextAffinity::kDownstream);
   ASSERT_NE(nullptr, text_position);
   ancestor_position = text_position->CreateAncestorPosition(
-      GetRootAsAXNode(), ax::mojom::MoveDirection::kBackward);
+      GetRoot(), ax::mojom::MoveDirection::kBackward);
   ASSERT_NE(nullptr, ancestor_position);
   EXPECT_TRUE(ancestor_position->IsTextPosition());
   EXPECT_EQ(root_1.id, ancestor_position->anchor_id());
@@ -7995,7 +7995,7 @@
       ax::mojom::TextAffinity::kDownstream);
   ASSERT_NE(nullptr, text_position);
   ancestor_position = text_position->CreateAncestorPosition(
-      GetRootAsAXNode(), ax::mojom::MoveDirection::kForward);
+      GetRoot(), ax::mojom::MoveDirection::kForward);
   ASSERT_NE(nullptr, ancestor_position);
   EXPECT_TRUE(ancestor_position->IsTextPosition());
   EXPECT_EQ(root_1.id, ancestor_position->anchor_id());
@@ -8013,7 +8013,7 @@
       ax::mojom::TextAffinity::kDownstream);
   ASSERT_NE(nullptr, text_position);
   ancestor_position = text_position->CreateAncestorPosition(
-      GetRootAsAXNode(), ax::mojom::MoveDirection::kBackward);
+      GetRoot(), ax::mojom::MoveDirection::kBackward);
   ASSERT_NE(nullptr, ancestor_position);
   EXPECT_TRUE(ancestor_position->IsTextPosition());
   EXPECT_EQ(root_1.id, ancestor_position->anchor_id());
@@ -8031,7 +8031,7 @@
       ax::mojom::TextAffinity::kDownstream);
   ASSERT_NE(nullptr, text_position);
   ancestor_position = text_position->CreateAncestorPosition(
-      GetRootAsAXNode(), ax::mojom::MoveDirection::kForward);
+      GetRoot(), ax::mojom::MoveDirection::kForward);
   ASSERT_NE(nullptr, ancestor_position);
   EXPECT_TRUE(ancestor_position->IsTextPosition());
   EXPECT_EQ(root_1.id, ancestor_position->anchor_id());
@@ -8049,7 +8049,7 @@
       ax::mojom::TextAffinity::kDownstream);
   ASSERT_NE(nullptr, text_position);
   ancestor_position = text_position->CreateAncestorPosition(
-      GetRootAsAXNode(), ax::mojom::MoveDirection::kBackward);
+      GetRoot(), ax::mojom::MoveDirection::kBackward);
   ASSERT_NE(nullptr, ancestor_position);
   EXPECT_TRUE(ancestor_position->IsTextPosition());
   EXPECT_EQ(root_1.id, ancestor_position->anchor_id());
diff --git a/ui/accessibility/ax_node_unittest.cc b/ui/accessibility/ax_node_unittest.cc
index 9dd6024..71308b4 100644
--- a/ui/accessibility/ax_node_unittest.cc
+++ b/ui/accessibility/ax_node_unittest.cc
@@ -374,10 +374,10 @@
   auto tree_2 = std::make_unique<AXTree>(initial_state_2);
   TestAXTreeManager tree_manager_2(std::move(tree_2));
 
-  const AXNode* root_node_1 = tree_manager_1.GetRootAsAXNode();
+  const AXNode* root_node_1 = tree_manager_1.GetRoot();
   ASSERT_EQ(root_1.id, root_node_1->id());
 
-  const AXNode* root_node_2 = tree_manager_2.GetRootAsAXNode();
+  const AXNode* root_node_2 = tree_manager_2.GetRoot();
   ASSERT_EQ(root_2.id, root_node_2->id());
 
   EXPECT_EQ(0u, root_node_1->GetChildCount());
diff --git a/ui/accessibility/ax_range_unittest.cc b/ui/accessibility/ax_range_unittest.cc
index 6501f20..c66f2e6a 100644
--- a/ui/accessibility/ax_range_unittest.cc
+++ b/ui/accessibility/ax_range_unittest.cc
@@ -1606,10 +1606,10 @@
 TEST_F(AXRangeTest, GetRectsOffscreen) {
   // Set up root node bounds/viewport size  to {0, 50, 800x60}, so that only
   // some text will be onscreen the rest will be offscreen.
-  AXNodeData old_root_node_data = GetRootAsAXNode()->data();
+  AXNodeData old_root_node_data = GetRoot()->data();
   AXNodeData new_root_node_data = old_root_node_data;
   new_root_node_data.relative_bounds.bounds = gfx::RectF(0, 50, 800, 60);
-  GetRootAsAXNode()->SetData(new_root_node_data);
+  GetRoot()->SetData(new_root_node_data);
 
   TestAXRangeScreenRectDelegate delegate(this);
 
@@ -1647,7 +1647,7 @@
 
   // Reset the root node bounds/viewport size back to {0, 0, 800x600}, and
   // verify all elements should be onscreen.
-  GetRootAsAXNode()->SetData(old_root_node_data);
+  GetRoot()->SetData(old_root_node_data);
   expected_screen_rects = {
       gfx::Rect(20, 20, 100, 30), gfx::Rect(120, 20, 30, 30),
       gfx::Rect(150, 20, 30, 30), gfx::Rect(20, 50, 30, 30),
diff --git a/ui/accessibility/ax_tree_fuzzer_util.cc b/ui/accessibility/ax_tree_fuzzer_util.cc
index ed27dc80..6a57707 100644
--- a/ui/accessibility/ax_tree_fuzzer_util.cc
+++ b/ui/accessibility/ax_tree_fuzzer_util.cc
@@ -215,8 +215,8 @@
                                                size_t node_count) {
   ui::AXTreeUpdate tree_update;
   std::set<ui::AXNodeID> updated_nodes;
-  RecursiveGenerateUpdate(tree_manager_.GetRootAsAXNode(), tree_update,
-                          fuzz_data, updated_nodes);
+  RecursiveGenerateUpdate(tree_manager_.GetRoot(), tree_update, fuzz_data,
+                          updated_nodes);
   return GetTree()->Unserialize(tree_update);
 }
 
diff --git a/ui/accessibility/ax_tree_manager.cc b/ui/accessibility/ax_tree_manager.cc
index 130be1c9..fa696df3 100644
--- a/ui/accessibility/ax_tree_manager.cc
+++ b/ui/accessibility/ax_tree_manager.cc
@@ -81,7 +81,7 @@
   return ax_tree_ ? ax_tree_->data().parent_tree_id : AXTreeIDUnknown();
 }
 
-AXNode* AXTreeManager::GetRootAsAXNode() const {
+AXNode* AXTreeManager::GetRoot() const {
   return ax_tree_ ? ax_tree_->root() : nullptr;
 }
 
diff --git a/ui/accessibility/ax_tree_manager.h b/ui/accessibility/ax_tree_manager.h
index 62ae882..ea80329e 100644
--- a/ui/accessibility/ax_tree_manager.h
+++ b/ui/accessibility/ax_tree_manager.h
@@ -50,7 +50,7 @@
   virtual AXTreeID GetParentTreeID() const;
 
   // Returns the AXNode that is at the root of the current tree.
-  AXNode* GetRootAsAXNode() const;
+  AXNode* GetRoot() const;
 
   // If this tree has a parent tree, returns the node in the parent tree that
   // hosts the current tree. Returns nullptr if this tree doesn't have a parent
diff --git a/ui/accessibility/platform/atk_util_auralinux_unittest.cc b/ui/accessibility/platform/atk_util_auralinux_unittest.cc
index 5cb64ef1..b3123e83 100644
--- a/ui/accessibility/platform/atk_util_auralinux_unittest.cc
+++ b/ui/accessibility/platform/atk_util_auralinux_unittest.cc
@@ -25,7 +25,7 @@
     Init(root);
 
     TestAXNodeWrapper* wrapper =
-        TestAXNodeWrapper::GetOrCreate(GetTree(), GetRootAsAXNode());
+        TestAXNodeWrapper::GetOrCreate(GetTree(), GetRoot());
     if (!wrapper)
       NOTREACHED();
     AXPlatformNodeAuraLinux::SetApplication(wrapper->ax_platform_node());
@@ -40,7 +40,7 @@
 
   void TearDown() override {
     TestAXNodeWrapper* wrapper =
-        TestAXNodeWrapper::GetOrCreate(GetTree(), GetRootAsAXNode());
+        TestAXNodeWrapper::GetOrCreate(GetTree(), GetRoot());
     if (!wrapper)
       NOTREACHED();
     g_object_unref(wrapper->ax_platform_node()->GetNativeViewAccessible());
@@ -78,7 +78,7 @@
   EXPECT_EQ(keyval_seen, 55);
 
   TestAXNodeWrapper* wrapper =
-      TestAXNodeWrapper::GetOrCreate(GetTree(), GetRootAsAXNode());
+      TestAXNodeWrapper::GetOrCreate(GetTree(), GetRoot());
   DCHECK(wrapper);
   AXMode prev_mode = wrapper->ax_platform_node()->ax_mode_;
   // Disables AX mode.
diff --git a/ui/accessibility/platform/ax_fragment_root_win_unittest.cc b/ui/accessibility/platform/ax_fragment_root_win_unittest.cc
index 43e1d30..89a8609 100644
--- a/ui/accessibility/platform/ax_fragment_root_win_unittest.cc
+++ b/ui/accessibility/platform/ax_fragment_root_win_unittest.cc
@@ -77,8 +77,8 @@
   ComPtr<IRawElementProviderSimple> button_raw_element_provider_simple =
       GetIRawElementProviderSimpleFromChildIndex(1);
 
-  AXNode* text1_node = GetRootAsAXNode()->children()[0];
-  AXNode* button_node = GetRootAsAXNode()->children()[1];
+  AXNode* text1_node = GetRoot()->children()[0];
+  AXNode* button_node = GetRoot()->children()[1];
 
   ComPtr<IItemContainerProvider> item_container_provider;
   EXPECT_HRESULT_SUCCEEDED(root_raw_element_provider_simple->GetPatternProvider(
@@ -92,7 +92,7 @@
   // When |start_after_element| is an invalid element, we should fail at finding
   // the item.
   {
-    unique_id = AXPlatformNodeFromNode(GetRootAsAXNode())->GetUniqueId();
+    unique_id = AXPlatformNodeFromNode(GetRoot())->GetUniqueId();
     unique_id_variant.Set(
         SysAllocString(base::NumberToWString(-unique_id).c_str()));
 
@@ -112,7 +112,7 @@
   // Fetch the AxUniqueId of "root", and verify we can retrieve its
   // corresponding IRawElementProviderSimple through FindItemByProperty().
   {
-    unique_id = AXPlatformNodeFromNode(GetRootAsAXNode())->GetUniqueId();
+    unique_id = AXPlatformNodeFromNode(GetRoot())->GetUniqueId();
     unique_id_variant.Set(
         SysAllocString(base::NumberToWString(-unique_id).c_str()));
 
@@ -297,7 +297,7 @@
   Init(root_data, element1_data, element2_data);
   InitFragmentRoot();
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   AXNode* element1_node = root_node->children()[0];
   AXNode* element2_node = root_node->children()[1];
 
@@ -345,7 +345,7 @@
   Init(root_data, element1_data, element2_data);
   InitFragmentRoot();
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   AXNode* element1_node = root_node->children()[0];
   AXNode* element2_node = root_node->children()[1];
 
@@ -434,7 +434,7 @@
   InitFragmentRoot();
 
   gfx::NativeViewAccessible native_view_accessible =
-      AXPlatformNodeFromNode(GetRootAsAXNode())->GetNativeViewAccessible();
+      AXPlatformNodeFromNode(GetRoot())->GetNativeViewAccessible();
   AXPlatformNodeDelegate* fragment_root = ax_fragment_root_.get();
   EXPECT_EQ(native_view_accessible, fragment_root->ChildAtIndex(0));
   EXPECT_EQ(nullptr, fragment_root->ChildAtIndex(1));
@@ -454,7 +454,7 @@
   EXPECT_EQ(nullptr, fragment_root->GetParent());
 
   gfx::NativeViewAccessible native_view_accessible =
-      AXPlatformNodeFromNode(GetRootAsAXNode())->GetNativeViewAccessible();
+      AXPlatformNodeFromNode(GetRoot())->GetNativeViewAccessible();
   test_fragment_root_delegate_->parent_ = native_view_accessible;
   EXPECT_EQ(native_view_accessible, fragment_root->GetParent());
 }
@@ -568,7 +568,7 @@
   Init(update);
   InitFragmentRoot();
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
 
   // Set up other fragment roots
   AXNode* child_fragment_root_n3_node = root_node->children()[1];
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
index 597d596..d846efb 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
@@ -55,7 +55,7 @@
   }
 
   AXPlatformNodeAuraLinux* GetRootPlatformNode() {
-    return GetPlatformNode(GetRootAsAXNode());
+    return GetPlatformNode(GetRoot());
   }
 
   AtkObject* AtkObjectFromNode(AXNode* node) {
@@ -67,10 +67,10 @@
   }
 
   TestAXNodeWrapper* GetRootWrapper() {
-    return TestAXNodeWrapper::GetOrCreate(GetTree(), GetRootAsAXNode());
+    return TestAXNodeWrapper::GetOrCreate(GetTree(), GetRoot());
   }
 
-  AtkObject* GetRootAtkObject() { return AtkObjectFromNode(GetRootAsAXNode()); }
+  AtkObject* GetRootAtkObject() { return AtkObjectFromNode(GetRoot()); }
 
   // If we were compiled with a newer version of ATK than the runtime version,
   // it's possible that the state we want to expose and/or emit an event for
@@ -328,9 +328,9 @@
   child.id = 2;
 
   Init(root, child);
-  AXNode* child_node = GetRootAsAXNode()->children()[0];
+  AXNode* child_node = GetRoot()->children()[0];
 
-  AtkObject* root_obj(AtkObjectFromNode(GetRootAsAXNode()));
+  AtkObject* root_obj(AtkObjectFromNode(GetRoot()));
   ASSERT_TRUE(ATK_IS_OBJECT(root_obj));
   g_object_ref(root_obj);
   EXPECT_EQ(ATK_ROLE_APPLICATION, atk_object_get_role(root_obj));
@@ -449,7 +449,7 @@
   root.AddBoolAttribute(ax::mojom::BoolAttribute::kBusy, true);
   root.SetInvalidState(ax::mojom::InvalidState::kTrue);
   root.AddStringAttribute(ax::mojom::StringAttribute::kAutoComplete, "foo");
-  GetRootAsAXNode()->SetData(root);
+  GetRoot()->SetData(root);
 
   state_set = atk_object_ref_state_set(root_obj);
   ASSERT_TRUE(ATK_IS_STATE_SET(state_set));
@@ -476,7 +476,7 @@
   root.AddState(ax::mojom::State::kVisited);
   root.AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
   root.SetHasPopup(ax::mojom::HasPopup::kTrue);
-  GetRootAsAXNode()->SetData(root);
+  GetRoot()->SetData(root);
 
   state_set = atk_object_ref_state_set(root_obj);
   ASSERT_TRUE(ATK_IS_STATE_SET(state_set));
@@ -498,7 +498,7 @@
   root.id = 1;
   root.AddState(ax::mojom::State::kInvisible);
   root.AddBoolAttribute(ax::mojom::BoolAttribute::kModal, true);
-  GetRootAsAXNode()->SetData(root);
+  GetRoot()->SetData(root);
 
   state_set = atk_object_ref_state_set(root_obj);
   ASSERT_TRUE(ATK_IS_STATE_SET(state_set));
@@ -525,8 +525,8 @@
   checkbox.id = 3;
 
   Init(root, button, checkbox);
-  AXNode* button_node = GetRootAsAXNode()->children()[0];
-  AXNode* checkbox_node = GetRootAsAXNode()->children()[1];
+  AXNode* button_node = GetRoot()->children()[0];
+  AXNode* checkbox_node = GetRoot()->children()[1];
   AtkObject* root_obj = GetRootAtkObject();
   AtkObject* button_obj = AtkObjectFromNode(button_node);
   AtkObject* checkbox_obj = AtkObjectFromNode(checkbox_node);
@@ -613,7 +613,7 @@
 
   Init(root_data);
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   AtkObject* root_atk_object(AtkObjectFromNode(root_node));
   ASSERT_TRUE(ATK_IS_OBJECT(root_atk_object));
   g_object_ref(root_atk_object);
@@ -648,7 +648,7 @@
 
   Init(root_data);
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   AtkObject* root_atk_object(AtkObjectFromNode(root_node));
   ASSERT_TRUE(ATK_IS_OBJECT(root_atk_object));
   g_object_ref(root_atk_object);
@@ -675,7 +675,7 @@
   root_data.id = 1;
   Init(root_data);
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   AtkObject* root_atk_object(AtkObjectFromNode(root_node));
   ASSERT_TRUE(ATK_IS_OBJECT(root_atk_object));
   g_object_ref(root_atk_object);
@@ -818,7 +818,7 @@
   EXPECT_EQ(800, width);
   EXPECT_EQ(600, height);
 
-  AXNode* child_node = GetRootAsAXNode()->children()[0];
+  AXNode* child_node = GetRoot()->children()[0];
   AtkObject* child_obj = AtkObjectFromNode(child_node);
   ASSERT_TRUE(ATK_IS_OBJECT(child_obj));
   ASSERT_TRUE(ATK_IS_COMPONENT(child_obj));
@@ -900,7 +900,7 @@
 
   Init(root, child1);
 
-  AXNode* child_node = GetRootAsAXNode()->children()[0];
+  AXNode* child_node = GetRoot()->children()[0];
   AtkObject* child_obj = AtkObjectFromNode(child_node);
   ASSERT_TRUE(ATK_IS_OBJECT(child_obj));
   ASSERT_TRUE(ATK_IS_COMPONENT(child_obj));
@@ -963,7 +963,7 @@
 
   Init(root, child1);
 
-  AXNode* child_node = GetRootAsAXNode()->children()[0];
+  AXNode* child_node = GetRoot()->children()[0];
   AtkObject* child_obj = AtkObjectFromNode(child_node);
   ASSERT_TRUE(ATK_IS_OBJECT(child_obj));
   ASSERT_TRUE(ATK_IS_COMPONENT(child_obj));
@@ -1077,7 +1077,7 @@
   ASSERT_TRUE(ATK_IS_OBJECT(root_obj));
   ASSERT_TRUE(ATK_IS_ACTION(root_obj));
   g_object_ref(root_obj);
-  auto* root_node = GetRootAsAXNode();
+  auto* root_node = GetRoot();
 
   EXPECT_TRUE(atk_action_do_action(ATK_ACTION(root_obj), 0));
   EXPECT_EQ(root_node, TestAXNodeWrapper::GetNodeFromLastDefaultAction());
@@ -1277,7 +1277,7 @@
   ASSERT_TRUE(ATK_IS_HYPERLINK_IMPL(root_obj));
   ASSERT_TRUE(ATK_IS_ACTION(root_obj));
   g_object_ref(root_obj);
-  auto* root_node = GetRootAsAXNode();
+  auto* root_node = GetRoot();
 
   gint number_of_actions = atk_action_get_n_actions(ATK_ACTION(root_obj));
   EXPECT_EQ(2, number_of_actions);
@@ -1807,7 +1807,7 @@
 
   EXPECT_TRUE(ATK_IS_WINDOW(root_atk_object));
 
-  AXNode* checkbox_node = GetRootAsAXNode()->children()[0];
+  AXNode* checkbox_node = GetRoot()->children()[0];
   AtkObject* checkbox_atk_obj = AtkObjectFromNode(checkbox_node);
 
   // Focus the checkbox to ensure that it also gets new focus events when
@@ -1983,7 +1983,7 @@
 
   g_object_ref(root_atk_object);
 
-  AXNode* child_node = GetRootAsAXNode()->children()[0];
+  AXNode* child_node = GetRoot()->children()[0];
 
   // A focus event on a child node should not cause the window to
   // activate.
@@ -2051,7 +2051,7 @@
   EXPECT_TRUE(ATK_IS_OBJECT(root_atk_object));
   g_object_ref(root_atk_object);
 
-  AXNode* window_node = GetRootAsAXNode()->children()[0];
+  AXNode* window_node = GetRoot()->children()[0];
   AtkObject* window_atk_node(AtkObjectFromNode(window_node));
 
   AXNode* document_node = window_node->children()[0];
@@ -2076,7 +2076,7 @@
 
   toplevel_tester.Reset();
 
-  AXNode* menu_node = GetRootAsAXNode()->children()[1];
+  AXNode* menu_node = GetRoot()->children()[1];
   AtkObject* menu_atk_node(AtkObjectFromNode(menu_node));
   {
     ActivationTester tester(menu_atk_node);
@@ -2259,15 +2259,15 @@
   update.nodes[3].AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, 5);
   Init(update);
 
-  AXNode* radiobutton1 = GetRootAsAXNode()->children()[0];
+  AXNode* radiobutton1 = GetRoot()->children()[0];
   AtkObject* radiobutton1_atk_object(AtkObjectFromNode(radiobutton1));
   EXPECT_TRUE(ATK_IS_OBJECT(radiobutton1_atk_object));
 
-  AXNode* radiobutton2 = GetRootAsAXNode()->children()[1];
+  AXNode* radiobutton2 = GetRoot()->children()[1];
   AtkObject* radiobutton2_atk_object(AtkObjectFromNode(radiobutton2));
   EXPECT_TRUE(ATK_IS_OBJECT(radiobutton2_atk_object));
 
-  AXNode* radiobutton3 = GetRootAsAXNode()->children()[2];
+  AXNode* radiobutton3 = GetRoot()->children()[2];
   AtkObject* radiobutton3_atk_object(AtkObjectFromNode(radiobutton3));
   EXPECT_TRUE(ATK_IS_OBJECT(radiobutton3_atk_object));
 
@@ -2336,9 +2336,9 @@
   EXPECT_TRUE(ATK_IS_OBJECT(root_atk_object));
   g_object_ref(root_atk_object);
 
-  AtkObject* atk_child1(AtkObjectFromNode(GetRootAsAXNode()->children()[0]));
-  AtkObject* atk_child2(AtkObjectFromNode(GetRootAsAXNode()->children()[1]));
-  AtkObject* atk_child3(AtkObjectFromNode(GetRootAsAXNode()->children()[2]));
+  AtkObject* atk_child1(AtkObjectFromNode(GetRoot()->children()[0]));
+  AtkObject* atk_child2(AtkObjectFromNode(GetRoot()->children()[1]));
+  AtkObject* atk_child3(AtkObjectFromNode(GetRoot()->children()[2]));
 
 #if defined(ATK_226)
   // Runtime check in case we were compiled with a newer version of ATK.
@@ -2387,7 +2387,7 @@
     Init(root_data, child_data);
 
     AtkObject* source(GetRootAtkObject());
-    AtkObject* target(AtkObjectFromNode(GetRootAsAXNode()->children()[0]));
+    AtkObject* target(AtkObjectFromNode(GetRoot()->children()[0]));
 
     AtkRelationSet* relations = atk_object_ref_relation_set(source);
     ASSERT_TRUE(atk_relation_set_contains(relations, expected_relation));
@@ -2499,12 +2499,12 @@
   EXPECT_TRUE(ATK_IS_OBJECT(root_atk_object));
   g_object_ref(root_atk_object);
 
-  AtkObject* atk_label1(AtkObjectFromNode(GetRootAsAXNode()->children()[0]));
-  AtkObject* atk_label2(AtkObjectFromNode(GetRootAsAXNode()->children()[1]));
-  AtkObject* atk_label3(AtkObjectFromNode(GetRootAsAXNode()->children()[2]));
-  AtkObject* atk_button1(AtkObjectFromNode(GetRootAsAXNode()->children()[3]));
-  AtkObject* atk_button2(AtkObjectFromNode(GetRootAsAXNode()->children()[4]));
-  AtkObject* atk_button3(AtkObjectFromNode(GetRootAsAXNode()->children()[5]));
+  AtkObject* atk_label1(AtkObjectFromNode(GetRoot()->children()[0]));
+  AtkObject* atk_label2(AtkObjectFromNode(GetRoot()->children()[1]));
+  AtkObject* atk_label3(AtkObjectFromNode(GetRoot()->children()[2]));
+  AtkObject* atk_button1(AtkObjectFromNode(GetRoot()->children()[3]));
+  AtkObject* atk_button2(AtkObjectFromNode(GetRoot()->children()[4]));
+  AtkObject* atk_button3(AtkObjectFromNode(GetRoot()->children()[5]));
 
   test_index(atk_button1, atk_label1, ATK_RELATION_LABELLED_BY, 0);
   test_index(atk_button1, atk_label2, ATK_RELATION_LABELLED_BY, 1);
@@ -2710,7 +2710,7 @@
   root_data = AXNodeData();
   root_data.id = 1;
   root_data.role = ax::mojom::Role::kListBox;
-  GetRootAsAXNode()->SetData(root_data);
+  GetRoot()->SetData(root_data);
 
   ASSERT_EQ(original_atk_object, GetRootAtkObject());
 
@@ -2735,7 +2735,7 @@
   root_data.role = ax::mojom::Role::kTextField;
   Init(root_data);
 
-  AXNode* root = GetRootAsAXNode();
+  AXNode* root = GetRoot();
   AtkObject* atk_object = AtkObjectFromNode(root);
   AXPlatformNodeAuraLinux* node = GetPlatformNode(root);
 
@@ -2783,7 +2783,7 @@
 
   Init(root_data, item_1_data);
 
-  AXNode* item_1 = GetRootAsAXNode()->children()[0];
+  AXNode* item_1 = GetRoot()->children()[0];
   AtkObject* atk_object = AtkObjectFromNode(item_1);
   AXPlatformNodeAuraLinux* node = GetPlatformNode(item_1);
 
@@ -2812,7 +2812,7 @@
 
   Init(root_data, item_1_data);
 
-  AXNode* item_1 = GetRootAsAXNode()->children()[0];
+  AXNode* item_1 = GetRoot()->children()[0];
   AtkObject* atk_object = AtkObjectFromNode(item_1);
 
   bool saw_caret_moved = false;
@@ -2853,7 +2853,7 @@
   AtkObject* root_atk_object(GetRootAtkObject());
   EXPECT_TRUE(ATK_IS_OBJECT(root_atk_object));
 
-  AXNode* dialog_node = GetRootAsAXNode()->children()[0];
+  AXNode* dialog_node = GetRoot()->children()[0];
   AtkObject* dialog_obj = AtkObjectFromNode(dialog_node);
   bool saw_active_state_change = false;
   g_signal_connect(dialog_obj, "state-change",
@@ -2872,7 +2872,7 @@
 
   saw_active_state_change = false;
 
-  AXNode* outside_node = GetRootAsAXNode()->children()[1];
+  AXNode* outside_node = GetRoot()->children()[1];
   GetPlatformNode(outside_node)
       ->NotifyAccessibilityEvent(ax::mojom::Event::kFocus);
   EXPECT_TRUE(saw_active_state_change);
@@ -2912,16 +2912,16 @@
 
   // Creates TestAXNodeWrapper for the first menu item to keep the current
   // active descendant.
-  AtkObjectFromNode(GetRootAsAXNode()->children()[1]->children()[0]);
+  AtkObjectFromNode(GetRoot()->children()[1]->children()[0]);
 
   // Sets focus to the input node.
-  AXNode* input_node = GetRootAsAXNode()->children()[0];
+  AXNode* input_node = GetRoot()->children()[0];
   GetPlatformNode(input_node)
       ->NotifyAccessibilityEvent(ax::mojom::Event::kFocus);
 
   bool saw_active_focus_state_change = false;
   AtkObject* menu_2_atk_object =
-      AtkObjectFromNode(GetRootAsAXNode()->children()[1]->children()[1]);
+      AtkObjectFromNode(GetRoot()->children()[1]->children()[1]);
   EXPECT_TRUE(ATK_IS_OBJECT(menu_2_atk_object));
   g_object_ref(menu_2_atk_object);
   // Registers callback to get focus event on |menu_2_atk_object|.
@@ -2934,7 +2934,7 @@
                    &saw_active_focus_state_change);
 
   // Updates the active descendant node from the node id 4 to the node id 5;
-  AXNode* menu_node = GetRootAsAXNode();
+  AXNode* menu_node = GetRoot();
   AXNodeData menu_new_data(menu);
   menu_new_data.AddIntAttribute(ax::mojom::IntAttribute::kActivedescendantId,
                                 5);
diff --git a/ui/accessibility/platform/ax_platform_node_textchildprovider_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_textchildprovider_win_unittest.cc
index 6caea7060..a579c4d 100644
--- a/ui/accessibility/platform/ax_platform_node_textchildprovider_win_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_textchildprovider_win_unittest.cc
@@ -79,7 +79,7 @@
 
     Init(update);
 
-    AXNode* root_node = GetRootAsAXNode();
+    AXNode* root_node = GetRoot();
     AXNode* nontext_child_of_root_node = root_node->children()[0];
     AXNode* text_child_of_root_node = root_node->children()[1];
     AXNode* nontext_child_of_nontext_node =
@@ -278,8 +278,8 @@
       nontext_child_of_root_text_child_provider_->get_TextRange(
           &text_range_provider));
   ASSERT_NE(nullptr, text_range_provider.Get());
-  AXPlatformNodeWin* owner = static_cast<AXPlatformNodeWin*>(
-      AXPlatformNodeFromNode(GetRootAsAXNode()));
+  AXPlatformNodeWin* owner =
+      static_cast<AXPlatformNodeWin*>(AXPlatformNodeFromNode(GetRoot()));
   ASSERT_NE(nullptr, owner);
   SetOwner(owner, text_range_provider.Get());
 
@@ -303,8 +303,8 @@
       text_child_of_root_text_child_provider_->get_TextRange(
           &text_range_provider));
   ASSERT_NE(nullptr, text_range_provider.Get());
-  AXPlatformNodeWin* owner = static_cast<AXPlatformNodeWin*>(
-      AXPlatformNodeFromNode(GetRootAsAXNode()));
+  AXPlatformNodeWin* owner =
+      static_cast<AXPlatformNodeWin*>(AXPlatformNodeFromNode(GetRoot()));
   ASSERT_NE(nullptr, owner);
   SetOwner(owner, text_range_provider.Get());
 
@@ -326,8 +326,8 @@
       nontext_child_of_nontext_text_child_provider_->get_TextRange(
           &text_range_provider));
   ASSERT_NE(nullptr, text_range_provider.Get());
-  AXPlatformNodeWin* owner = static_cast<AXPlatformNodeWin*>(
-      AXPlatformNodeFromNode(GetRootAsAXNode()));
+  AXPlatformNodeWin* owner =
+      static_cast<AXPlatformNodeWin*>(AXPlatformNodeFromNode(GetRoot()));
   ASSERT_NE(nullptr, owner);
   SetOwner(owner, text_range_provider.Get());
 
@@ -349,8 +349,8 @@
       text_child_of_nontext_text_child_provider_->get_TextRange(
           &text_range_provider));
   ASSERT_NE(nullptr, text_range_provider.Get());
-  AXPlatformNodeWin* owner = static_cast<AXPlatformNodeWin*>(
-      AXPlatformNodeFromNode(GetRootAsAXNode()));
+  AXPlatformNodeWin* owner =
+      static_cast<AXPlatformNodeWin*>(AXPlatformNodeFromNode(GetRoot()));
   ASSERT_NE(nullptr, owner);
   SetOwner(owner, text_range_provider.Get());
 
@@ -372,8 +372,8 @@
       text_child_of_text_text_child_provider_->get_TextRange(
           &text_range_provider));
   ASSERT_NE(nullptr, text_range_provider.Get());
-  AXPlatformNodeWin* owner = static_cast<AXPlatformNodeWin*>(
-      AXPlatformNodeFromNode(GetRootAsAXNode()));
+  AXPlatformNodeWin* owner =
+      static_cast<AXPlatformNodeWin*>(AXPlatformNodeFromNode(GetRoot()));
   ASSERT_NE(nullptr, owner);
   SetOwner(owner, text_range_provider.Get());
 
diff --git a/ui/accessibility/platform/ax_platform_node_textprovider_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_textprovider_win_unittest.cc
index eb0663f..46155ed 100644
--- a/ui/accessibility/platform/ax_platform_node_textprovider_win_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_textprovider_win_unittest.cc
@@ -92,7 +92,7 @@
   update.nodes = {root_data, link_data, text1_data, text2_data};
 
   Init(update);
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   AXNode* link_node = root_node->children()[0];
   AXNode* text2_node = link_node->children()[1];
   AXPlatformNodeWin* owner =
@@ -196,7 +196,7 @@
 
   Init(update);
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   AXNode* text_node = root_node->children()[0];
   AXNode* empty_text_node = root_node->children()[1];
   AXPlatformNodeWin* owner =
@@ -323,7 +323,7 @@
 
   Init(update);
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   AXNode* dialog_node = root_node->children()[0];
   AXPlatformNodeWin* owner =
       static_cast<AXPlatformNodeWin*>(AXPlatformNodeFromNode(root_node));
@@ -376,7 +376,7 @@
 
   Init(root_data, text_data);
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   AXNode* text_node = root_node->children()[0];
 
   struct NearestTextIndexTestData {
@@ -727,7 +727,7 @@
   selected_tree_data.sel_anchor_offset = 1;
   selected_tree_data.sel_focus_offset = 1;
 
-  AXNode* text_edit_node = GetRootAsAXNode()->children()[1];
+  AXNode* text_edit_node = GetRoot()->children()[1];
 
   ComPtr<IRawElementProviderSimple> text_edit_com =
       QueryInterfaceFromNode<IRawElementProviderSimple>(text_edit_node);
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
index e4c5eed..c21f3b85 100644
--- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
@@ -1434,7 +1434,7 @@
     const ui::AXTreeID tree_id) {
   const AXTreeManager* ax_tree_manager = AXTreeManager::FromID(tree_id);
   DCHECK(ax_tree_manager);
-  AXNode* root_node = ax_tree_manager->GetRootAsAXNode();
+  AXNode* root_node = ax_tree_manager->GetRoot();
   const AXPlatformNode* root_platform_node =
       GetOwner()->GetDelegate()->GetFromTreeIDAndNodeID(tree_id,
                                                         root_node->id());
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
index 9be764a..71112752 100644
--- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
@@ -1017,7 +1017,7 @@
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider,
-                                   GetRootAsAXNode()->children()[0]);
+                                   GetRoot()->children()[0]);
   EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"some text");
 
   ComPtr<ITextRangeProvider> text_range_provider_clone;
@@ -1047,7 +1047,7 @@
                          false /* build_word_boundaries_offsets */,
                          true /* place_text_on_one_line */));
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
 
   // Get the textRangeProvider for the document,
   // which contains text "some textmore text".
@@ -1128,7 +1128,7 @@
        TestITextRangeProviderExpandToEnclosingCharacter) {
   ui::AXTreeUpdate update = BuildTextDocument({"some text", "more text"});
   Init(update);
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider, root_node);
@@ -1208,7 +1208,7 @@
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider,
-                                   GetRootAsAXNode()->children()[1]);
+                                   GetRoot()->children()[1]);
   EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"definitely not text");
 
   // Start endpoint is already on a word's start boundary.
@@ -1256,7 +1256,7 @@
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider,
-                                   GetRootAsAXNode()->children()[0]);
+                                   GetRoot()->children()[0]);
   EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"line #1");
 
   // Start endpoint is already on a line's start boundary.
@@ -1301,7 +1301,7 @@
 TEST_F(AXPlatformNodeTextRangeProviderTest,
        TestITextRangeProviderExpandToEnclosingParagraph) {
   Init(BuildAXTreeForMove());
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider, root_node);
@@ -1365,7 +1365,7 @@
 TEST_F(AXPlatformNodeTextRangeProviderTest,
        TestITextRangeProviderExpandToEnclosingFormat) {
   Init(BuildAXTreeForMoveByFormat());
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider, root_node);
   ComPtr<AXPlatformNodeTextRangeProviderWin> text_range_provider_internal;
@@ -1644,7 +1644,7 @@
 
   Init(update);
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider, root_node);
 
@@ -1672,7 +1672,7 @@
        TestITextRangeProviderExpandToEnclosingDocument) {
   Init(BuildTextDocument({"some text", "more text", "even more text"}));
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   AXNode* text_node = root_node->children()[0];
   AXNode* more_text_node = root_node->children()[1];
   AXNode* even_more_text_node = root_node->children()[2];
@@ -1780,7 +1780,7 @@
 
   Init(update);
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider, root_node);
 
@@ -1808,7 +1808,7 @@
     Init(BuildTextDocument({}));
 
     ComPtr<ITextRangeProvider> text_range_provider;
-    GetTextRangeProviderFromTextNode(text_range_provider, GetRootAsAXNode());
+    GetTextRangeProviderFromTextNode(text_range_provider, GetRoot());
 
     DestroyTree();
     ComPtr<ITextRangeProvider> text_range_provider_clone;
@@ -1845,7 +1845,7 @@
     Init(BuildTextDocument({}));
 
     ComPtr<ITextRangeProvider> this_provider;
-    GetTextRangeProviderFromTextNode(this_provider, GetRootAsAXNode());
+    GetTextRangeProviderFromTextNode(this_provider, GetRoot());
 
     ComPtr<ITextRangeProvider> other_provider_different_type;
     MockAXPlatformNodeTextRangeProviderWin::CreateMockTextRangeProvider(
@@ -1869,7 +1869,7 @@
 TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderGetText) {
   Init(BuildTextDocument({"some text", "more text"}));
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   AXNode* text_node = root_node->children()[0];
 
   ComPtr<ITextRangeProvider> text_range_provider;
@@ -1919,7 +1919,7 @@
 TEST_F(AXPlatformNodeTextRangeProviderTest,
        TestITextRangeProviderMoveCharacter) {
   Init(BuildAXTreeForMove());
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider, root_node);
@@ -2003,7 +2003,7 @@
 
 TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderMoveFormat) {
   Init(BuildAXTreeForMoveByFormat());
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider, root_node);
@@ -2133,7 +2133,7 @@
 
 TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderMovePage) {
   Init(BuildAXTreeForMoveByPage());
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider, root_node);
@@ -2209,7 +2209,7 @@
 
 TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderMoveWord) {
   Init(BuildAXTreeForMove());
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider, root_node);
@@ -2300,7 +2300,7 @@
 
 TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderMoveLine) {
   Init(BuildAXTreeForMove());
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider, root_node);
@@ -2376,7 +2376,7 @@
 TEST_F(AXPlatformNodeTextRangeProviderTest,
        TestITextRangeProviderMoveParagraph) {
   Init(BuildAXTreeForMove());
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider, root_node);
@@ -2548,7 +2548,7 @@
 TEST_F(AXPlatformNodeTextRangeProviderTest,
        TestITextRangeProviderMoveDocument) {
   Init(BuildAXTreeForMove());
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider, root_node);
@@ -2599,7 +2599,7 @@
 
 TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderMove) {
   Init(BuildAXTreeForMove());
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider, root_node);
@@ -2610,7 +2610,7 @@
 TEST_F(AXPlatformNodeTextRangeProviderTest,
        TestITextRangeProviderMoveEndpointByDocument) {
   Init(BuildTextDocument({"some text", "more text", "even more text"}));
-  AXNode* text_node = GetRootAsAXNode()->children()[1];
+  AXNode* text_node = GetRoot()->children()[1];
 
   // Run the test twice, one for TextUnit_Document and once for TextUnit_Page,
   // since they should have identical behavior.
@@ -2692,7 +2692,7 @@
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider,
-                                   GetRootAsAXNode()->children()[0]);
+                                   GetRoot()->children()[0]);
 
   // Verify MoveEndpointByUnit with zero count has no effect
   EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"hey");
@@ -2789,7 +2789,7 @@
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider,
-                                   GetRootAsAXNode()->children()[1]);
+                                   GetRoot()->children()[1]);
   EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"more text");
 
   // Moving with zero count does not alter the range.
@@ -2886,7 +2886,7 @@
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider,
-                                   GetRootAsAXNode()->children()[3]);
+                                   GetRoot()->children()[3]);
   EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"3");
 
   // Moving with zero count does not alter the range.
@@ -3045,7 +3045,7 @@
   Init(update);
 
   // Set up variables from the tree for testing.
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   AXNode* text_node = root_node->children()[0]->children()[0];
 
   ComPtr<ITextRangeProvider> text_range_provider;
@@ -3123,7 +3123,7 @@
 TEST_F(AXPlatformNodeTextRangeProviderTest,
        TestITextRangeProviderMoveEndpointByFormat) {
   Init(BuildAXTreeForMoveByFormat());
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
 
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider, root_node);
@@ -3183,7 +3183,7 @@
 
 TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderCompare) {
   Init(BuildTextDocument({"some text", "some text"}));
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
 
   // Get the textRangeProvider for the document,
   // which contains text "some textsome text".
@@ -3226,7 +3226,7 @@
   Init(BuildTextDocument({"some text"}));
 
   ComPtr<ITextRangeProvider> text_range_provider;
-  GetTextRangeProviderFromTextNode(text_range_provider, GetRootAsAXNode());
+  GetTextRangeProviderFromTextNode(text_range_provider, GetRoot());
 
   ASSERT_UIA_INVALIDOPERATION(text_range_provider->AddToSelection());
   ASSERT_UIA_INVALIDOPERATION(text_range_provider->RemoveFromSelection());
@@ -3243,7 +3243,7 @@
   // Expected bounding rects:
   // <button>Button</button><input type="checkbox">Line 1<br>Line 2
   // |---------------------||---------------------||----|   |------|
-  GetTextRangeProviderFromTextNode(text_range_provider, GetRootAsAXNode());
+  GetTextRangeProviderFromTextNode(text_range_provider, GetRoot());
   EXPECT_HRESULT_SUCCEEDED(
       text_range_provider->GetBoundingRectangles(rectangles.Receive()));
   std::vector<double> expected_values = {20,  20, 200, 30, /* button */
@@ -3422,7 +3422,7 @@
   Init(update);
 
   // Set up variables from the tree for testing.
-  AXNode* paragraph_node = GetRootAsAXNode()->children()[0];
+  AXNode* paragraph_node = GetRoot()->children()[0];
   AXNode* static_text_node1 = paragraph_node->children()[0];
   AXNode* link_node = paragraph_node->children()[1];
   AXNode* inline_text_node1 = static_text_node1->children()[0];
@@ -3601,10 +3601,10 @@
   Init(update);
 
   // Set up variables from the tree for testing.
-  AXNode* button_1_node = GetRootAsAXNode()->children()[0];
+  AXNode* button_1_node = GetRoot()->children()[0];
   AXNode* static_text_1_node = button_1_node->children()[0];
   AXNode* inline_text_1_node = static_text_1_node->children()[0];
-  AXNode* button_2_node = GetRootAsAXNode()->children()[1];
+  AXNode* button_2_node = GetRoot()->children()[1];
   AXNode* heading_node = button_2_node->children()[0];
   AXNode* static_text_2_node = heading_node->children()[0];
   AXNode* inline_text_2_node = static_text_2_node->children()[0];
@@ -3659,7 +3659,7 @@
        TestITextRangeProviderMoveEndpointByRange) {
   Init(BuildTextDocument({"some text", "more text"}));
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   AXNode* text_node = root_node->children()[0];
   AXNode* more_text_node = root_node->children()[1];
   AXPlatformNodeWin* owner =
@@ -4115,7 +4115,7 @@
 
   Init(update);
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   AXNode* text_node = root_node->children()[0];
   AXNode* heading_node = root_node->children()[1];
   AXNode* heading_text_node = heading_node->children()[0];
@@ -4611,7 +4611,7 @@
 
   Init(update);
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   AXNode* annotation_target_node = root_node->children()[0];
   AXNode* comment1_node = root_node->children()[1];
   AXNode* comment2_node = root_node->children()[2];
@@ -4741,7 +4741,7 @@
 
   Init(update);
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   AXNode* highlighted_node = root_node->children()[0];
   AXNode* readonly_text_node = root_node->children()[1];
   AXNode* comment1_node = root_node->children()[2];
@@ -4848,7 +4848,7 @@
   Init(update);
 
   ComPtr<ITextRangeProvider> document_range_provider;
-  GetTextRangeProviderFromTextNode(document_range_provider, GetRootAsAXNode());
+  GetTextRangeProviderFromTextNode(document_range_provider, GetRoot());
 
   EXPECT_UIA_TEXTATTRIBUTE_NOTSUPPORTED(document_range_provider,
                                         UIA_AfterParagraphSpacingAttributeId);
@@ -4958,7 +4958,7 @@
 
 TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderSelect) {
   Init(BuildTextDocument({"some text", "more text2"}));
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
 
   // Text range for the document, which contains text "some textmore text2".
   ComPtr<IRawElementProviderSimple> root_node_raw =
@@ -5165,7 +5165,7 @@
   update.nodes = {root_data,   list_data,        list_item_data,
                   list_marker, static_text_data, list_item_text_data};
   Init(update);
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
 
   // Text range related to "1. ".
   AXNode* list_node = root_node->children()[0];
@@ -5196,7 +5196,7 @@
                          false /* build_word_boundaries_offsets */,
                          true /* place_text_on_one_line */));
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   AXPlatformNodeWin* owner =
       static_cast<AXPlatformNodeWin*>(AXPlatformNodeFromNode(root_node));
   ASSERT_NE(owner, nullptr);
@@ -5305,7 +5305,7 @@
 
   Init(update);
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   ComPtr<ITextRangeProvider> text_range_provider;
   GetTextRangeProviderFromTextNode(text_range_provider, root_node);
 
@@ -5331,7 +5331,7 @@
   Init(BuildTextDocument({"text", "some", "text"},
                          false /* build_word_boundaries_offsets */,
                          true /* place_text_on_one_line */));
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
 
   ComPtr<ITextRangeProvider> root_range_provider;
   GetTextRangeProviderFromTextNode(root_range_provider, root_node);
@@ -5405,8 +5405,7 @@
     V_VT(&is_hidden_attr_val) = VT_BOOL;
     ComPtr<ITextRangeProvider> matched_range_provider;
     ComPtr<ITextRangeProvider> document_range_provider;
-    GetTextRangeProviderFromTextNode(document_range_provider,
-                                     GetRootAsAXNode());
+    GetTextRangeProviderFromTextNode(document_range_provider, GetRoot());
 
     // Search forward, look for IsHidden=true.
     // Expected: nullptr
@@ -5494,8 +5493,7 @@
     V_VT(&is_hidden_attr_val) = VT_BOOL;
     ComPtr<ITextRangeProvider> matched_range_provider;
     ComPtr<ITextRangeProvider> document_range_provider;
-    GetTextRangeProviderFromTextNode(document_range_provider,
-                                     GetRootAsAXNode());
+    GetTextRangeProviderFromTextNode(document_range_provider, GetRoot());
 
     // Search forward, look for IsHidden=true.
     // Expected: "text1"
@@ -5583,8 +5581,7 @@
     V_VT(&is_hidden_attr_val) = VT_BOOL;
     ComPtr<ITextRangeProvider> matched_range_provider;
     ComPtr<ITextRangeProvider> document_range_provider;
-    GetTextRangeProviderFromTextNode(document_range_provider,
-                                     GetRootAsAXNode());
+    GetTextRangeProviderFromTextNode(document_range_provider, GetRoot());
 
     // Search forward, look for IsHidden=true.
     // Expected: nullptr
@@ -5693,8 +5690,7 @@
     V_VT(&is_hidden_attr_val) = VT_BOOL;
     ComPtr<ITextRangeProvider> matched_range_provider;
     ComPtr<ITextRangeProvider> document_range_provider;
-    GetTextRangeProviderFromTextNode(document_range_provider,
-                                     GetRootAsAXNode());
+    GetTextRangeProviderFromTextNode(document_range_provider, GetRoot());
 
     // Search forward, look for IsHidden=true.
     // Expected: "text2text3"
@@ -5811,8 +5807,7 @@
     V_VT(&is_hidden_attr_val) = VT_BOOL;
     ComPtr<ITextRangeProvider> matched_range_provider;
     ComPtr<ITextRangeProvider> document_range_provider;
-    GetTextRangeProviderFromTextNode(document_range_provider,
-                                     GetRootAsAXNode());
+    GetTextRangeProviderFromTextNode(document_range_provider, GetRoot());
 
     // Search forward, look for IsHidden=true.
     // Expected: "text2text3text4"
@@ -5875,7 +5870,7 @@
   Init(root_ax_node_data);
 
   ComPtr<IRawElementProviderSimple> raw_element_provider_simple =
-      QueryInterfaceFromNode<IRawElementProviderSimple>(GetRootAsAXNode());
+      QueryInterfaceFromNode<IRawElementProviderSimple>(GetRoot());
   ASSERT_NE(nullptr, raw_element_provider_simple.Get());
 
   ComPtr<ITextProvider> text_provider;
@@ -7126,7 +7121,7 @@
 
   Init(update);
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   AXNodePosition::AXPositionInstance range_start =
       AXNodePosition::CreateTreePosition(tree_data.tree_id,
                                          generic_container_2.id,
diff --git a/ui/accessibility/platform/ax_platform_node_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
index 8d8fe7f8..d09663b 100644
--- a/ui/accessibility/platform/ax_platform_node_win_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
@@ -311,20 +311,19 @@
 
 ComPtr<IRawElementProviderSimple>
 AXPlatformNodeWinTest::GetRootIRawElementProviderSimple() {
-  return QueryInterfaceFromNode<IRawElementProviderSimple>(GetRootAsAXNode());
+  return QueryInterfaceFromNode<IRawElementProviderSimple>(GetRoot());
 }
 
 ComPtr<IRawElementProviderSimple>
 AXPlatformNodeWinTest::GetIRawElementProviderSimpleFromChildIndex(
     int child_index) {
-  if (!GetRootAsAXNode() || child_index < 0 ||
-      static_cast<size_t>(child_index) >=
-          GetRootAsAXNode()->children().size()) {
+  if (!GetRoot() || child_index < 0 ||
+      static_cast<size_t>(child_index) >= GetRoot()->children().size()) {
     return ComPtr<IRawElementProviderSimple>();
   }
 
   return QueryInterfaceFromNode<IRawElementProviderSimple>(
-      GetRootAsAXNode()->children()[static_cast<size_t>(child_index)]);
+      GetRoot()->children()[static_cast<size_t>(child_index)]);
 }
 
 Microsoft::WRL::ComPtr<IRawElementProviderSimple>
@@ -337,7 +336,7 @@
 
 ComPtr<IRawElementProviderFragment>
 AXPlatformNodeWinTest::GetRootIRawElementProviderFragment() {
-  return QueryInterfaceFromNode<IRawElementProviderFragment>(GetRootAsAXNode());
+  return QueryInterfaceFromNode<IRawElementProviderFragment>(GetRoot());
 }
 
 Microsoft::WRL::ComPtr<IRawElementProviderFragment>
@@ -357,7 +356,7 @@
 }
 
 ComPtr<IAccessible> AXPlatformNodeWinTest::GetRootIAccessible() {
-  return IAccessibleFromNode(GetRootAsAXNode());
+  return IAccessibleFromNode(GetRoot());
 }
 
 ComPtr<IAccessible2> AXPlatformNodeWinTest::ToIAccessible2(
@@ -434,8 +433,8 @@
 
 void AXPlatformNodeWinTest::InitFragmentRoot() {
   test_fragment_root_delegate_ = std::make_unique<TestFragmentRootDelegate>();
-  ax_fragment_root_.reset(InitNodeAsFragmentRoot(
-      GetRootAsAXNode(), test_fragment_root_delegate_.get()));
+  ax_fragment_root_.reset(
+      InitNodeAsFragmentRoot(GetRoot(), test_fragment_root_delegate_.get()));
 }
 
 AXFragmentRootWin* AXPlatformNodeWinTest::InitNodeAsFragmentRoot(
@@ -511,7 +510,7 @@
   Init(root, row1, column_header, row_header);
 
   ComPtr<ITableProvider> root_itableprovider(
-      QueryInterfaceFromNode<ITableProvider>(GetRootAsAXNode()));
+      QueryInterfaceFromNode<ITableProvider>(GetRoot()));
 
   base::win::ScopedSafearray safearray;
   EXPECT_HRESULT_SUCCEEDED(
@@ -525,7 +524,7 @@
   // Remove column_header's native event target and verify it's no longer
   // returned.
   TestAXNodeWrapper* column_header_wrapper = TestAXNodeWrapper::GetOrCreate(
-      GetTree(), GetRootAsAXNode()->children()[0]->children()[0]);
+      GetTree(), GetRoot()->children()[0]->children()[0]);
   column_header_wrapper->ResetNativeEventTarget();
 
   safearray.Release();
@@ -1061,7 +1060,7 @@
   child.id = 2;
 
   Init(root, child);
-  AXNode* child_node = GetRootAsAXNode()->children()[0];
+  AXNode* child_node = GetRoot()->children()[0];
   ComPtr<IAccessible> child_iaccessible(IAccessibleFromNode(child_node));
 
   ScopedVariant role;
@@ -1136,8 +1135,8 @@
   checkbox.id = 3;
 
   Init(root, button, checkbox);
-  AXNode* button_node = GetRootAsAXNode()->children()[0];
-  AXNode* checkbox_node = GetRootAsAXNode()->children()[1];
+  AXNode* button_node = GetRoot()->children()[0];
+  AXNode* checkbox_node = GetRoot()->children()[1];
   ComPtr<IAccessible> root_iaccessible(GetRootIAccessible());
   ComPtr<IAccessible> button_iaccessible(IAccessibleFromNode(button_node));
   ComPtr<IAccessible> checkbox_iaccessible(IAccessibleFromNode(checkbox_node));
@@ -1238,10 +1237,10 @@
   ComPtr<IAccessible> root_iaccessible(GetRootIAccessible());
   ComPtr<IAccessible2> root_iaccessible2 = ToIAccessible2(root_iaccessible);
   ComPtr<IAccessible> left_iaccessible(
-      IAccessibleFromNode(GetRootAsAXNode()->children()[0]));
+      IAccessibleFromNode(GetRoot()->children()[0]));
   ComPtr<IAccessible2> left_iaccessible2 = ToIAccessible2(left_iaccessible);
   ComPtr<IAccessible> right_iaccessible(
-      IAccessibleFromNode(GetRootAsAXNode()->children()[1]));
+      IAccessibleFromNode(GetRoot()->children()[1]));
   ComPtr<IAccessible2> right_iaccessible2 = ToIAccessible2(right_iaccessible);
 
   LONG index;
@@ -1274,13 +1273,11 @@
   ComPtr<IDispatch> disp_root;
   ASSERT_HRESULT_SUCCEEDED(ia_root.As(&disp_root));
   ScopedVariant var_root(disp_root.Get());
-  ComPtr<IAccessible> ia_child1(
-      IAccessibleFromNode(GetRootAsAXNode()->children()[0]));
+  ComPtr<IAccessible> ia_child1(IAccessibleFromNode(GetRoot()->children()[0]));
   ComPtr<IDispatch> disp_child1;
   ASSERT_HRESULT_SUCCEEDED(ia_child1.As(&disp_child1));
   ScopedVariant var_child1(disp_child1.Get());
-  ComPtr<IAccessible> ia_child2(
-      IAccessibleFromNode(GetRootAsAXNode()->children()[1]));
+  ComPtr<IAccessible> ia_child2(IAccessibleFromNode(GetRoot()->children()[1]));
   ComPtr<IDispatch> disp_child2;
   ASSERT_HRESULT_SUCCEEDED(ia_child2.As(&disp_child2));
   ScopedVariant var_child2(disp_child2.Get());
@@ -2886,7 +2883,7 @@
 
   Init(tree);
   ComPtr<IAccessible> ia2_root_obj(GetRootIAccessible());
-  auto* uia_root_node(GetRootAsAXNode());
+  auto* uia_root_node(GetRoot());
 
   for (int child_index = 0;
        child_index < static_cast<int>(tree.nodes[0].child_ids.size());
@@ -3079,7 +3076,7 @@
   Init(tree);
 
   ComPtr<IAccessible> ia2_root_obj(GetRootIAccessible());
-  auto* uia_root_node(GetRootAsAXNode());
+  auto* uia_root_node(GetRoot());
 
   for (int child_index = 0; child_index < child_count; child_index++) {
     ComPtr<IDispatch> child_dispatch;
@@ -3113,7 +3110,7 @@
 
   Init(root, node);
 
-  AXNode* child_node = GetRootAsAXNode()->children()[0];
+  AXNode* child_node = GetRoot()->children()[0];
   ComPtr<IAccessible> child_iaccessible(IAccessibleFromNode(child_node));
   ASSERT_NE(nullptr, child_iaccessible.Get());
 
@@ -3170,7 +3167,7 @@
   Init(root, button, static_text1, inline_box1);
 
   LONG offset_result;
-  ComPtr<IAccessible> root_iaccessible(IAccessibleFromNode(GetRootAsAXNode()));
+  ComPtr<IAccessible> root_iaccessible(IAccessibleFromNode(GetRoot()));
   ASSERT_NE(nullptr, root_iaccessible.Get());
 
   ComPtr<IAccessibleText> root_text;
@@ -3206,7 +3203,7 @@
                       &offset_result));
   EXPECT_EQ(0, offset_result);
 
-  AXNode* static_text1_node = GetRootAsAXNode()->children()[1];
+  AXNode* static_text1_node = GetRoot()->children()[1];
   ComPtr<IAccessible> text1_iaccessible(IAccessibleFromNode(static_text1_node));
   ASSERT_NE(nullptr, text1_iaccessible.Get());
 
@@ -3518,19 +3515,19 @@
 
   // Empty Grid
   ComPtr<IGridProvider> grid1_provider =
-      QueryInterfaceFromNode<IGridProvider>(GetRootAsAXNode()->children()[0]);
+      QueryInterfaceFromNode<IGridProvider>(GetRoot()->children()[0]);
 
   // Grid with a cell that defines aria-rowindex (4) and aria-colindex (5)
   ComPtr<IGridProvider> grid2_provider =
-      QueryInterfaceFromNode<IGridProvider>(GetRootAsAXNode()->children()[1]);
+      QueryInterfaceFromNode<IGridProvider>(GetRoot()->children()[1]);
 
   // Grid that specifies aria-rowcount (2) and aria-colcount (3)
   ComPtr<IGridProvider> grid3_provider =
-      QueryInterfaceFromNode<IGridProvider>(GetRootAsAXNode()->children()[2]);
+      QueryInterfaceFromNode<IGridProvider>(GetRoot()->children()[2]);
 
   // Grid that specifies aria-rowcount and aria-colcount are both (-1)
   ComPtr<IGridProvider> grid4_provider =
-      QueryInterfaceFromNode<IGridProvider>(GetRootAsAXNode()->children()[3]);
+      QueryInterfaceFromNode<IGridProvider>(GetRoot()->children()[3]);
 
   int row_count;
 
@@ -3551,19 +3548,19 @@
 
   // Empty Grid
   ComPtr<IGridProvider> grid1_provider =
-      QueryInterfaceFromNode<IGridProvider>(GetRootAsAXNode()->children()[0]);
+      QueryInterfaceFromNode<IGridProvider>(GetRoot()->children()[0]);
 
   // Grid with a cell that defines aria-rowindex (4) and aria-colindex (5)
   ComPtr<IGridProvider> grid2_provider =
-      QueryInterfaceFromNode<IGridProvider>(GetRootAsAXNode()->children()[1]);
+      QueryInterfaceFromNode<IGridProvider>(GetRoot()->children()[1]);
 
   // Grid that specifies aria-rowcount (2) and aria-colcount (3)
   ComPtr<IGridProvider> grid3_provider =
-      QueryInterfaceFromNode<IGridProvider>(GetRootAsAXNode()->children()[2]);
+      QueryInterfaceFromNode<IGridProvider>(GetRoot()->children()[2]);
 
   // Grid that specifies aria-rowcount and aria-colcount are both (-1)
   ComPtr<IGridProvider> grid4_provider =
-      QueryInterfaceFromNode<IGridProvider>(GetRootAsAXNode()->children()[3]);
+      QueryInterfaceFromNode<IGridProvider>(GetRoot()->children()[3]);
 
   int column_count;
 
@@ -3599,11 +3596,11 @@
   Init(root, row1, cell1);
 
   ComPtr<IGridProvider> root_igridprovider(
-      QueryInterfaceFromNode<IGridProvider>(GetRootAsAXNode()));
+      QueryInterfaceFromNode<IGridProvider>(GetRoot()));
 
   ComPtr<IRawElementProviderSimple> cell1_irawelementprovidersimple(
       QueryInterfaceFromNode<IRawElementProviderSimple>(
-          GetRootAsAXNode()->children()[0]->children()[0]));
+          GetRoot()->children()[0]->children()[0]));
 
   IRawElementProviderSimple* grid_item = nullptr;
   EXPECT_HRESULT_SUCCEEDED(root_igridprovider->GetItem(0, 0, &grid_item));
@@ -3632,7 +3629,7 @@
   Init(root, row1);
 
   ComPtr<ITableProvider> root_itableprovider(
-      QueryInterfaceFromNode<ITableProvider>(GetRootAsAXNode()));
+      QueryInterfaceFromNode<ITableProvider>(GetRoot()));
 
   base::win::ScopedSafearray safearray;
   EXPECT_HRESULT_SUCCEEDED(
@@ -3747,7 +3744,7 @@
        cell_r2c2, cell_r2c3, cell_r3c1, header_r3c2);
 
   ComPtr<ITableProvider> root_itableprovider(
-      QueryInterfaceFromNode<ITableProvider>(GetRootAsAXNode()));
+      QueryInterfaceFromNode<ITableProvider>(GetRoot()));
 
   base::win::ScopedSafearray safearray;
   EXPECT_HRESULT_SUCCEEDED(
@@ -3787,7 +3784,7 @@
   Init(root, row1, column_header, row_header);
 
   ComPtr<ITableProvider> root_itableprovider(
-      QueryInterfaceFromNode<ITableProvider>(GetRootAsAXNode()));
+      QueryInterfaceFromNode<ITableProvider>(GetRoot()));
 
   base::win::ScopedSafearray safearray;
   EXPECT_HRESULT_SUCCEEDED(
@@ -3799,7 +3796,7 @@
 
   // Remove row_header's native event target and verify it's no longer returned.
   TestAXNodeWrapper* row_header_wrapper = TestAXNodeWrapper::GetOrCreate(
-      GetTree(), GetRootAsAXNode()->children()[0]->children()[1]);
+      GetTree(), GetRoot()->children()[0]->children()[1]);
   row_header_wrapper->ResetNativeEventTarget();
 
   safearray.Release();
@@ -3816,7 +3813,7 @@
   Init(root);
 
   ComPtr<ITableProvider> root_itableprovider(
-      QueryInterfaceFromNode<ITableProvider>(GetRootAsAXNode()));
+      QueryInterfaceFromNode<ITableProvider>(GetRoot()));
 
   RowOrColumnMajor row_or_column_major;
   EXPECT_HRESULT_SUCCEEDED(
@@ -3859,12 +3856,12 @@
   Init(root, row1, column_header_1, column_header_2, row2, cell);
 
   TestAXNodeWrapper* root_wrapper =
-      TestAXNodeWrapper::GetOrCreate(GetTree(), GetRootAsAXNode());
-  root_wrapper->BuildAllWrappers(GetTree(), GetRootAsAXNode());
+      TestAXNodeWrapper::GetOrCreate(GetTree(), GetRoot());
+  root_wrapper->BuildAllWrappers(GetTree(), GetRoot());
 
   ComPtr<ITableItemProvider> cell_itableitemprovider(
       QueryInterfaceFromNode<ITableItemProvider>(
-          GetRootAsAXNode()->children()[1]->children()[0]));
+          GetRoot()->children()[1]->children()[0]));
 
   base::win::ScopedSafearray safearray;
   EXPECT_HRESULT_SUCCEEDED(
@@ -3878,7 +3875,7 @@
   // Remove column_header_1's native event target and verify it's no longer
   // returned.
   TestAXNodeWrapper* column_header_wrapper = TestAXNodeWrapper::GetOrCreate(
-      GetTree(), GetRootAsAXNode()->children()[0]->children()[0]);
+      GetTree(), GetRoot()->children()[0]->children()[0]);
   column_header_wrapper->ResetNativeEventTarget();
 
   safearray.Release();
@@ -3922,12 +3919,12 @@
   Init(root, row1, row_header_1, cell, row2, row_header_2);
 
   TestAXNodeWrapper* root_wrapper =
-      TestAXNodeWrapper::GetOrCreate(GetTree(), GetRootAsAXNode());
-  root_wrapper->BuildAllWrappers(GetTree(), GetRootAsAXNode());
+      TestAXNodeWrapper::GetOrCreate(GetTree(), GetRoot());
+  root_wrapper->BuildAllWrappers(GetTree(), GetRoot());
 
   ComPtr<ITableItemProvider> cell_itableitemprovider(
       QueryInterfaceFromNode<ITableItemProvider>(
-          GetRootAsAXNode()->children()[0]->children()[1]));
+          GetRoot()->children()[0]->children()[1]));
 
   base::win::ScopedSafearray safearray;
   EXPECT_HRESULT_SUCCEEDED(
@@ -3940,7 +3937,7 @@
   // Remove row_header_1's native event target and verify it's no longer
   // returned.
   TestAXNodeWrapper* row_header_wrapper = TestAXNodeWrapper::GetOrCreate(
-      GetTree(), GetRootAsAXNode()->children()[0]->children()[0]);
+      GetTree(), GetRoot()->children()[0]->children()[0]);
   row_header_wrapper->ResetNativeEventTarget();
 
   safearray.Release();
@@ -4043,7 +4040,7 @@
   EXPECT_UIA_BOOL_EQ(root_node, UIA_IsOffscreenPropertyId, false);
   ComPtr<IRawElementProviderSimple> child_node1 =
       QueryInterfaceFromNode<IRawElementProviderSimple>(
-          GetRootAsAXNode()->children()[0]);
+          GetRoot()->children()[0]);
   EXPECT_UIA_INT_EQ(child_node1, UIA_PositionInSetPropertyId, 1);
   EXPECT_UIA_BSTR_EQ(
       child_node1, UIA_AriaPropertiesPropertyId,
@@ -4052,7 +4049,7 @@
 
   ComPtr<IRawElementProviderSimple> child_node2 =
       QueryInterfaceFromNode<IRawElementProviderSimple>(
-          GetRootAsAXNode()->children()[1]);
+          GetRoot()->children()[1]);
   // aria-current="false" should not be serialized.
   EXPECT_UIA_BSTR_EQ(
       child_node2, UIA_AriaPropertiesPropertyId,
@@ -4092,19 +4089,19 @@
 
   ComPtr<IRawElementProviderSimple> row =
       QueryInterfaceFromNode<IRawElementProviderSimple>(
-          GetRootAsAXNode()->children()[0]);
+          GetRoot()->children()[0]);
   EXPECT_UIA_BOOL_EQ(row, UIA_IsControlElementPropertyId, true);
   EXPECT_UIA_BOOL_EQ(row, UIA_IsContentElementPropertyId, true);
 
   ComPtr<IRawElementProviderSimple> cell =
       QueryInterfaceFromNode<IRawElementProviderSimple>(
-          GetRootAsAXNode()->children()[0]->children()[0]);
+          GetRoot()->children()[0]->children()[0]);
   EXPECT_UIA_BOOL_EQ(cell, UIA_IsControlElementPropertyId, true);
   EXPECT_UIA_BOOL_EQ(cell, UIA_IsContentElementPropertyId, true);
 
   ComPtr<IRawElementProviderSimple> generic_container_provider =
       QueryInterfaceFromNode<IRawElementProviderSimple>(
-          GetRootAsAXNode()->children()[0]->children()[0]->children()[0]);
+          GetRoot()->children()[0]->children()[0]->children()[0]);
   EXPECT_UIA_BOOL_EQ(generic_container_provider, UIA_IsControlElementPropertyId,
                      false);
   EXPECT_UIA_BOOL_EQ(generic_container_provider, UIA_IsContentElementPropertyId,
@@ -4162,7 +4159,7 @@
   // Turn on web content mode for the AXTree.
   TestAXNodeWrapper::SetGlobalIsWebContent(true);
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   AXNode* text_3_node = root_node->children()[0]->children()[0];
   AXNode* text_5_node = root_node->children()[1]->children()[0];
   AXNode* text_7_node = root_node->children()[2]->children()[0];
@@ -4359,7 +4356,7 @@
 
   Init(root, highlighted, comment);
   ComPtr<IRawElementProviderSimple> root_node =
-      QueryInterfaceFromNode<IRawElementProviderSimple>(GetRootAsAXNode());
+      QueryInterfaceFromNode<IRawElementProviderSimple>(GetRoot());
 
   ScopedVariant array;
   ASSERT_HRESULT_SUCCEEDED(root_node->GetPropertyValue(
@@ -4406,12 +4403,12 @@
 
   Init(root, tab, panel1, panel2, group1, text1);
   TestAXNodeWrapper* root_wrapper =
-      TestAXNodeWrapper::GetOrCreate(GetTree(), GetRootAsAXNode());
-  root_wrapper->BuildAllWrappers(GetTree(), GetRootAsAXNode());
+      TestAXNodeWrapper::GetOrCreate(GetTree(), GetRoot());
+  root_wrapper->BuildAllWrappers(GetTree(), GetRoot());
 
   ComPtr<IRawElementProviderSimple> tab_node =
       QueryInterfaceFromNode<IRawElementProviderSimple>(
-          GetRootAsAXNode()->children()[0]);
+          GetRoot()->children()[0]);
 
   std::vector<std::wstring> expected_names_1 = {L"panel1", L"panel2"};
   EXPECT_UIA_PROPERTY_ELEMENT_ARRAY_BSTR_EQ(
@@ -4419,8 +4416,8 @@
       expected_names_1);
 
   // Remove panel1's native event target and verify it's no longer returned.
-  TestAXNodeWrapper* panel1_wrapper = TestAXNodeWrapper::GetOrCreate(
-      GetTree(), GetRootAsAXNode()->children()[1]);
+  TestAXNodeWrapper* panel1_wrapper =
+      TestAXNodeWrapper::GetOrCreate(GetTree(), GetRoot()->children()[1]);
   panel1_wrapper->ResetNativeEventTarget();
   std::vector<std::wstring> expected_names_2 = {L"panel2"};
   EXPECT_UIA_PROPERTY_ELEMENT_ARRAY_BSTR_EQ(
@@ -4431,7 +4428,7 @@
   // UIA property.
   ComPtr<IRawElementProviderSimple> group1_node =
       QueryInterfaceFromNode<IRawElementProviderSimple>(
-          GetRootAsAXNode()->children()[3]);
+          GetRoot()->children()[3]);
 
   std::vector<std::wstring> expected_names_3 = {L"text1"};
   EXPECT_UIA_PROPERTY_ELEMENT_ARRAY_BSTR_EQ(
@@ -4517,7 +4514,7 @@
 
   Init(root, row1, header1, header2, header3, header4);
 
-  auto* row_node = GetRootAsAXNode()->children()[0];
+  auto* row_node = GetRoot()->children()[0];
 
   EXPECT_UIA_BSTR_EQ(QueryInterfaceFromNode<IRawElementProviderSimple>(
                          row_node->children()[0]),
@@ -4603,12 +4600,11 @@
   root.child_ids.push_back(child1.id);
 
   Init(root, child1);
-  ASSERT_NE(nullptr,
-            TestAXNodeWrapper::GetOrCreate(GetTree(), GetRootAsAXNode()));
+  ASSERT_NE(nullptr, TestAXNodeWrapper::GetOrCreate(GetTree(), GetRoot()));
 
   ComPtr<IRawElementProviderSimple> child_node1 =
       QueryInterfaceFromNode<IRawElementProviderSimple>(
-          GetRootAsAXNode()->children()[0]);
+          GetRoot()->children()[0]);
   std::vector<std::wstring> expected_names = {L"root"};
   EXPECT_UIA_PROPERTY_ELEMENT_ARRAY_BSTR_EQ(
       child_node1, UIA_FlowsFromPropertyId, UIA_NamePropertyId, expected_names);
@@ -4635,22 +4631,21 @@
   root.child_ids.push_back(child2.id);
 
   Init(root, child1, child2);
-  ASSERT_NE(nullptr,
-            TestAXNodeWrapper::GetOrCreate(GetTree(), GetRootAsAXNode()));
-  ASSERT_NE(nullptr, TestAXNodeWrapper::GetOrCreate(
-                         GetTree(), GetRootAsAXNode()->children()[0]));
+  ASSERT_NE(nullptr, TestAXNodeWrapper::GetOrCreate(GetTree(), GetRoot()));
+  ASSERT_NE(nullptr, TestAXNodeWrapper::GetOrCreate(GetTree(),
+                                                    GetRoot()->children()[0]));
 
   ComPtr<IRawElementProviderSimple> child_node2 =
       QueryInterfaceFromNode<IRawElementProviderSimple>(
-          GetRootAsAXNode()->children()[1]);
+          GetRoot()->children()[1]);
   std::vector<std::wstring> expected_names_1 = {L"root", L"child1"};
   EXPECT_UIA_PROPERTY_UNORDERED_ELEMENT_ARRAY_BSTR_EQ(
       child_node2, UIA_FlowsFromPropertyId, UIA_NamePropertyId,
       expected_names_1);
 
   // Remove child1's native event target and verify it's no longer returned.
-  TestAXNodeWrapper* child1_wrapper = TestAXNodeWrapper::GetOrCreate(
-      GetTree(), GetRootAsAXNode()->children()[0]);
+  TestAXNodeWrapper* child1_wrapper =
+      TestAXNodeWrapper::GetOrCreate(GetTree(), GetRoot()->children()[0]);
   child1_wrapper->ResetNativeEventTarget();
   std::vector<std::wstring> expected_names_2 = {L"root"};
   EXPECT_UIA_PROPERTY_UNORDERED_ELEMENT_ARRAY_BSTR_EQ(
@@ -4722,7 +4717,7 @@
 
   Init(root_1, gc_2, static_text_3, gc_4, gc_5, static_text_6, alert_7);
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   AXNode* gc_2_node = root_node->children()[0];
   AXNode* static_text_3_node = gc_2_node->children()[0];
   AXNode* gc_4_node = root_node->children()[1];
@@ -4856,7 +4851,7 @@
 
   Init(root, input1, input2, input3, input4, input5);
 
-  auto* root_node = GetRootAsAXNode();
+  auto* root_node = GetRoot();
   EXPECT_UIA_BSTR_EQ(QueryInterfaceFromNode<IRawElementProviderSimple>(
                          root_node->children()[0]),
                      UIA_HelpTextPropertyId, L"placeholder");
@@ -4900,11 +4895,11 @@
   EXPECT_UIA_BSTR_EQ(root_node, UIA_LocalizedControlTypePropertyId,
                      L"root role description");
   EXPECT_UIA_BSTR_EQ(QueryInterfaceFromNode<IRawElementProviderSimple>(
-                         GetRootAsAXNode()->children()[0]),
+                         GetRoot()->children()[0]),
                      UIA_LocalizedControlTypePropertyId,
                      L"child1 role description");
   EXPECT_UIA_EMPTY(QueryInterfaceFromNode<IRawElementProviderSimple>(
-                       GetRootAsAXNode()->children()[1]),
+                       GetRoot()->children()[1]),
                    UIA_LocalizedControlTypePropertyId);
 }
 
@@ -5070,7 +5065,7 @@
   Init(root_data, element1_data);
   InitFragmentRoot();
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   AXNode* element1_node = root_node->children()[0];
 
   ComPtr<IRawElementProviderFragment> element1_provider =
@@ -5277,7 +5272,7 @@
 
   Init(root_data, element1_data, element2_data, element3_data);
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   AXNode* element1_node = root_node->children()[0];
   AXNode* element2_node = root_node->children()[1];
   AXNode* element3_node = element1_node->children()[0];
@@ -5387,19 +5382,19 @@
 
   ComPtr<IRawElementProviderSimple> highlighted1_node =
       QueryInterfaceFromNode<IRawElementProviderSimple>(
-          GetRootAsAXNode()->children()[0]);
+          GetRoot()->children()[0]);
   ComPtr<IRawElementProviderSimple> comment1_node =
       QueryInterfaceFromNode<IRawElementProviderSimple>(
-          GetRootAsAXNode()->children()[1]);
+          GetRoot()->children()[1]);
   ComPtr<IRawElementProviderSimple> footnote_node =
       QueryInterfaceFromNode<IRawElementProviderSimple>(
-          GetRootAsAXNode()->children()[2]);
+          GetRoot()->children()[2]);
   ComPtr<IRawElementProviderSimple> definition_node =
       QueryInterfaceFromNode<IRawElementProviderSimple>(
-          GetRootAsAXNode()->children()[3]);
+          GetRoot()->children()[3]);
   ComPtr<IRawElementProviderSimple> button_node =
       QueryInterfaceFromNode<IRawElementProviderSimple>(
-          GetRootAsAXNode()->children()[4]);
+          GetRoot()->children()[4]);
   ComPtr<IAnnotationProvider> annotation_provider;
   ComPtr<IRawElementProviderSimple> target;
   int annotation_type;
@@ -5566,10 +5561,10 @@
 
   ComPtr<IRawElementProviderSimple> highlighted1_node =
       QueryInterfaceFromNode<IRawElementProviderSimple>(
-          GetRootAsAXNode()->children()[0]);
+          GetRoot()->children()[0]);
   ComPtr<IRawElementProviderSimple> comment1_node =
       QueryInterfaceFromNode<IRawElementProviderSimple>(
-          GetRootAsAXNode()->children()[3]);
+          GetRoot()->children()[3]);
 
   ComPtr<IAnnotationProvider> annotation_provider;
   ComPtr<IRawElementProviderSimple> target;
@@ -5596,7 +5591,7 @@
                     /*option_3_is_selected*/ false, {}));
 
   ComPtr<ISelectionProvider> selection_provider(
-      QueryInterfaceFromNode<ISelectionProvider>(GetRootAsAXNode()));
+      QueryInterfaceFromNode<ISelectionProvider>(GetRoot()));
 
   BOOL multiple = TRUE;
   EXPECT_HRESULT_SUCCEEDED(
@@ -5613,7 +5608,7 @@
                     /*additional_state*/ state));
 
   ComPtr<ISelectionProvider> selection_provider(
-      QueryInterfaceFromNode<ISelectionProvider>(GetRootAsAXNode()));
+      QueryInterfaceFromNode<ISelectionProvider>(GetRoot()));
 
   BOOL multiple = FALSE;
   EXPECT_HRESULT_SUCCEEDED(
@@ -5628,7 +5623,7 @@
                     /*additional_state*/ {}));
 
   ComPtr<ISelectionProvider> selection_provider(
-      QueryInterfaceFromNode<ISelectionProvider>(GetRootAsAXNode()));
+      QueryInterfaceFromNode<ISelectionProvider>(GetRoot()));
 
   BOOL selection_required = TRUE;
   EXPECT_HRESULT_SUCCEEDED(
@@ -5643,7 +5638,7 @@
                     /*additional_state*/ {ax::mojom::State::kRequired}));
 
   ComPtr<ISelectionProvider> selection_provider(
-      QueryInterfaceFromNode<ISelectionProvider>(GetRootAsAXNode()));
+      QueryInterfaceFromNode<ISelectionProvider>(GetRoot()));
 
   BOOL selection_required = FALSE;
   EXPECT_HRESULT_SUCCEEDED(
@@ -5658,7 +5653,7 @@
                     /*additional_state*/ {ax::mojom::State::kFocusable}));
 
   ComPtr<ISelectionProvider> selection_provider(
-      QueryInterfaceFromNode<ISelectionProvider>(GetRootAsAXNode()));
+      QueryInterfaceFromNode<ISelectionProvider>(GetRoot()));
 
   base::win::ScopedSafearray selected_items;
   EXPECT_HRESULT_SUCCEEDED(
@@ -5684,10 +5679,10 @@
                     /*additional_state*/ {ax::mojom::State::kFocusable}));
 
   ComPtr<ISelectionProvider> selection_provider(
-      QueryInterfaceFromNode<ISelectionProvider>(GetRootAsAXNode()));
+      QueryInterfaceFromNode<ISelectionProvider>(GetRoot()));
   ComPtr<IRawElementProviderSimple> option2_provider(
       QueryInterfaceFromNode<IRawElementProviderSimple>(
-          GetRootAsAXNode()->children()[1]));
+          GetRoot()->children()[1]));
 
   base::win::ScopedSafearray selected_items;
   EXPECT_HRESULT_SUCCEEDED(
@@ -5721,16 +5716,16 @@
                     /*additional_state*/ state));
 
   ComPtr<ISelectionProvider> selection_provider(
-      QueryInterfaceFromNode<ISelectionProvider>(GetRootAsAXNode()));
+      QueryInterfaceFromNode<ISelectionProvider>(GetRoot()));
   ComPtr<IRawElementProviderSimple> option1_provider(
       QueryInterfaceFromNode<IRawElementProviderSimple>(
-          GetRootAsAXNode()->children()[0]));
+          GetRoot()->children()[0]));
   ComPtr<IRawElementProviderSimple> option2_provider(
       QueryInterfaceFromNode<IRawElementProviderSimple>(
-          GetRootAsAXNode()->children()[1]));
+          GetRoot()->children()[1]));
   ComPtr<IRawElementProviderSimple> option3_provider(
       QueryInterfaceFromNode<IRawElementProviderSimple>(
-          GetRootAsAXNode()->children()[2]));
+          GetRoot()->children()[2]));
 
   base::win::ScopedSafearray selected_items;
   EXPECT_HRESULT_SUCCEEDED(
@@ -5925,7 +5920,7 @@
 
   Init(root_data, element1_data, element2_data);
 
-  AXNode* root_node = GetRootAsAXNode();
+  AXNode* root_node = GetRoot();
   AXNode* element1_node = root_node->children()[0];
   AXNode* element2_node = root_node->children()[1];
 
@@ -5953,35 +5948,35 @@
   ComPtr<IRawElementProviderSimple> simple_provider =
       GetRootIRawElementProviderSimple();
   ComPtr<IRawElementProviderSimple2> simple2_provider =
-      QueryInterfaceFromNode<IRawElementProviderSimple2>(GetRootAsAXNode());
+      QueryInterfaceFromNode<IRawElementProviderSimple2>(GetRoot());
   ComPtr<IRawElementProviderFragment> fragment_provider =
       GetRootIRawElementProviderFragment();
   ComPtr<IGridItemProvider> grid_item_provider =
-      QueryInterfaceFromNode<IGridItemProvider>(GetRootAsAXNode());
+      QueryInterfaceFromNode<IGridItemProvider>(GetRoot());
   ComPtr<IGridProvider> grid_provider =
-      QueryInterfaceFromNode<IGridProvider>(GetRootAsAXNode());
+      QueryInterfaceFromNode<IGridProvider>(GetRoot());
   ComPtr<IScrollItemProvider> scroll_item_provider =
-      QueryInterfaceFromNode<IScrollItemProvider>(GetRootAsAXNode());
+      QueryInterfaceFromNode<IScrollItemProvider>(GetRoot());
   ComPtr<IScrollProvider> scroll_provider =
-      QueryInterfaceFromNode<IScrollProvider>(GetRootAsAXNode());
+      QueryInterfaceFromNode<IScrollProvider>(GetRoot());
   ComPtr<ISelectionItemProvider> selection_item_provider =
-      QueryInterfaceFromNode<ISelectionItemProvider>(GetRootAsAXNode());
+      QueryInterfaceFromNode<ISelectionItemProvider>(GetRoot());
   ComPtr<ISelectionProvider> selection_provider =
-      QueryInterfaceFromNode<ISelectionProvider>(GetRootAsAXNode());
+      QueryInterfaceFromNode<ISelectionProvider>(GetRoot());
   ComPtr<ITableItemProvider> table_item_provider =
-      QueryInterfaceFromNode<ITableItemProvider>(GetRootAsAXNode());
+      QueryInterfaceFromNode<ITableItemProvider>(GetRoot());
   ComPtr<ITableProvider> table_provider =
-      QueryInterfaceFromNode<ITableProvider>(GetRootAsAXNode());
+      QueryInterfaceFromNode<ITableProvider>(GetRoot());
   ComPtr<IExpandCollapseProvider> expand_collapse_provider =
-      QueryInterfaceFromNode<IExpandCollapseProvider>(GetRootAsAXNode());
+      QueryInterfaceFromNode<IExpandCollapseProvider>(GetRoot());
   ComPtr<IToggleProvider> toggle_provider =
-      QueryInterfaceFromNode<IToggleProvider>(GetRootAsAXNode());
+      QueryInterfaceFromNode<IToggleProvider>(GetRoot());
   ComPtr<IValueProvider> value_provider =
-      QueryInterfaceFromNode<IValueProvider>(GetRootAsAXNode());
+      QueryInterfaceFromNode<IValueProvider>(GetRoot());
   ComPtr<IRangeValueProvider> range_value_provider =
-      QueryInterfaceFromNode<IRangeValueProvider>(GetRootAsAXNode());
+      QueryInterfaceFromNode<IRangeValueProvider>(GetRoot());
   ComPtr<IWindowProvider> window_provider =
-      QueryInterfaceFromNode<IWindowProvider>(GetRootAsAXNode());
+      QueryInterfaceFromNode<IWindowProvider>(GetRoot());
 
   // Create an empty tree.
   SetTree(std::make_unique<AXTree>());
@@ -6857,7 +6852,7 @@
   button_disabled.SetRestriction(ax::mojom::Restriction::kDisabled);
 
   Init(root, button, button_disabled);
-  AXNode* button_node = GetRootAsAXNode()->children()[0];
+  AXNode* button_node = GetRoot()->children()[0];
 
   // generic button can be invoked.
   ComPtr<IRawElementProviderSimple> raw_element_provider_simple =
@@ -7212,7 +7207,7 @@
 
   Init(root, row1, cell1);
 
-  const auto* row = GetRootAsAXNode()->children()[0];
+  const auto* row = GetRoot()->children()[0];
   ComPtr<IRawElementProviderSimple> raw_element_provider_simple =
       QueryInterfaceFromNode<IRawElementProviderSimple>(row->children()[0]);
 
@@ -7282,7 +7277,7 @@
   ComPtr<IRawElementProviderSimple> container_provider =
       GetRootIRawElementProviderSimple();
 
-  const auto* row = GetRootAsAXNode()->children()[0];
+  const auto* row = GetRoot()->children()[0];
   ComPtr<ISelectionItemProvider> item_provider =
       QueryInterfaceFromNode<ISelectionItemProvider>(row->children()[0]);
 
@@ -7306,7 +7301,7 @@
 
   Init(root, tab1);
 
-  auto* tab1_node = GetRootAsAXNode()->children()[0];
+  auto* tab1_node = GetRoot()->children()[0];
   ComPtr<IRawElementProviderSimple> tab1_raw_element_provider_simple =
       QueryInterfaceFromNode<IRawElementProviderSimple>(tab1_node);
   ASSERT_NE(nullptr, tab1_raw_element_provider_simple.Get());
@@ -7399,32 +7394,32 @@
   ScopedBstr bstr_value;
 
   EXPECT_HRESULT_SUCCEEDED(
-      QueryInterfaceFromNode<IValueProvider>(GetRootAsAXNode())
-          ->get_Value(bstr_value.Receive()));
+      QueryInterfaceFromNode<IValueProvider>(GetRoot())->get_Value(
+          bstr_value.Receive()));
   EXPECT_STREQ(url,
                base::UTF16ToASCII(base::as_u16cstr(bstr_value.Get())).c_str());
   bstr_value.Reset();
 
   EXPECT_HRESULT_SUCCEEDED(
-      QueryInterfaceFromNode<IValueProvider>(GetRootAsAXNode()->children()[0])
+      QueryInterfaceFromNode<IValueProvider>(GetRoot()->children()[0])
           ->get_Value(bstr_value.Receive()));
   EXPECT_STREQ(L"3", bstr_value.Get());
   bstr_value.Reset();
 
   EXPECT_HRESULT_SUCCEEDED(
-      QueryInterfaceFromNode<IValueProvider>(GetRootAsAXNode()->children()[1])
+      QueryInterfaceFromNode<IValueProvider>(GetRoot()->children()[1])
           ->get_Value(bstr_value.Receive()));
   EXPECT_STREQ(L"test", bstr_value.Get());
   bstr_value.Reset();
 
   EXPECT_HRESULT_SUCCEEDED(
-      QueryInterfaceFromNode<IValueProvider>(GetRootAsAXNode()->children()[2])
+      QueryInterfaceFromNode<IValueProvider>(GetRoot()->children()[2])
           ->get_Value(bstr_value.Receive()));
   EXPECT_STREQ(L"test", bstr_value.Get());
   bstr_value.Reset();
 
   EXPECT_HRESULT_SUCCEEDED(
-      QueryInterfaceFromNode<IValueProvider>(GetRootAsAXNode()->children()[3])
+      QueryInterfaceFromNode<IValueProvider>(GetRoot()->children()[3])
           ->get_Value(bstr_value.Receive()));
   EXPECT_STREQ(L"test", bstr_value.Get());
   bstr_value.Reset();
@@ -7447,7 +7442,7 @@
 
   ScopedVariant value;
   EXPECT_HRESULT_SUCCEEDED(
-      QueryInterfaceFromNode<IAccessibleValue>(GetRootAsAXNode()->children()[0])
+      QueryInterfaceFromNode<IAccessibleValue>(GetRoot()->children()[0])
           ->get_currentValue(value.Receive()));
   ASSERT_EQ(VT_R8, value.type());
   EXPECT_DOUBLE_EQ(3.0, V_R8(value.ptr()));
@@ -7492,13 +7487,13 @@
   Init(update);
 
   ComPtr<IValueProvider> root_provider =
-      QueryInterfaceFromNode<IValueProvider>(GetRootAsAXNode());
+      QueryInterfaceFromNode<IValueProvider>(GetRoot());
   ComPtr<IValueProvider> provider1 =
-      QueryInterfaceFromNode<IValueProvider>(GetRootAsAXNode()->children()[0]);
+      QueryInterfaceFromNode<IValueProvider>(GetRoot()->children()[0]);
   ComPtr<IValueProvider> provider2 =
-      QueryInterfaceFromNode<IValueProvider>(GetRootAsAXNode()->children()[1]);
+      QueryInterfaceFromNode<IValueProvider>(GetRoot()->children()[1]);
   ComPtr<IValueProvider> provider3 =
-      QueryInterfaceFromNode<IValueProvider>(GetRootAsAXNode()->children()[2]);
+      QueryInterfaceFromNode<IValueProvider>(GetRoot()->children()[2]);
 
   ScopedBstr bstr_value;
 
@@ -7563,27 +7558,27 @@
   BOOL is_readonly = false;
 
   EXPECT_HRESULT_SUCCEEDED(
-      QueryInterfaceFromNode<IValueProvider>(GetRootAsAXNode())
-          ->get_IsReadOnly(&is_readonly));
+      QueryInterfaceFromNode<IValueProvider>(GetRoot())->get_IsReadOnly(
+          &is_readonly));
   EXPECT_TRUE(is_readonly);
 
   EXPECT_HRESULT_SUCCEEDED(
-      QueryInterfaceFromNode<IValueProvider>(GetRootAsAXNode()->children()[0])
+      QueryInterfaceFromNode<IValueProvider>(GetRoot()->children()[0])
           ->get_IsReadOnly(&is_readonly));
   EXPECT_FALSE(is_readonly);
 
   EXPECT_HRESULT_SUCCEEDED(
-      QueryInterfaceFromNode<IValueProvider>(GetRootAsAXNode()->children()[1])
+      QueryInterfaceFromNode<IValueProvider>(GetRoot()->children()[1])
           ->get_IsReadOnly(&is_readonly));
   EXPECT_TRUE(is_readonly);
 
   EXPECT_HRESULT_SUCCEEDED(
-      QueryInterfaceFromNode<IValueProvider>(GetRootAsAXNode()->children()[2])
+      QueryInterfaceFromNode<IValueProvider>(GetRoot()->children()[2])
           ->get_IsReadOnly(&is_readonly));
   EXPECT_TRUE(is_readonly);
 
   EXPECT_HRESULT_SUCCEEDED(
-      QueryInterfaceFromNode<IValueProvider>(GetRootAsAXNode()->children()[3])
+      QueryInterfaceFromNode<IValueProvider>(GetRoot()->children()[3])
           ->get_IsReadOnly(&is_readonly));
   EXPECT_TRUE(is_readonly);
 }
@@ -7603,7 +7598,7 @@
   Init(root);
 
   ComPtr<IScrollProvider> scroll_provider =
-      QueryInterfaceFromNode<IScrollProvider>(GetRootAsAXNode());
+      QueryInterfaceFromNode<IScrollProvider>(GetRoot());
   double x_scroll_percent;
   double y_scroll_percent;
 
@@ -7735,7 +7730,7 @@
   Init(root);
 
   ComPtr<IChromeAccessible> chrome_accessible =
-      QueryInterfaceFromNode<IChromeAccessible>(GetRootAsAXNode());
+      QueryInterfaceFromNode<IChromeAccessible>(GetRoot());
 
   CComObject<TestIChromeAccessibleDelegate>* delegate = nullptr;
   ASSERT_HRESULT_SUCCEEDED(
@@ -7763,7 +7758,7 @@
   Init(root);
 
   ComPtr<IChromeAccessible> chrome_accessible =
-      QueryInterfaceFromNode<IChromeAccessible>(GetRootAsAXNode());
+      QueryInterfaceFromNode<IChromeAccessible>(GetRoot());
 
   CComObject<TestIChromeAccessibleDelegate>* delegate = nullptr;
   ASSERT_HRESULT_SUCCEEDED(
@@ -7775,7 +7770,7 @@
   LONG result_unique_id = 0;
   ASSERT_HRESULT_SUCCEEDED(accessible->get_uniqueID(&result_unique_id));
   ComPtr<IAccessible2> root_accessible =
-      QueryInterfaceFromNode<IAccessible2>(GetRootAsAXNode());
+      QueryInterfaceFromNode<IAccessible2>(GetRoot());
   LONG root_unique_id = 0;
   ASSERT_HRESULT_SUCCEEDED(root_accessible->get_uniqueID(&root_unique_id));
   ASSERT_EQ(root_unique_id, result_unique_id);
diff --git a/ui/base/ime/ash/ime_engine_handler_interface.h b/ui/base/ime/ash/ime_engine_handler_interface.h
index ee162079..2e2f0b5 100644
--- a/ui/base/ime/ash/ime_engine_handler_interface.h
+++ b/ui/base/ime/ash/ime_engine_handler_interface.h
@@ -30,12 +30,18 @@
 
 namespace ime {
 struct AssistiveWindowButton;
+enum class KeyEventHandledState {
+  kNotHandled = 0,
+  kHandledByIME = 1,
+  kHandledByAssistiveSuggester = 2,
+};
 }  // namespace ime
 
 // A interface to handle the engine handler method call.
 class COMPONENT_EXPORT(UI_BASE_IME_ASH) IMEEngineHandlerInterface {
  public:
-  using KeyEventDoneCallback = base::OnceCallback<void(bool)>;
+  using KeyEventDoneCallback =
+      base::OnceCallback<void(ui::ime::KeyEventHandledState)>;
 
   // A information about a focused text input field.
   // A type of each member is based on the html spec, but InputContext can be
diff --git a/ui/base/ime/ash/input_method_ash.cc b/ui/base/ime/ash/input_method_ash.cc
index 3073706..a4b5479 100644
--- a/ui/base/ime/ash/input_method_ash.cc
+++ b/ui/base/ime/ash/input_method_ash.cc
@@ -132,9 +132,9 @@
       if (ExecuteCharacterComposer(*event)) {
         // Treating as PostIME event if character composer handles key event and
         // generates some IME event,
-        return ProcessKeyEventPostIME(event,
-                                      /* handled */ true,
-                                      /* stopped_propagation */ true);
+        return ProcessKeyEventPostIME(
+            event, ui::ime::KeyEventHandledState::kHandledByIME,
+            /* stopped_propagation */ true);
       }
       return ProcessUnfilteredKeyPressEvent(event);
     }
@@ -150,17 +150,19 @@
   return ui::EventDispatchDetails();
 }
 
-void InputMethodAsh::ProcessKeyEventDone(ui::KeyEvent* event, bool is_handled) {
+void InputMethodAsh::ProcessKeyEventDone(
+    ui::KeyEvent* event,
+    ui::ime::KeyEventHandledState handled_state) {
   DCHECK(event);
   if (event->type() == ET_KEY_PRESSED) {
-    if (is_handled) {
+    if (handled_state != ui::ime::KeyEventHandledState::kNotHandled) {
       // IME event has a priority to be handled, so that character composer
       // should be reset.
       character_composer_.Reset();
     } else {
       // If IME does not handle key event, passes keyevent to character composer
       // to be able to compose complex characters.
-      is_handled = ExecuteCharacterComposer(*event);
+      bool is_handled = ExecuteCharacterComposer(*event);
 
       if (!is_handled &&
           !KeycodeConverter::IsDomKeyForModifier(event->GetDomKey())) {
@@ -175,7 +177,7 @@
     }
   }
   if (event->type() == ET_KEY_PRESSED || event->type() == ET_KEY_RELEASED) {
-    std::ignore = ProcessKeyEventPostIME(event, is_handled,
+    std::ignore = ProcessKeyEventPostIME(event, handled_state,
                                          /* stopped_propagation */ false);
   }
   handling_key_event_ = false;
@@ -555,8 +557,9 @@
 
 ui::EventDispatchDetails InputMethodAsh::ProcessKeyEventPostIME(
     ui::KeyEvent* event,
-    bool handled,
+    ui::ime::KeyEventHandledState handled_state,
     bool stopped_propagation) {
+  bool handled = (handled_state != ui::ime::KeyEventHandledState::kNotHandled);
   TextInputClient* client = GetTextInputClient();
   if (!client) {
     // As ibus works asynchronously, there is a chance that the focused client
@@ -565,8 +568,11 @@
   }
 
   if (event->type() == ET_KEY_PRESSED && handled) {
+    bool only_dispatch_vkey_processkey =
+        (handled_state ==
+         ui::ime::KeyEventHandledState::kHandledByAssistiveSuggester);
     ui::EventDispatchDetails dispatch_details =
-        ProcessFilteredKeyPressEvent(event);
+        ProcessFilteredKeyPressEvent(event, only_dispatch_vkey_processkey);
     if (event->stopped_propagation()) {
       ResetContext();
       return dispatch_details;
@@ -598,8 +604,9 @@
 }
 
 ui::EventDispatchDetails InputMethodAsh::ProcessFilteredKeyPressEvent(
-    ui::KeyEvent* event) {
-  if (NeedInsertChar())
+    ui::KeyEvent* event,
+    bool only_dispatch_vkey_processkey) {
+  if (!only_dispatch_vkey_processkey && NeedInsertChar())
     return DispatchKeyEventPostIME(event);
 
   ui::KeyEvent fabricated_event(ET_KEY_PRESSED, VKEY_PROCESSKEY, event->code(),
diff --git a/ui/base/ime/ash/input_method_ash.h b/ui/base/ime/ash/input_method_ash.h
index 9f20178..eea5e916 100644
--- a/ui/base/ime/ash/input_method_ash.h
+++ b/ui/base/ime/ash/input_method_ash.h
@@ -22,6 +22,10 @@
 
 namespace ui {
 
+namespace ime {
+enum class KeyEventHandledState;
+}
+
 // A `ui::InputMethod` implementation for Ash.
 class COMPONENT_EXPORT(UI_BASE_IME_ASH) InputMethodAsh
     : public InputMethodBase,
@@ -92,7 +96,7 @@
   // Process a key returned from the input method.
   [[nodiscard]] virtual ui::EventDispatchDetails ProcessKeyEventPostIME(
       ui::KeyEvent* event,
-      bool handled,
+      ui::ime::KeyEventHandledState handled_state,
       bool stopped_propagation);
 
   // Resets context and abandon all pending results and key events.
@@ -131,7 +135,8 @@
   // It returns the result of whether the event has been stopped propagation
   // when dispatching post IME.
   [[nodiscard]] ui::EventDispatchDetails ProcessFilteredKeyPressEvent(
-      ui::KeyEvent* event);
+      ui::KeyEvent* event,
+      bool only_dispatch_vkey_processkey);
 
   // Processes a key event that was not filtered by the input method.
   [[nodiscard]] ui::EventDispatchDetails ProcessUnfilteredKeyPressEvent(
@@ -171,7 +176,8 @@
   TextInputMode GetTextInputMode() const;
 
   // Called from the engine when it completes processing.
-  void ProcessKeyEventDone(ui::KeyEvent* event, bool is_handled);
+  void ProcessKeyEventDone(ui::KeyEvent* event,
+                           ui::ime::KeyEventHandledState handled_state);
 
   bool IsPasswordOrNoneInputFieldFocused();
 
diff --git a/ui/base/ime/ash/input_method_ash_unittest.cc b/ui/base/ime/ash/input_method_ash_unittest.cc
index bee6c3c..f1ee63c 100644
--- a/ui/base/ime/ash/input_method_ash_unittest.cc
+++ b/ui/base/ime/ash/input_method_ash_unittest.cc
@@ -64,20 +64,20 @@
   struct ProcessKeyEventPostIMEArgs {
     ProcessKeyEventPostIMEArgs()
         : event(ET_UNKNOWN, VKEY_UNKNOWN, DomCode::NONE, EF_NONE),
-          handled(false) {}
+          handled_state(ui::ime::KeyEventHandledState::kNotHandled) {}
     ui::KeyEvent event;
-    bool handled;
+    ui::ime::KeyEventHandledState handled_state;
   };
 
   // Overridden from InputMethodAsh:
   ui::EventDispatchDetails ProcessKeyEventPostIME(
       ui::KeyEvent* key_event,
-      bool handled,
+      ui::ime::KeyEventHandledState handled_state,
       bool stopped_propagation) override {
     ui::EventDispatchDetails details = InputMethodAsh::ProcessKeyEventPostIME(
-        key_event, handled, stopped_propagation);
+        key_event, handled_state, stopped_propagation);
     process_key_event_post_ime_args_.event = *key_event;
-    process_key_event_post_ime_args_.handled = handled;
+    process_key_event_post_ime_args_.handled_state = handled_state;
     ++process_key_event_post_ime_call_count_;
     return details;
   }
@@ -1026,7 +1026,8 @@
   EXPECT_EQ(0, inserted_char_);
 
   // Do callback.
-  std::move(mock_ime_engine_handler_->last_passed_callback()).Run(true);
+  std::move(mock_ime_engine_handler_->last_passed_callback())
+      .Run(ui::ime::KeyEventHandledState::kHandledByIME);
 
   // Check the results
   EXPECT_EQ(1, input_method_ash_->process_key_event_post_ime_call_count());
@@ -1034,7 +1035,8 @@
       input_method_ash_->process_key_event_post_ime_args().event;
   EXPECT_EQ(ui::VKEY_A, stored_event.key_code());
   EXPECT_EQ(kFlags, stored_event.flags());
-  EXPECT_TRUE(input_method_ash_->process_key_event_post_ime_args().handled);
+  EXPECT_EQ(input_method_ash_->process_key_event_post_ime_args().handled_state,
+            ui::ime::KeyEventHandledState::kHandledByIME);
 
   EXPECT_EQ(L'A', inserted_char_);
 }
@@ -1080,7 +1082,7 @@
   EXPECT_EQ(0, composition_text_.text[0]);
 
   // Do callback for first key event.
-  std::move(first_callback).Run(true);
+  std::move(first_callback).Run(ui::ime::KeyEventHandledState::kHandledByIME);
 
   EXPECT_EQ(comp.text, composition_text_.text);
 
@@ -1090,18 +1092,21 @@
       input_method_ash_->process_key_event_post_ime_args().event;
   EXPECT_EQ(ui::VKEY_B, stored_event.key_code());
   EXPECT_EQ(kFlags, stored_event.flags());
-  EXPECT_TRUE(input_method_ash_->process_key_event_post_ime_args().handled);
+  EXPECT_EQ(input_method_ash_->process_key_event_post_ime_args().handled_state,
+            ui::ime::KeyEventHandledState::kHandledByIME);
   EXPECT_EQ(0, inserted_char_);
 
   // Do callback for second key event.
-  mock_ime_engine_handler_->last_passed_callback().Run(false);
+  mock_ime_engine_handler_->last_passed_callback().Run(
+      ui::ime::KeyEventHandledState::kNotHandled);
 
   // Check the results for second key event.
   EXPECT_EQ(2, input_method_ash_->process_key_event_post_ime_call_count());
   stored_event = input_method_ash_->process_key_event_post_ime_args().event;
   EXPECT_EQ(ui::VKEY_C, stored_event.key_code());
   EXPECT_EQ(kFlags, stored_event.flags());
-  EXPECT_FALSE(input_method_ash_->process_key_event_post_ime_args().handled);
+  EXPECT_EQ(input_method_ash_->process_key_event_post_ime_args().handled_state,
+            ui::ime::KeyEventHandledState::kNotHandled);
 
   EXPECT_EQ(L'C', inserted_char_);
 }
@@ -1116,7 +1121,8 @@
   ui::KeyEvent eventA(ui::ET_KEY_PRESSED, ui::VKEY_A, EF_NONE);
   eventA.set_character(L'A');
   input_method_ash_->DispatchKeyEvent(&eventA);
-  mock_ime_engine_handler_->last_passed_callback().Run(false);
+  mock_ime_engine_handler_->last_passed_callback().Run(
+      ui::ime::KeyEventHandledState::kNotHandled);
 
   const ui::KeyEvent* key_event =
       mock_ime_engine_handler_->last_processed_key_event();
@@ -1126,7 +1132,8 @@
   // Do key event with event not being stopped propagation.
   stop_propagation_post_ime_ = false;
   input_method_ash_->DispatchKeyEvent(&eventA);
-  mock_ime_engine_handler_->last_passed_callback().Run(false);
+  mock_ime_engine_handler_->last_passed_callback().Run(
+      ui::ime::KeyEventHandledState::kNotHandled);
 
   key_event = mock_ime_engine_handler_->last_processed_key_event();
   EXPECT_EQ(ui::VKEY_A, key_event->key_code());
@@ -1143,7 +1150,8 @@
                       DomCode::BRACKET_LEFT, 0,
                       DomKey::DeadKeyFromCombiningCharacter('^'),
                       EventTimeForNow());
-  input_method_ash_->ProcessKeyEventPostIME(&eventA, true, true);
+  input_method_ash_->ProcessKeyEventPostIME(
+      &eventA, ui::ime::KeyEventHandledState::kHandledByIME, true);
 
   const ui::KeyEvent& key_event = dispatched_key_event_;
 
@@ -1155,6 +1163,29 @@
   EXPECT_EQ(eventA.time_stamp(), key_event.time_stamp());
 }
 
+TEST_F(InputMethodAshKeyEventTest,
+       SingleCharAssistiveSuggesterKeyEventDispatchesProcessKey) {
+  ui::KeyEvent event(ui::ET_KEY_PRESSED, ui::VKEY_A, EF_NONE);
+  input_type_ = TEXT_INPUT_TYPE_TEXT;
+
+  input_method_ash_->OnTextInputTypeChanged(this);
+  input_method_ash_->DispatchKeyEvent(&event);
+  static_cast<IMEInputContextHandlerInterface*>(input_method_ash_.get())
+      ->CommitText(
+          u"b",
+          TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
+  std::move(mock_ime_engine_handler_->last_passed_callback())
+      .Run(ui::ime::KeyEventHandledState::kHandledByAssistiveSuggester);
+
+  const ui::KeyEvent& key_event = dispatched_key_event_;
+  EXPECT_EQ(ET_KEY_PRESSED, key_event.type());
+  EXPECT_EQ(VKEY_PROCESSKEY, key_event.key_code());
+  EXPECT_EQ(event.code(), key_event.code());
+  EXPECT_EQ(event.flags(), key_event.flags());
+  EXPECT_EQ(DomKey::PROCESS, key_event.GetDomKey());
+  EXPECT_EQ(event.time_stamp(), key_event.time_stamp());
+}
+
 TEST_F(InputMethodAshKeyEventTest, JP106KeyTest) {
   ui::KeyEvent eventConvert(ET_KEY_PRESSED, VKEY_CONVERT, EF_NONE);
   input_method_ash_->DispatchKeyEvent(&eventConvert);
@@ -1187,7 +1218,7 @@
   input_method_ash_->DispatchKeyEvent(&event);
   input_method_ash_->SetAutocorrectRange(gfx::Range(0, 1));
   std::move(mock_ime_engine_handler_->last_passed_callback())
-      .Run(/*handled=*/true);
+      .Run(ui::ime::KeyEventHandledState::kHandledByIME);
 
   EXPECT_EQ(gfx::Range(0, 1), GetAutocorrectRange());
 }
@@ -1202,7 +1233,7 @@
       u"a", TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
   input_method_ash_->SetAutocorrectRange(gfx::Range(0, 1));
   std::move(mock_ime_engine_handler_->last_passed_callback())
-      .Run(/*handled=*/true);
+      .Run(ui::ime::KeyEventHandledState::kHandledByIME);
 
   EXPECT_EQ(L'a', inserted_char_);
   EXPECT_EQ(gfx::Range(0, 1), GetAutocorrectRange());
@@ -1223,7 +1254,7 @@
   ime.CommitText(
       u"cde", TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
   std::move(mock_ime_engine_handler_->last_passed_callback())
-      .Run(/*handled=*/true);
+      .Run(ui::ime::KeyEventHandledState::kHandledByIME);
 
   EXPECT_EQ(fake_text_input_client.text(), u"abcde");
   EXPECT_EQ(fake_text_input_client.selection(), gfx::Range(5, 5));
@@ -1248,7 +1279,7 @@
   ime.CommitText(
       u"e", TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
   std::move(mock_ime_engine_handler_->last_passed_callback())
-      .Run(/*handled=*/true);
+      .Run(ui::ime::KeyEventHandledState::kHandledByIME);
 
   EXPECT_EQ(fake_text_input_client.text(), u"bceda");
   EXPECT_EQ(fake_text_input_client.selection(), gfx::Range(3, 3));
@@ -1267,7 +1298,7 @@
   ime.CommitText(
       u"", TextInputClient::InsertTextCursorBehavior::kMoveCursorBeforeText);
   std::move(mock_ime_engine_handler_->last_passed_callback())
-      .Run(/*handled=*/true);
+      .Run(ui::ime::KeyEventHandledState::kHandledByIME);
 
   EXPECT_EQ(fake_text_input_client.text(), u"");
   EXPECT_FALSE(fake_text_input_client.HasCompositionText());
@@ -1323,7 +1354,7 @@
   ui::KeyEvent key(ET_KEY_PRESSED, VKEY_A, EF_NONE);
   ime.DispatchKeyEvent(&key);
   std::move(mock_ime_engine_handler_->last_passed_callback())
-      .Run(/*handled=*/true);
+      .Run(ui::ime::KeyEventHandledState::kHandledByIME);
 
   EXPECT_EQ(fake_text_input_client.text(), u"a");
 }
diff --git a/ui/chromeos/strings/network_element_localized_strings_provider.cc b/ui/chromeos/strings/network_element_localized_strings_provider.cc
index 5b64c64e..e7ff3f7 100644
--- a/ui/chromeos/strings/network_element_localized_strings_provider.cc
+++ b/ui/chromeos/strings/network_element_localized_strings_provider.cc
@@ -436,8 +436,6 @@
   };
   html_source->AddLocalizedStrings(kLocalizedStrings);
 
-  html_source->AddBoolean("useAttachApn",
-                          chromeos::features::ShouldUseAttachApn());
   html_source->AddBoolean("isSimLockPolicyEnabled",
                           chromeos::features::IsSimLockPolicyEnabled());
 }
diff --git a/ui/file_manager/file_manager/background/js/trash.js b/ui/file_manager/file_manager/background/js/trash.js
index 107c174..12ce630 100644
--- a/ui/file_manager/file_manager/background/js/trash.js
+++ b/ui/file_manager/file_manager/background/js/trash.js
@@ -9,7 +9,7 @@
 
 import {assert} from 'chrome://resources/js/assert.m.js';
 
-import {TrashConfig, TrashDirs, TrashEntry} from '../../common/js/trash.js';
+import {AUTO_DELETE_INTERVAL_MS, TrashConfig, TrashDirs, TrashEntry} from '../../common/js/trash.js';
 import {util} from '../../common/js/util.js';
 import {VolumeManager} from '../../externs/volume_manager.js';
 
@@ -381,7 +381,7 @@
           }
 
           // Delete entries older than 30d.
-          const ago30d = now - Trash.AUTO_DELETE_INTERVAL_MS;
+          const ago30d = now - AUTO_DELETE_INTERVAL_MS;
           const ago30dStr = new Date(ago30d).toISOString();
           if (d < ago30d) {
             const msg = `Older than ${ago30dStr}, DeletionDate=${found[1]}`;
@@ -401,10 +401,3 @@
     }
   }
 }
-
-/**
- * Interval (ms) until items in trash are permanently deleted. 30 days.
- * @const
- */
-Trash.AUTO_DELETE_INTERVAL_MS = 30 * 24 * 60 * 60 * 1000;
-
diff --git a/ui/file_manager/file_manager/common/js/trash.js b/ui/file_manager/file_manager/common/js/trash.js
index d12a4af..fdb6e69 100644
--- a/ui/file_manager/file_manager/common/js/trash.js
+++ b/ui/file_manager/file_manager/common/js/trash.js
@@ -22,7 +22,7 @@
 import {FilesAppEntry} from '../../externs/files_app_entry_interfaces.js';
 import {VolumeManager} from '../../externs/volume_manager.js';
 
-import {parseTrashInfoFiles} from './api.js';
+import {parseTrashInfoFiles, startIOTask} from './api.js';
 import {FakeEntryImpl} from './files_app_entry_types.js';
 import {metrics} from './metrics.js';
 import {VolumeManagerCommon} from './volume_manager_types.js';
@@ -88,6 +88,11 @@
 ];
 
 /**
+ * Interval (ms) until items in trash are permanently deleted. 30 days.
+ */
+export const AUTO_DELETE_INTERVAL_MS = 30 * 24 * 60 * 60 * 1000;
+
+/**
  * Returns a list of strings that represent volumes that are enabled for Trash.
  * Used to validate drag drop data without resolving the URLs to Entry's.
  * @param {!VolumeManager} volumeManager
@@ -369,8 +374,7 @@
    * @return {?TrashEntry}
    */
   createTrashEntry_(parsedEntry, infoEntry) {
-    const filesEntry = this.filesEntries_[parsedEntry.trashInfoFileName];
-    delete this.filesEntries_[parsedEntry.trashInfoFileName];
+    const filesEntry = this.getFilesEntry(parsedEntry.trashInfoFileName);
 
     // Ignore any .trashinfo file with no matching file entry.
     if (!filesEntry) {
@@ -386,6 +390,18 @@
   }
 
   /**
+   * Returns the Entry from the cached files entries.
+   * @param {string} trashInfoFileName The .trashinfo filename that keys the
+   *     files entry.
+   * @returns {?Entry} The files entry if one exists, null otherwise.
+   */
+  getFilesEntry(trashInfoFileName) {
+    const filesEntry = this.filesEntries_[trashInfoFileName];
+    delete this.filesEntries_[trashInfoFileName];
+    return filesEntry;
+  }
+
+  /**
    * Async version of readEntries(). This function may be called multiple times
    * and returns an empty result to indicate end of stream.
    *
@@ -435,6 +451,8 @@
     // Consume infoReader which is initialized in the first call. Read from
     // .Trash/info until we have at least 1 result, or end of stream.
     const result = [];
+    const entriesToDelete = [];
+    const dateNow = Date.now();
     while (true) {
       let entries = [];
       try {
@@ -460,6 +478,16 @@
         return;
       }
       for (const parsedEntry of parsedEntries) {
+        // In the event the parsed entry was deleted more than 30 days ago,
+        // schedule them for deletion and don't render them in the view.
+        if (parsedEntry.deletionDate < (dateNow - AUTO_DELETE_INTERVAL_MS)) {
+          entriesToDelete.push(infoEntryMap[parsedEntry.trashInfoFileName]);
+          const trashEntry = this.getFilesEntry(parsedEntry.trashInfoFileName);
+          if (trashEntry) {
+            entriesToDelete.push(trashEntry);
+          }
+          continue;
+        }
         const trashEntry = this.createTrashEntry_(
             parsedEntry, infoEntryMap[parsedEntry.trashInfoFileName]);
         if (trashEntry) {
@@ -472,6 +500,12 @@
     }
     success(result);
 
+    if (entriesToDelete.length > 0) {
+      startIOTask(
+          chrome.fileManagerPrivate.IOTaskType.DELETE, entriesToDelete,
+          {showNotification: false});
+    }
+
     // Record the amount of files seen for this particularly directory reader.
     metrics.recordMediumCount(
         /*name=*/ `TrashFiles.${this.config_.volumeType}`, result.length);
diff --git a/ui/file_manager/integration_tests/file_manager/trash.js b/ui/file_manager/integration_tests/file_manager/trash.js
index 15925d7..e3836331 100644
--- a/ui/file_manager/integration_tests/file_manager/trash.js
+++ b/ui/file_manager/integration_tests/file_manager/trash.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import {DialogType} from '../dialog_type.js';
-import {addEntries, RootPath} from '../test_util.js';
+import {addEntries, ENTRIES, RootPath} from '../test_util.js';
 import {testcase} from '../testcase.js';
 
 import {navigateWithDirectoryTree, openNewWindow, remoteCall, setupAndWaitUntilReady} from './background.js';
@@ -678,3 +678,46 @@
   await remoteCall.waitForElementLost(
       appId, '#directory-tree [entry-label="Trash"]');
 };
+
+/**
+ * Tests that a trashed file with a deletion date >30 days gets permanently
+ * removed.
+ */
+testcase.trashEnsureOldEntriesArePeriodicallyRemoved = async () => {
+  const appId =
+      await setupAndWaitUntilReady(RootPath.DOWNLOADS, [ENTRIES.hello], []);
+  const fileNameSelector = '#file-list [file-name="hello.txt"]';
+
+  // Select hello.txt and make sure a default task is executed when double
+  // clicking.
+  await remoteCall.waitAndClickElement(appId, fileNameSelector);
+  await remoteCall.waitAndClickElement(appId, '#move-to-trash-button');
+  await remoteCall.waitForElementLost(appId, fileNameSelector);
+
+  // Navigate to /Trash and ensure the file is there and has not been deleted,
+  // the deletion date is well within the periodic deletion boundaries.
+  await navigateWithDirectoryTree(appId, '/Trash');
+  await remoteCall.waitForElement(appId, fileNameSelector);
+
+  // Navigate away from /Trash (to /My files) as the periodic removal will only
+  // be kicked off on initial directory scan.
+  await navigateWithDirectoryTree(appId, '/My files');
+
+  // Overwrite the existing .trashinfo file with an older one that is outside
+  // the 30 day window and should trigger periodic removal.
+  await addEntries(['local'], [
+    ENTRIES.trashRootDirectory,
+    ENTRIES.trashInfoDirectory,
+    ENTRIES.oldTrashInfoFile,
+  ]);
+
+  // Navigate to /Trash and ensure the file has been removed.
+  await navigateWithDirectoryTree(appId, '/Trash');
+  await remoteCall.waitForElement(appId, `[scan-completed="Trash"]`);
+  await remoteCall.waitForElementLost(appId, fileNameSelector);
+
+  // Expect no feedback panel element to appear as the IOTask was kicked off
+  // with notifications disabled.
+  await remoteCall.waitForElementLost(
+      appId, ['#progress-panel', 'xf-panel-item']);
+};
diff --git a/ui/file_manager/integration_tests/test_util.js b/ui/file_manager/integration_tests/test_util.js
index 39e9fc60..d0428af4 100644
--- a/ui/file_manager/integration_tests/test_util.js
+++ b/ui/file_manager/integration_tests/test_util.js
@@ -1568,6 +1568,35 @@
     sizeText: '51 bytes',
     typeText: 'Plain text',
   }),
+
+  trashRootDirectory: new TestEntryInfo({
+    type: EntryType.DIRECTORY,
+    targetPath: '.Trash',
+    lastModifiedTime: 'Jan 1, 1980, 11:59 PM',
+    nameText: '.Trash',
+    sizeText: '--',
+    typeText: 'Folder',
+  }),
+
+  trashInfoDirectory: new TestEntryInfo({
+    type: EntryType.DIRECTORY,
+    targetPath: '.Trash/info',
+    lastModifiedTime: 'Jan 1, 1980, 11:59 PM',
+    nameText: 'info',
+    sizeText: '--',
+    typeText: 'Folder',
+  }),
+
+  oldTrashInfoFile: new TestEntryInfo({
+    type: EntryType.FILE,
+    sourceFileName: 'old_file.trashinfo',
+    targetPath: '.Trash/info/hello.txt.trashinfo',
+    lastModifiedTime: 'Jan 1, 1980, 11:59 PM',
+    mimeType: 'text/plan',
+    nameText: 'hello.txt.trashinfo',
+    sizeText: '64 bytes',
+    typeText: 'TRASHINFO',
+  }),
 };
 
 
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate.cc b/ui/views/accessibility/view_ax_platform_node_delegate.cc
index a3cca9d7..aa464c10 100644
--- a/ui/views/accessibility/view_ax_platform_node_delegate.cc
+++ b/ui/views/accessibility/view_ax_platform_node_delegate.cc
@@ -462,8 +462,8 @@
         ->Unserialize(update);
   }
 
-  return ui::AXNodePosition::CreatePosition(
-      *dummy_tree_manager_->GetRootAsAXNode(), offset, affinity);
+  return ui::AXNodePosition::CreatePosition(*dummy_tree_manager_->GetRoot(),
+                                            offset, affinity);
 }
 
 gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::GetNSWindow() {
diff --git a/ui/views/accessibility/views_ax_tree_manager_unittest.cc b/ui/views/accessibility/views_ax_tree_manager_unittest.cc
index 6d4f5c9..8139637f 100644
--- a/ui/views/accessibility/views_ax_tree_manager_unittest.cc
+++ b/ui/views/accessibility/views_ax_tree_manager_unittest.cc
@@ -147,7 +147,7 @@
 ui::AXNode* ViewsAXTreeManagerTest::FindNode(
     const ax::mojom::Role role,
     const std::string& name_or_value) const {
-  ui::AXNode* root = manager()->GetRootAsAXNode();
+  ui::AXNode* root = manager()->GetRoot();
 
   // If the manager has been closed, it will return nullptr as root.
   if (!root)
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_apnlist.html b/ui/webui/resources/cr_components/chromeos/network/network_apnlist.html
index eff33cec..7f364c3 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_apnlist.html
+++ b/ui/webui/resources/cr_components/chromeos/network/network_apnlist.html
@@ -60,21 +60,19 @@
             edit-field-types="[[otherApnEditTypes_]]" prefix="cellular.apn."
             disabled="[[disabled]]">
         </network-property-list-mojo>
-        <template is="dom-if" if="[[isAttachApnAllowed_]]">
-          <div id="attachApnPropertyRow" class="property-box horizontal center">
-            <div id="attachApnDescription" class="start" aria-hidden="true">
-              <span id="attachApnTitle">[[i18n('OncCellular-APN-Attach')]]</span>
-              <cr-tooltip-icon id="attachApnTooltip" tooltip-position="right"
-                  icon-class="cr:help-outline"
-                  tooltip-text="[[i18n('OncCellular-APN-Attach_TooltipText')]]">
-              </cr-tooltip-icon>
-            </div>
-            <cr-toggle id="attachApnControl" aria-labelledby="attachApnTitle"
-                aria-describedby="attachApnTooltip"
-                checked="{{isAttachApnToggleEnabled_}}">
-            </cr-toggle>
+        <div id="attachApnPropertyRow" class="property-box horizontal center">
+          <div id="attachApnDescription" class="start" aria-hidden="true">
+            <span id="attachApnTitle">[[i18n('OncCellular-APN-Attach')]]</span>
+            <cr-tooltip-icon id="attachApnTooltip" tooltip-position="right"
+                icon-class="cr:help-outline"
+                tooltip-text="[[i18n('OncCellular-APN-Attach_TooltipText')]]">
+            </cr-tooltip-icon>
           </div>
-        </template>
+          <cr-toggle id="attachApnControl" aria-labelledby="attachApnTitle"
+              aria-describedby="attachApnTooltip"
+              checked="{{isAttachApnToggleEnabled_}}">
+          </cr-toggle>
+        </div>
         <cr-button id="saveButton" class="action-button"
             on-click="onSaveOtherTap_" disabled="[[disabled]]">
           [[i18n('save')]]
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_apnlist.js b/ui/webui/resources/cr_components/chromeos/network/network_apnlist.js
index 4d1f28f..0a5d52b 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_apnlist.js
+++ b/ui/webui/resources/cr_components/chromeos/network/network_apnlist.js
@@ -101,15 +101,6 @@
     },
 
     /** @private */
-    isAttachApnAllowed_: {
-      type: Boolean,
-      value() {
-        return loadTimeData.valueExists('useAttachApn') &&
-            loadTimeData.getBoolean('useAttachApn');
-      },
-    },
-
-    /** @private */
     isAttachApnToggleEnabled_: {
       type: Boolean,
       value: false,
@@ -319,7 +310,7 @@
    * @private
    */
   onSaveOtherTap_() {
-    if (this.sendApnChange_(this.selectedApn_) && this.isAttachApnAllowed_) {
+    if (this.sendApnChange_(this.selectedApn_)) {
       chrome.metricsPrivate.recordBoolean(
           USE_ATTACH_APN_ON_SAVE_METRIC_NAME, this.isAttachApnToggleEnabled_);
     }