diff --git a/DEPS b/DEPS
index 0ee5d7c..00603460 100644
--- a/DEPS
+++ b/DEPS
@@ -275,15 +275,15 @@
   # 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': '8f7abc5eee87eb6afefc902add48c509a990fb7f',
+  'skia_revision': '48cb5bc138aea78b5350272481ff78d6fb8d6335',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '14c5ef09fc64e934f0b859b8e9323f7c907166f3',
+  'v8_revision': '693814c3949fb5a92e8bcd23c9946704190b9c12',
   # 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': '1ce69722a89116601fc16b9aca5f8ffd126a0535',
+  'angle_revision': '9800a3cf3f7ccebfc91c85979aa94516d571b304',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -326,7 +326,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
-  'freetype_revision': 'b98dd169a1823485e35b3007ce707a6712dcd525',
+  'freetype_revision': 'd6857981239ea5f6e95cb4eb4402307f3527760a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
@@ -354,7 +354,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': 'b1f1172776e6e94bae134c44a8d95851700054a4',
+  'devtools_frontend_revision': 'fba45c59e90b0362070ef206dff6dddb3eb2413e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -390,11 +390,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '08f4b557fcf03e7fa6fea0342fb47b7c194f27be',
+  'dawn_revision': '1ee244b3d3cd23962c9b1292cff4f80fa7dc358b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'quiche_revision': '66cfacd105f168803bfc75dd99f2555d0e6bbe5c',
+  'quiche_revision': '2c30ea85887a86e93df9a74207d9f51d80b0cf3a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ios_webkit
   # and whatever else without interference from each other.
@@ -751,7 +751,7 @@
   },
 
   'src/ios/third_party/earl_grey2/src': {
-      'url': Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + 'd423acd46f8938bd66a15f999259d8977a8d9361',
+      'url': Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + '31af87eb29f2bf39da0e4adb29fb174de11bdd1d',
       'condition': 'checkout_ios',
   },
 
@@ -1136,7 +1136,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '739a76e05d134ed412732efcffe8a8b3f6891403',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'e1197f06a8f45c0328d341b30e337d3a4b609716',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1516,7 +1516,7 @@
     Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + 'fac04ceb3e966f613ed17e98178e9d690280bba6',
 
   'src/third_party/openscreen/src':
-    Var('chromium_git') + '/openscreen' + '@' + 'a82e9e4df560dc770e358b907128d378e35541ca',
+    Var('chromium_git') + '/openscreen' + '@' + 'b4283729c944a55837024e0d70f1482647541d18',
 
   'src/third_party/openxr/src': {
     'url': Var('chromium_git') + '/external/github.com/KhronosGroup/OpenXR-SDK' + '@' + 'bf21ccb1007bb531b45d9978919a56ea5059c245',
@@ -1669,7 +1669,7 @@
       'condition': 'checkout_android',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@59aa5963cf6476846f7537136b7dac4fdeec98ff',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@ba231aba224387afee7eb9ac2869c0063f3d89e0',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907',
@@ -1705,10 +1705,10 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'bb289ce3cb15bbabd42fdcb01439367846d9069d',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '24c2a787daefb05e27c1689f5ef6cc491eeadb1c',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'e4ee0a51309c6b5bfcaa1e85656a4377a1a747b2',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'ee6ad1403ae6c2c853097b8928253e5d29228046',
+    Var('webrtc_git') + '/src.git' + '@' + '563dfd1948d7d27296fcef59f163f4db087c6489',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1781,7 +1781,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@0f593bfb2966b8d668cd3fdd09bbd26a7c8ce6a9',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@5f96f117ce75d9e77af21160c438dcac73b781e6',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/gfx/gpu_service_webview.cc b/android_webview/browser/gfx/gpu_service_webview.cc
index c488be26..ffe31384 100644
--- a/android_webview/browser/gfx/gpu_service_webview.cc
+++ b/android_webview/browser/gfx/gpu_service_webview.cc
@@ -29,9 +29,9 @@
   gpu::GpuPreferences gpu_preferences =
       content::GetGpuPreferencesFromCommandLine();
   auto* command_line = base::CommandLine::ForCurrentProcess();
-  gl::GLDisplay* display = gpu::InitializeGLThreadSafe(
-      command_line, gpu_preferences, &gpu_info, &gpu_feature_info);
-  if (!display) {
+  bool success = gpu::InitializeGLThreadSafe(command_line, gpu_preferences,
+                                             &gpu_info, &gpu_feature_info);
+  if (!success) {
     LOG(FATAL) << "gpu::InitializeGLThreadSafe() failed.";
   }
   auto sync_point_manager = std::make_unique<gpu::SyncPointManager>();
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
index 86a0bb6..9ae21ef 100644
--- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
+++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -186,12 +186,6 @@
             Flag.baseFeature(AutofillFeatures.AUTOFILL_PARSE_MERCHANT_PROMO_CODE_FIELDS,
                     "When enabled, Autofill will attempt to find merchant promo/coupon/gift code "
                             + "fields when parsing forms."),
-            Flag.baseFeature(AutofillFeatures.AUTOFILL_UPSTREAM_ALLOW_ADDITIONAL_EMAIL_DOMAINS,
-                    "When enabled, Autofill will allow credit card upload save for select "
-                            + "non-Google-based accounts."),
-            Flag.baseFeature(AutofillFeatures.AUTOFILL_UPSTREAM_ALLOW_ALL_EMAIL_DOMAINS,
-                    "When enabled, Autofill will allow credit card upload save for all "
-                            + "non-Google-based accounts."),
             Flag.baseFeature(AutofillFeatures.AUTOFILL_ENABLE_NAME_SURENAME_PARSING,
                     "Adds new name surname field combinations to the parsing logic"),
             Flag.baseFeature(AutofillFeatures.AUTOFILL_RATIONALIZE_STREET_ADDRESS_AND_ADDRESS_LINE,
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index f7f7d9f..e331336 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -185,6 +185,9 @@
 const base::Feature kAssistPersonalInfoPhoneNumber{
     "AssistPersonalInfoPhoneNumber", base::FEATURE_ENABLED_BY_DEFAULT};
 
+const base::Feature kAssistantNativeIcons{"AssistantNativeIcons",
+                                          base::FEATURE_ENABLED_BY_DEFAULT};
+
 // Enables the Audio Settings Page in System Settings, which allows
 // audio configuration. crbug.com/1092970.
 const base::Feature kAudioSettingsPage{"AudioSettingsPage",
@@ -531,11 +534,6 @@
     "EnableExternalKeyboardsInDiagnosticsApp",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Enables displaying additional OpenVPN configuration values on the network
-// details page.
-const base::Feature kExtendedOpenVpnSettings{"ExtendedOpenVpnSettings",
-                                             base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Enables setting the device hostname.
 const base::Feature kEnableHostnameSetting{"EnableHostnameSetting",
                                            base::FEATURE_DISABLED_BY_DEFAULT};
@@ -1653,6 +1651,10 @@
   return IsNetworkingInDiagnosticsAppEnabled();
 }
 
+bool IsAssistantNativeIconsEnabled() {
+  return base::FeatureList::IsEnabled(kAssistantNativeIcons);
+}
+
 bool IsAssistiveMultiWordEnabled() {
   return base::FeatureList::IsEnabled(kAssistMultiWord);
 }
@@ -1789,10 +1791,6 @@
   return base::FeatureList::IsEnabled(kExperimentalRgbKeyboardPatterns);
 }
 
-bool IsExtendedOpenVpnSettingsEnabled() {
-  return base::FeatureList::IsEnabled(kExtendedOpenVpnSettings);
-}
-
 bool IsExternalKeyboardInDiagnosticsAppEnabled() {
   return base::FeatureList::IsEnabled(kEnableExternalKeyboardsInDiagnostics);
 }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 402c13dd..c65f843 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -87,6 +87,8 @@
 extern const base::Feature kAssistPersonalInfoName;
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kAssistPersonalInfoPhoneNumber;
+COMPONENT_EXPORT(ASH_CONSTANTS)
+extern const base::Feature kAssistantNativeIcons;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kAudioUrl;
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kAutoNightLight;
@@ -261,8 +263,6 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kEnforceAshExtensionKeeplist;
 COMPONENT_EXPORT(ASH_CONSTANTS)
-extern const base::Feature kExtendedOpenVpnSettings;
-COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kEolWarningNotifications;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kESimPolicy;
 COMPONENT_EXPORT(ASH_CONSTANTS)
@@ -631,6 +631,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsAppNotificationsPageEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsArcInputOverlayEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsArcNetworkDiagnosticsButtonEnabled();
+COMPONENT_EXPORT(ASH_CONSTANTS) bool IsAssistantNativeIconsEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsAssistiveMultiWordEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsAudioSettingsPageEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsAutoNightLightEnabled();
@@ -668,7 +669,6 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsESimPolicyEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS)
 bool IsExperimentalRgbKeyboardPatternsEnabled();
-COMPONENT_EXPORT(ASH_CONSTANTS) bool IsExtendedOpenVpnSettingsEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS)
 bool IsExternalKeyboardInDiagnosticsAppEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFamilyLinkOnSchoolDeviceEnabled();
diff --git a/ash/webui/camera_app_ui/resources/utils/cca.py b/ash/webui/camera_app_ui/resources/utils/cca.py
index bac2ff71..718986c2 100755
--- a/ash/webui/camera_app_ui/resources/utils/cca.py
+++ b/ash/webui/camera_app_ui/resources/utils/cca.py
@@ -151,6 +151,15 @@
         '--inplace',
         '--delete',
         '--mkpath',
+        # rsync by default use source file permission masked by target file
+        # system umask while transferring new files, and since workstation
+        # defaults to have file not readable by others, this makes deployed
+        # file not readable by Chrome.
+        # Set --chmod=+r to rsync to fix this, and set --perms so existing
+        # files that might have the wrong permission will have their permission
+        # fixed.
+        '--perms',
+        '--chmod=+r',
         f'{tsc_dir}/',
         f'{args.device}:{CCA_OVERRIDE_PATH}/js/',
     ]
@@ -163,6 +172,8 @@
             '--inplace',
             '--delete',
             '--mkpath',
+            '--perms',
+            '--chmod=+r',
             f'{os.path.join(cca_root, dir)}/',
             f'{args.device}:{CCA_OVERRIDE_PATH}/{dir}/',
         ]
diff --git a/ash/webui/shimless_rma/resources/wrapup_repair_complete_page.html b/ash/webui/shimless_rma/resources/wrapup_repair_complete_page.html
index b07871e5..c2f473a 100644
--- a/ash/webui/shimless_rma/resources/wrapup_repair_complete_page.html
+++ b/ash/webui/shimless_rma/resources/wrapup_repair_complete_page.html
@@ -41,6 +41,10 @@
     width: 100%;
   }
 
+  .button-card:focus {
+    outline: rgba(var(--google-blue-600-rgb), .4) solid 2px;
+  }
+
   #diagnosticsButton {
     margin-bottom: 16px;
   }
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1
index c08cd64..c33e4ead 100644
--- a/build/fuchsia/linux_internal.sdk.sha1
+++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@
-8.20220531.2.1
+8.20220531.3.1
diff --git a/cc/resources/resource_pool.cc b/cc/resources/resource_pool.cc
index 23efa96..5ff92dc 100644
--- a/cc/resources/resource_pool.cc
+++ b/cc/resources/resource_pool.cc
@@ -339,7 +339,9 @@
         gpu_backing->mailbox, GL_LINEAR, gpu_backing->texture_target,
         gpu_backing->mailbox_sync_token, resource->size(),
         gpu_backing->overlay_candidate);
-    transferable.read_lock_fences_enabled = gpu_backing->wait_on_fence_required;
+    if (gpu_backing->wait_on_fence_required)
+      transferable.synchronization_type =
+          viz::TransferableResource::SynchronizationType::kGpuCommandsCompleted;
   } else {
     transferable = viz::TransferableResource::MakeSoftware(
         resource->software_backing()->shared_bitmap_id, resource->size(),
diff --git a/cc/resources/resource_pool_unittest.cc b/cc/resources/resource_pool_unittest.cc
index 24d04f3..45104e7 100644
--- a/cc/resources/resource_pool_unittest.cc
+++ b/cc/resources/resource_pool_unittest.cc
@@ -722,7 +722,9 @@
   EXPECT_EQ(transfer[0].mailbox_holder.sync_token, sync_token);
   EXPECT_EQ(transfer[0].mailbox_holder.texture_target, target);
   EXPECT_EQ(transfer[0].format, format);
-  EXPECT_TRUE(transfer[0].read_lock_fences_enabled);
+  EXPECT_EQ(
+      transfer[0].synchronization_type,
+      viz::TransferableResource::SynchronizationType::kGpuCommandsCompleted);
   EXPECT_TRUE(transfer[0].is_overlay_candidate);
 
   resource_pool_->ReleaseResource(std::move(resource));
diff --git a/chrome/VERSION b/chrome/VERSION
index 96ebb63..e3f64aad 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=104
 MINOR=0
-BUILD=5096
+BUILD=5097
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabViewAndroidDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabViewAndroidDelegate.java
index a42cf9a5f..f0441e6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabViewAndroidDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabViewAndroidDelegate.java
@@ -4,11 +4,18 @@
 
 package org.chromium.chrome.browser.tab;
 
+import android.app.Activity;
+import android.os.Build;
+import android.os.Build.VERSION;
+import android.view.DragAndDropPermissions;
+import android.view.DragEvent;
 import android.view.ViewGroup;
 
 import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
 
 import org.chromium.base.Callback;
+import org.chromium.base.ContextUtils;
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.components.embedder_support.view.ContentView;
 import org.chromium.content_public.browser.ContentFeatureList;
@@ -16,6 +23,7 @@
 import org.chromium.content_public.common.ContentFeatures;
 import org.chromium.ui.base.ViewAndroidDelegate;
 import org.chromium.ui.base.WindowAndroid;
+import org.chromium.ui.dragdrop.DragAndDropBrowserDelegate;
 import org.chromium.ui.dragdrop.DragStateTracker;
 import org.chromium.ui.dragdrop.DropDataContentProvider;
 
@@ -40,15 +48,20 @@
         super(containerView);
         mTab = (TabImpl) tab;
         containerView.addOnDragListener(getDragStateTracker());
+
         if (ContentFeatureList.isEnabled(ContentFeatures.TOUCH_DRAG_AND_CONTEXT_MENU)) {
             int delay = ContentFeatureList.getFieldTrialParamByFeatureAsInt(
                     ContentFeatures.TOUCH_DRAG_AND_CONTEXT_MENU, PARAM_CLEAR_CACHE_DELAYED_MS,
                     DropDataContentProvider.DEFAULT_CLEAR_CACHED_DATA_INTERVAL_MS);
             DropDataContentProvider.setClearCachedDataIntervalMs(delay);
 
-            boolean dropInChrome = ContentFeatureList.getFieldTrialParamByFeatureAsBoolean(
+            boolean supportDropInChrome = ContentFeatureList.getFieldTrialParamByFeatureAsBoolean(
                     ContentFeatures.TOUCH_DRAG_AND_CONTEXT_MENU, PARAM_DROP_IN_CHROME, false);
-            getDragAndDropDelegate().enableDropInChrome(dropInChrome);
+            if (VERSION.SDK_INT >= Build.VERSION_CODES.N && supportDropInChrome) {
+                DragAndDropBrowserDelegate browserDelegate =
+                        new DragAndDropBrowserDelegateImpl(mTab, supportDropInChrome);
+                getDragAndDropDelegate().setDragAndDropBrowserDelegate(browserDelegate);
+            }
         }
 
         Callback<Integer> insetObserver = (inset) -> updateInsetViewportBottom();
@@ -154,4 +167,32 @@
             getContentView().removeOnDragListener(getDragStateTracker());
         }
     }
+
+    /**
+     * Delegate for browser related functions used by Drag and Drop.
+     */
+    static class DragAndDropBrowserDelegateImpl implements DragAndDropBrowserDelegate {
+        private final TabImpl mTab;
+        private final boolean mSupportDropInChrome;
+
+        public DragAndDropBrowserDelegateImpl(TabImpl tab, boolean supportDropInChrome) {
+            mTab = tab;
+            mSupportDropInChrome = supportDropInChrome;
+        }
+
+        @Override
+        public boolean getSupportDropInChrome() {
+            return mSupportDropInChrome;
+        }
+
+        @Override
+        @RequiresApi(Build.VERSION_CODES.N)
+        public DragAndDropPermissions getDragAndDropPermissions(DragEvent dropEvent) {
+            Activity activity = ContextUtils.activityFromContext(mTab.getContext());
+            if (activity == null) {
+                return null;
+            }
+            return activity.requestDragAndDropPermissions(dropEvent);
+        }
+    }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tab/TabViewAndroidDelegateTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/tab/TabViewAndroidDelegateTest.java
index bab73fe..4e5d3ec 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/tab/TabViewAndroidDelegateTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/tab/TabViewAndroidDelegateTest.java
@@ -5,9 +5,16 @@
 package org.chromium.chrome.browser.tab;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.Activity;
+import android.os.Build;
+import android.view.DragAndDropPermissions;
+import android.view.DragEvent;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -21,11 +28,13 @@
 import org.chromium.base.FeatureList.TestValues;
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.chrome.browser.tab.TabViewAndroidDelegate.DragAndDropBrowserDelegateImpl;
 import org.chromium.components.embedder_support.view.ContentView;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.common.ContentFeatures;
 import org.chromium.ui.base.ApplicationViewportInsetSupplier;
 import org.chromium.ui.base.WindowAndroid;
+import org.chromium.ui.dragdrop.DragAndDropBrowserDelegate;
 
 /** Unit tests for the TabViewAndroidDelegate. */
 @RunWith(BaseRobolectricTestRunner.class)
@@ -46,6 +55,15 @@
     @Mock
     private ContentView mContentView;
 
+    @Mock
+    private DragEvent mDragEvent;
+
+    @Mock
+    private DragAndDropPermissions mDragAndDropPermissions;
+
+    @Mock
+    private Activity mActivity;
+
     private ApplicationViewportInsetSupplier mApplicationInsetSupplier;
     private ObservableSupplierImpl<Integer> mFeatureInsetSupplier;
     private TabViewAndroidDelegate mViewAndroidDelegate;
@@ -63,6 +81,9 @@
                 .thenReturn(mApplicationInsetSupplier);
         when(mTab.getWindowAndroid()).thenReturn(mWindowAndroid);
         when(mTab.getWebContents()).thenReturn(mWebContents);
+        when(mTab.getContext()).thenReturn(mActivity);
+        when(mActivity.requestDragAndDropPermissions(mDragEvent))
+                .thenReturn(mDragAndDropPermissions);
 
         FeatureList.TestValues testValues = new TestValues();
         testValues.addFeatureFlagOverride(ContentFeatures.TOUCH_DRAG_AND_CONTEXT_MENU, false);
@@ -106,4 +127,14 @@
         assertEquals("The bottom inset for the tab should be non-zero.", 10,
                 mViewAndroidDelegate.getViewportInsetBottom());
     }
+
+    @Test
+    public void testDragAndDropBrowserDelegate() {
+        DragAndDropBrowserDelegate delegate = new DragAndDropBrowserDelegateImpl(mTab, true);
+        assertTrue("SupportDropInChrome should be true.", delegate.getSupportDropInChrome());
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            DragAndDropPermissions permissions = delegate.getDragAndDropPermissions(mDragEvent);
+            assertNotNull("DragAndDropPermissions should not be null.", permissions);
+        }
+    }
 }
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index ef03c8a..cd79435 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -642,6 +642,8 @@
     "lifetime/application_lifetime.h",
     "lifetime/browser_shutdown.cc",
     "lifetime/browser_shutdown.h",
+    "lifetime/termination_notification.cc",
+    "lifetime/termination_notification.h",
     "login_detection/login_detection_keyed_service.cc",
     "login_detection/login_detection_keyed_service.h",
     "login_detection/login_detection_keyed_service_factory.cc",
@@ -3804,8 +3806,6 @@
       "intranet_redirect_detector.h",
       "lifetime/browser_close_manager.cc",
       "lifetime/browser_close_manager.h",
-      "lifetime/termination_notification.cc",
-      "lifetime/termination_notification.h",
       "media/capture_access_handler_base.cc",
       "media/capture_access_handler_base.h",
       "media/unified_autoplay_config.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 1e0dae776..e40f5c9b 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3743,10 +3743,6 @@
     {"esim-policy", flag_descriptions::kESimPolicyName,
      flag_descriptions::kESimPolicyDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(chromeos::features::kESimPolicy)},
-    {"extended-open-vpn-settings",
-     flag_descriptions::kExtendedOpenVpnSettingsName,
-     flag_descriptions::kExtendedOpenVpnSettingsDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(ash::features::kExtendedOpenVpnSettings)},
     {"dns-proxy-enable-doh", flag_descriptions::kDnsProxyEnableDOHName,
      flag_descriptions::kDnsProxyEnableDOHDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(::features::kDnsProxyEnableDOH)},
diff --git a/chrome/browser/apps/app_service/app_service_proxy_base.cc b/chrome/browser/apps/app_service/app_service_proxy_base.cc
index 4a883546..8e4d492 100644
--- a/chrome/browser/apps/app_service/app_service_proxy_base.cc
+++ b/chrome/browser/apps/app_service/app_service_proxy_base.cc
@@ -659,6 +659,13 @@
   if (app_id == apps_util::kUseBrowserForLink) {
     std::vector<apps::mojom::IntentFilterPtr> filters;
     filters.push_back(std::move(mojom_intent_filter));
+    if (preferred_apps_impl_) {
+      preferred_apps_impl_->SetSupportedLinksPreference(
+          AppType::kUnknown, app_id,
+          ConvertMojomIntentFiltersToIntentFilters(filters));
+      return;
+    }
+
     app_service_->SetSupportedLinksPreference(apps::mojom::AppType::kUnknown,
                                               app_id, std::move(filters));
     return;
@@ -684,19 +691,25 @@
     return;
   }
 
-  std::vector<apps::mojom::IntentFilterPtr> filters;
+  IntentFilters filters;
   AppRegistryCache().ForOneApp(
       app_id, [&app_id, &filters](const AppUpdate& app) {
         for (auto& filter : app.IntentFilters()) {
           if (apps_util::IsSupportedLinkForApp(app_id, filter)) {
-            filters.push_back(ConvertIntentFilterToMojomIntentFilter(filter));
+            filters.push_back(std::move(filter));
           }
         }
       });
 
+  if (preferred_apps_impl_) {
+    preferred_apps_impl_->SetSupportedLinksPreference(
+        app_registry_cache_.GetAppType(app_id), app_id, std::move(filters));
+    return;
+  }
+
   app_service_->SetSupportedLinksPreference(
       ConvertAppTypeToMojomAppType(app_registry_cache_.GetAppType(app_id)),
-      app_id, std::move(filters));
+      app_id, ConvertIntentFiltersToMojomIntentFilters(filters));
 }
 
 void AppServiceProxyBase::RemoveSupportedLinksPreference(
diff --git a/chrome/browser/ash/app_restore/arc_ghost_window_delegate.cc b/chrome/browser/ash/app_restore/arc_ghost_window_delegate.cc
index 08294f4..cf9e043c 100644
--- a/chrome/browser/ash/app_restore/arc_ghost_window_delegate.cc
+++ b/chrome/browser/ash/app_restore/arc_ghost_window_delegate.cc
@@ -20,11 +20,12 @@
     ArcWindowHandler* handler,
     int window_id,
     int64_t display_id,
-    const gfx::Rect& bounds)
+    const gfx::Rect& bounds,
+    chromeos::WindowStateType window_state)
     : window_id_(window_id),
       bounds_(gfx::Rect(bounds)),
       pending_close_(false),
-      window_state_(chromeos::WindowStateType::kDefault),
+      window_state_(window_state),
       shell_surface_(shell_surface),
       arc_handler_(handler) {
   DCHECK(shell_surface);
diff --git a/chrome/browser/ash/app_restore/arc_ghost_window_delegate.h b/chrome/browser/ash/app_restore/arc_ghost_window_delegate.h
index 58c0e05..268d250 100644
--- a/chrome/browser/ash/app_restore/arc_ghost_window_delegate.h
+++ b/chrome/browser/ash/app_restore/arc_ghost_window_delegate.h
@@ -24,7 +24,8 @@
                          ArcWindowHandler* handler,
                          int window_id,
                          int64_t display_id,
-                         const gfx::Rect& bounds);
+                         const gfx::Rect& bounds,
+                         chromeos::WindowStateType window_state);
   ~ArcGhostWindowDelegate() override;
 
   // exo::ClientControlledShellSurface::Delegate
diff --git a/chrome/browser/ash/app_restore/arc_ghost_window_shell_surface.cc b/chrome/browser/ash/app_restore/arc_ghost_window_shell_surface.cc
index 1ec1ad8..31f9227b 100644
--- a/chrome/browser/ash/app_restore/arc_ghost_window_shell_surface.cc
+++ b/chrome/browser/ash/app_restore/arc_ghost_window_shell_surface.cc
@@ -120,7 +120,7 @@
   // TODO(sstan): Add set_surface_destroyed_callback.
   shell_surface->set_delegate(std::make_unique<ArcGhostWindowDelegate>(
       shell_surface.get(), window_handler, window_id, display_id_value,
-      local_bounds));
+      local_bounds, window_state.value_or(chromeos::WindowStateType::kDefault)));
   shell_surface->set_close_callback(std::move(close_callback));
 
   shell_surface->SetAppId(app_id);
diff --git a/chrome/browser/ash/app_restore/full_restore_app_launch_handler_browsertest.cc b/chrome/browser/ash/app_restore/full_restore_app_launch_handler_browsertest.cc
index 23daa0fc..7848ea2 100644
--- a/chrome/browser/ash/app_restore/full_restore_app_launch_handler_browsertest.cc
+++ b/chrome/browser/ash/app_restore/full_restore_app_launch_handler_browsertest.cc
@@ -34,7 +34,6 @@
 #include "chrome/browser/ash/crosapi/browser_util.h"
 #include "chrome/browser/ash/web_applications/system_web_app_integration_test.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/notifications/notification_display_service_tester.h"
 #include "chrome/browser/prefs/session_startup_pref.h"
 #include "chrome/browser/profiles/profile.h"
@@ -66,8 +65,6 @@
 #include "components/services/app_service/public/cpp/features.h"
 #include "components/services/app_service/public/mojom/types.mojom.h"
 #include "components/strings/grit/components_strings.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_source.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/test_utils.h"
@@ -1039,10 +1036,7 @@
   WaitForAppLaunchInfoSaved();
 
   // Simulate the system shutdown process, and the window is closed.
-  FullRestoreService::GetForProfile(profile())->Observe(
-      chrome::NOTIFICATION_APP_TERMINATING,
-      content::Source<extensions::AppWindow>(app_window),
-      content::NotificationDetails());
+  FullRestoreService::GetForProfile(profile())->OnAppTerminating();
   CloseAppWindow(app_window);
   WaitForAppLaunchInfoSaved();
 
@@ -1565,9 +1559,7 @@
   WaitForAppLaunchInfoSaved();
 
   // Simulate the system shutdown process, and the window is closed.
-  FullRestoreService::GetForProfile(profile())->Observe(
-      chrome::NOTIFICATION_APP_TERMINATING,
-      content::Source<aura::Window>(window), content::NotificationDetails());
+  FullRestoreService::GetForProfile(profile())->OnAppTerminating();
   widget->CloseNow();
   WaitForAppLaunchInfoSaved();
 
diff --git a/chrome/browser/ash/app_restore/full_restore_service.cc b/chrome/browser/ash/app_restore/full_restore_service.cc
index f950460..bcc5b3f 100644
--- a/chrome/browser/ash/app_restore/full_restore_service.cc
+++ b/chrome/browser/ash/app_restore/full_restore_service.cc
@@ -19,8 +19,8 @@
 #include "chrome/browser/ash/app_restore/new_user_restore_pref_handler.h"
 #include "chrome/browser/ash/policy/scheduled_task_handler/reboot_notifications_scheduler.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/first_run/first_run.h"
+#include "chrome/browser/lifetime/termination_notification.h"
 #include "chrome/browser/notifications/notification_display_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
@@ -35,9 +35,6 @@
 #include "components/app_restore/full_restore_utils.h"
 #include "components/prefs/pref_service.h"
 #include "components/strings/grit/components_strings.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_source.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/chromeos/devicetype_utils.h"
 #include "ui/message_center/public/cpp/notification.h"
@@ -115,8 +112,9 @@
           /*should_init_service=*/true)),
       restore_data_handler_(
           std::make_unique<FullRestoreDataHandler>(profile_)) {
-  notification_registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
-                              content::NotificationService::AllSources());
+  on_app_terminating_subscription_ =
+      browser_shutdown::AddAppTerminatingCallback(base::BindOnce(
+          &FullRestoreService::OnAppTerminating, base::Unretained(this)));
 
   PrefService* prefs = profile_->GetPrefs();
   DCHECK(prefs);
@@ -313,10 +311,7 @@
   MaybeCloseNotification();
 }
 
-void FullRestoreService::Observe(int type,
-                                 const content::NotificationSource& source,
-                                 const content::NotificationDetails& details) {
-  DCHECK_EQ(chrome::NOTIFICATION_APP_TERMINATING, type);
+void FullRestoreService::OnAppTerminating() {
   if (auto* arc_task_handler =
           app_restore::AppRestoreArcTaskHandler::GetForProfile(profile_)) {
     arc_task_handler->Shutdown();
diff --git a/chrome/browser/ash/app_restore/full_restore_service.h b/chrome/browser/ash/app_restore/full_restore_service.h
index dc90426b..c841924 100644
--- a/chrome/browser/ash/app_restore/full_restore_service.h
+++ b/chrome/browser/ash/app_restore/full_restore_service.h
@@ -8,13 +8,12 @@
 #include <memory>
 
 #include "ash/public/cpp/accelerators.h"
+#include "base/callback_list.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observation.h"
 #include "chrome/browser/sessions/exit_type_service.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/prefs/pref_change_registrar.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/message_center/public/cpp/notification_delegate.h"
 
@@ -66,7 +65,6 @@
 // interfaces to restore the app launchings and app windows.
 class FullRestoreService : public KeyedService,
                            public message_center::NotificationObserver,
-                           public content::NotificationObserver,
                            public ash::AcceleratorController::Observer {
  public:
   static FullRestoreService* GetForProfile(Profile* profile);
@@ -94,11 +92,6 @@
   void Click(const absl::optional<int>& button_index,
              const absl::optional<std::u16string>& reply) override;
 
-  // content::NotificationObserver:
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
-
   // ash::AcceleratorController::Observer:
   void OnActionPerformed(AcceleratorAction action) override;
   void OnAcceleratorControllerWillBeDestroyed(
@@ -113,6 +106,10 @@
 
  private:
   friend class FullRestoreServiceMultipleUsersTest;
+  FRIEND_TEST_ALL_PREFIXES(FullRestoreAppLaunchHandlerChromeAppBrowserTest,
+                           RestoreChromeApp);
+  FRIEND_TEST_ALL_PREFIXES(FullRestoreAppLaunchHandlerArcAppBrowserTest,
+                           RestoreArcApp);
 
   // KeyedService overrides.
   void Shutdown() override;
@@ -138,6 +135,8 @@
   // Chrome is run. Otherwise, returns false.
   bool ShouldShowNotification();
 
+  void OnAppTerminating();
+
   Profile* profile_ = nullptr;
   PrefChangeRegistrar pref_change_registrar_;
 
@@ -173,7 +172,7 @@
 
   std::unique_ptr<message_center::Notification> notification_;
 
-  content::NotificationRegistrar notification_registrar_;
+  base::CallbackListSubscription on_app_terminating_subscription_;
 
   // Browser session restore exit type service lock. This is created when the
   // system is restored from crash to help set the browser saving flag.
diff --git a/chrome/browser/ash/chrome_browser_main_parts_ash.cc b/chrome/browser/ash/chrome_browser_main_parts_ash.cc
index cc5a702..b987c19 100644
--- a/chrome/browser/ash/chrome_browser_main_parts_ash.cc
+++ b/chrome/browser/ash/chrome_browser_main_parts_ash.cc
@@ -1156,7 +1156,8 @@
     network_health::NetworkHealthService::GetInstance();
 
     // Create cros_healthd data collector.
-    cros_healthd::internal::DataCollector::Initialize();
+    cros_healthd_data_collector_ =
+        std::make_unique<cros_healthd::internal::DataCollector>();
 
     // Create the service connection to CrosHealthd platform service instance.
     auto* cros_healthd = cros_healthd::ServiceConnection::GetInstance();
@@ -1176,6 +1177,10 @@
               ->GetDiagnosticsRemoteAndBindReceiver();
         }));
 
+    // Sets up the connection of healthd data collector to cros_healthd.
+    cros_healthd->SendChromiumDataCollector(
+        cros_healthd_data_collector_->BindNewPipeAndPassRemote());
+
     if (features::IsTrafficCountersEnabled()) {
       // Initialize the TrafficCountersHandler instance.
       traffic_counters_handler_ =
diff --git a/chrome/browser/ash/chrome_browser_main_parts_ash.h b/chrome/browser/ash/chrome_browser_main_parts_ash.h
index 446d9b4d..2145005 100644
--- a/chrome/browser/ash/chrome_browser_main_parts_ash.h
+++ b/chrome/browser/ash/chrome_browser_main_parts_ash.h
@@ -41,6 +41,11 @@
 namespace default_app_order {
 class ExternalLoader;
 }
+namespace cros_healthd {
+namespace internal {
+class DataCollector;
+}
+}  // namespace cros_healthd
 }  // namespace chromeos
 
 namespace crosapi {
@@ -248,6 +253,9 @@
 
   std::unique_ptr<SessionTerminationManager> session_termination_manager_;
 
+  std::unique_ptr<chromeos::cros_healthd::internal::DataCollector>
+      cros_healthd_data_collector_;
+
   // Set when PreProfileInit() is called. If PreMainMessageLoopRun() exits
   // early, this will be false during PostMainMessageLoopRun(), etc.
   // Used to prevent shutting down classes that were not initialized.
diff --git a/chrome/browser/ash/crosapi/prefs_ash.cc b/chrome/browser/ash/crosapi/prefs_ash.cc
index ceb9d5e..3a84127 100644
--- a/chrome/browser/ash/crosapi/prefs_ash.cc
+++ b/chrome/browser/ash/crosapi/prefs_ash.cc
@@ -11,7 +11,7 @@
 #include "base/bind.h"
 #include "base/check.h"
 #include "base/no_destructor.h"
-#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/lifetime/termination_notification.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/components/quick_answers/public/cpp/quick_answers_prefs.h"
@@ -20,7 +20,6 @@
 #include "components/metrics/metrics_pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/user_manager/user_manager.h"
-#include "content/public/browser/notification_service.h"
 
 namespace crosapi {
 namespace {
@@ -116,8 +115,9 @@
   DCHECK(profile_manager_);
   DCHECK(local_state_);
 
-  notification_registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
-                              content::NotificationService::AllSources());
+  on_app_terminating_subscription_ =
+      browser_shutdown::AddAppTerminatingCallback(
+          base::BindOnce(&PrefsAsh::OnAppTerminating, base::Unretained(this)));
 
   profile_manager_->AddObserver(this);
   local_state_registrar_.Init(local_state_);
@@ -322,13 +322,6 @@
   profile_prefs_registrar_.reset();
 }
 
-void PrefsAsh::Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) {
-  DCHECK_EQ(chrome::NOTIFICATION_APP_TERMINATING, type);
-  profile_prefs_registrar_.reset();
-}
-
 void PrefsAsh::OnPrefChanged(mojom::PrefPath path) {
   auto state = GetState(path);
   const base::Value* value =
@@ -356,4 +349,8 @@
   profile_prefs_registrar_->Init(profile->GetPrefs());
 }
 
+void PrefsAsh::OnAppTerminating() {
+  profile_prefs_registrar_.reset();
+}
+
 }  // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/prefs_ash.h b/chrome/browser/ash/crosapi/prefs_ash.h
index 3e175c78..20e168e 100644
--- a/chrome/browser/ash/crosapi/prefs_ash.h
+++ b/chrome/browser/ash/crosapi/prefs_ash.h
@@ -10,6 +10,7 @@
 #include <string>
 #include <utility>
 
+#include "base/callback_list.h"
 #include "base/gtest_prod_util.h"
 #include "base/scoped_observation.h"
 #include "chrome/browser/profiles/profile.h"
@@ -17,8 +18,6 @@
 #include "chrome/browser/profiles/profile_observer.h"
 #include "chromeos/crosapi/mojom/prefs.mojom.h"
 #include "components/prefs/pref_change_registrar.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
 #include "extensions/browser/extension_pref_store.h"
 #include "extensions/browser/extension_pref_value_map_factory.h"
 #include "extensions/browser/extension_prefs.h"
@@ -37,8 +36,7 @@
 // This class must only be used from the main thread.
 class PrefsAsh : public mojom::Prefs,
                  public ProfileManagerObserver,
-                 public ProfileObserver,
-                 public content::NotificationObserver {
+                 public ProfileObserver {
  public:
   PrefsAsh(ProfileManager* profile_manager, PrefService* local_state);
   PrefsAsh(const PrefsAsh&) = delete;
@@ -68,11 +66,6 @@
   // ProfileObserver:
   void OnProfileWillBeDestroyed(Profile* profile) override;
 
-  // content::NotificationObserver:
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
-
   // Used to inject |profile| as a primary profile for testing.
   void OnPrimaryProfileReadyForTesting(Profile* profile) {
     OnPrimaryProfileReady(profile);
@@ -95,6 +88,8 @@
   // Called when Primary logged in user profile is ready.
   void OnPrimaryProfileReady(Profile* profile);
 
+  void OnAppTerminating();
+
   // In production, owned by g_browser_process, which does not outlives this
   // object.
   ProfileManager* profile_manager_;
@@ -114,7 +109,7 @@
   // Observe profile destruction to reset prefs observation.
   base::ScopedObservation<Profile, ProfileObserver> profile_observation_{this};
 
-  content::NotificationRegistrar notification_registrar_;
+  base::CallbackListSubscription on_app_terminating_subscription_;
   // Map of extension pref paths to preference names.
   std::map<mojom::PrefPath, std::string> extension_prefpath_to_name_;
 };
diff --git a/chrome/browser/ash/input_method/autocorrect_manager_unittest.cc b/chrome/browser/ash/input_method/autocorrect_manager_unittest.cc
index e9bd2db6..5ec5f37 100644
--- a/chrome/browser/ash/input_method/autocorrect_manager_unittest.cc
+++ b/chrome/browser/ash/input_method/autocorrect_manager_unittest.cc
@@ -65,6 +65,7 @@
               AcceptSuggestionCandidate,
               (int context_id,
                const std::u16string& candidate,
+               size_t delete_previous_utf16_len,
                std::string* error),
               (override));
   MOCK_METHOD(bool,
diff --git a/chrome/browser/ash/input_method/emoji_suggester.cc b/chrome/browser/ash/input_method/emoji_suggester.cc
index c74a87c..b5e397c4 100644
--- a/chrome/browser/ash/input_method/emoji_suggester.cc
+++ b/chrome/browser/ash/input_method/emoji_suggester.cc
@@ -311,8 +311,9 @@
     return false;
 
   std::string error;
-  suggestion_handler_->AcceptSuggestionCandidate(*focused_context_id_,
-                                                 candidates_[index], &error);
+  suggestion_handler_->AcceptSuggestionCandidate(
+      *focused_context_id_, candidates_[index],
+      /* delete_previous_utf16_len=*/0, &error);
 
   if (!error.empty()) {
     LOG(ERROR) << "Failed to accept suggestion. " << error;
diff --git a/chrome/browser/ash/input_method/emoji_suggester_unittest.cc b/chrome/browser/ash/input_method/emoji_suggester_unittest.cc
index e3d7fc5..4ad56d7 100644
--- a/chrome/browser/ash/input_method/emoji_suggester_unittest.cc
+++ b/chrome/browser/ash/input_method/emoji_suggester_unittest.cc
@@ -105,6 +105,7 @@
 
   bool AcceptSuggestionCandidate(int context_id,
                                  const std::u16string& candidate,
+                                 size_t delete_previous_utf16_len,
                                  std::string* error) override {
     return false;
   }
diff --git a/chrome/browser/ash/input_method/fake_suggestion_handler.cc b/chrome/browser/ash/input_method/fake_suggestion_handler.cc
index c034a0b..48d6d1d9 100644
--- a/chrome/browser/ash/input_method/fake_suggestion_handler.cc
+++ b/chrome/browser/ash/input_method/fake_suggestion_handler.cc
@@ -66,10 +66,12 @@
 bool FakeSuggestionHandler::AcceptSuggestionCandidate(
     int context_id,
     const std::u16string& candidate,
+    size_t delete_previous_utf16_len,
     std::string* error) {
   showing_suggestion_ = false;
   accepted_suggestion_ = true;
   accepted_suggestion_text_ = candidate;
+  delete_previous_utf16_len_ = delete_previous_utf16_len;
   suggestion_text_ = u"";
   confirmed_length_ = 0;
   return true;
diff --git a/chrome/browser/ash/input_method/fake_suggestion_handler.h b/chrome/browser/ash/input_method/fake_suggestion_handler.h
index b1b1ee0..e3f952c 100644
--- a/chrome/browser/ash/input_method/fake_suggestion_handler.h
+++ b/chrome/browser/ash/input_method/fake_suggestion_handler.h
@@ -40,6 +40,7 @@
   void ClickButton(const ui::ime::AssistiveWindowButton& button) override;
   bool AcceptSuggestionCandidate(int context_id,
                                  const std::u16string& candidate,
+                                 size_t delete_previous_utf16_len,
                                  std::string* error) override;
   bool SetAssistiveWindowProperties(
       int context_id,
@@ -54,6 +55,7 @@
     return accepted_suggestion_text_;
   }
   size_t GetConfirmedLength() { return confirmed_length_; }
+  size_t GetDeletePreviousUtf16Len() { return delete_previous_utf16_len_; }
   bool GetShowingSuggestion() { return showing_suggestion_; }
   bool GetAcceptedSuggestion() { return accepted_suggestion_; }
   bool GetDismissedSuggestion() { return dismissed_suggestion_; }
@@ -75,6 +77,7 @@
   std::u16string suggestion_text_;
   std::u16string accepted_suggestion_text_;
   size_t confirmed_length_ = 0;
+  size_t delete_previous_utf16_len_ = 0;
   bool showing_suggestion_ = false;
   bool accepted_suggestion_ = false;
   bool dismissed_suggestion_ = false;
diff --git a/chrome/browser/ash/input_method/grammar_manager_unittest.cc b/chrome/browser/ash/input_method/grammar_manager_unittest.cc
index a9fc1d1f..680af8ab 100644
--- a/chrome/browser/ash/input_method/grammar_manager_unittest.cc
+++ b/chrome/browser/ash/input_method/grammar_manager_unittest.cc
@@ -95,6 +95,7 @@
               AcceptSuggestionCandidate,
               (int context_id,
                const std::u16string& candidate,
+               size_t delete_previous_utf16_len,
                std::string* error),
               (override));
   MOCK_METHOD(bool,
diff --git a/chrome/browser/ash/input_method/input_method_engine.cc b/chrome/browser/ash/input_method/input_method_engine.cc
index f1b1871..708f891a 100644
--- a/chrome/browser/ash/input_method/input_method_engine.cc
+++ b/chrome/browser/ash/input_method/input_method_engine.cc
@@ -758,6 +758,7 @@
 bool InputMethodEngine::AcceptSuggestionCandidate(
     int context_id,
     const std::u16string& suggestion,
+    size_t delete_previous_utf16_len,
     std::string* error) {
   if (!IsActive()) {
     *error = kErrorNotActive;
@@ -768,6 +769,11 @@
     return false;
   }
 
+  if (delete_previous_utf16_len) {
+    DeleteSurroundingText(context_id_, -delete_previous_utf16_len,
+                          delete_previous_utf16_len, error);
+  }
+
   CommitText(context_id, suggestion, error);
 
   IMEAssistiveWindowHandlerInterface* aw_handler =
@@ -839,10 +845,9 @@
   return true;
 }
 
-bool InputMethodEngine::SetCandidates(
-    int context_id,
-    const std::vector<Candidate>& candidates,
-    std::string* error) {
+bool InputMethodEngine::SetCandidates(int context_id,
+                                      const std::vector<Candidate>& candidates,
+                                      std::string* error) {
   if (!IsActive()) {
     *error = kErrorNotActive;
     return false;
diff --git a/chrome/browser/ash/input_method/input_method_engine.h b/chrome/browser/ash/input_method/input_method_engine.h
index 2f95ca7..3ecf9a07 100644
--- a/chrome/browser/ash/input_method/input_method_engine.h
+++ b/chrome/browser/ash/input_method/input_method_engine.h
@@ -258,6 +258,7 @@
   void ClickButton(const ui::ime::AssistiveWindowButton& button) override;
   bool AcceptSuggestionCandidate(int context_id,
                                  const std::u16string& candidate,
+                                 size_t delete_previous_utf16_len,
                                  std::string* error) override;
   bool SetAssistiveWindowProperties(
       int context_id,
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 07d0bc0..09e3b87 100644
--- a/chrome/browser/ash/input_method/input_method_engine_unittest.cc
+++ b/chrome/browser/ash/input_method/input_method_engine_unittest.cc
@@ -400,5 +400,42 @@
   histogram_tester.ExpectTotalCount("InputMethod.KeyEventLatency", 1);
 }
 
+TEST_F(InputMethodEngineTest, AcceptSuggestionCandidateCommitsCandidate) {
+  CreateEngine(true);
+  FocusIn(ui::TEXT_INPUT_TYPE_TEXT);
+  engine_->Enable(kTestImeComponentId);
+
+  const int context = engine_->GetContextIdForTesting();
+
+  std::string error;
+  engine_->AcceptSuggestionCandidate(context, u"suggestion", 0, &error);
+
+  EXPECT_EQ("", error);
+  EXPECT_EQ(
+      0, mock_ime_input_context_handler_->delete_surrounding_text_call_count());
+  EXPECT_EQ(u"suggestion", mock_ime_input_context_handler_->last_commit_text());
+}
+
+TEST_F(InputMethodEngineTest,
+       AcceptSuggestionCandidateDeletesSurroundingAndCommitsCandidate) {
+  CreateEngine(true);
+  FocusIn(ui::TEXT_INPUT_TYPE_TEXT);
+  engine_->Enable(kTestImeComponentId);
+
+  const int context = engine_->GetContextIdForTesting();
+
+  std::string error;
+  engine_->CommitText(context, u"text", &error);
+  engine_->AcceptSuggestionCandidate(context, u"suggestion", 1, &error);
+
+  EXPECT_EQ("", error);
+  EXPECT_EQ(
+      1, mock_ime_input_context_handler_->delete_surrounding_text_call_count());
+  auto deleteSurroundingTextArg =
+      mock_ime_input_context_handler_->last_delete_surrounding_text_arg();
+  EXPECT_EQ(deleteSurroundingTextArg.offset, -1);
+  EXPECT_EQ(deleteSurroundingTextArg.length, 1u);
+  EXPECT_EQ(u"suggestion", mock_ime_input_context_handler_->last_commit_text());
+}
 }  // namespace input_method
 }  // namespace ash
diff --git a/chrome/browser/ash/input_method/longpress_diacritics_suggester.cc b/chrome/browser/ash/input_method/longpress_diacritics_suggester.cc
index 4e0589e0..0671bce 100644
--- a/chrome/browser/ash/input_method/longpress_diacritics_suggester.cc
+++ b/chrome/browser/ash/input_method/longpress_diacritics_suggester.cc
@@ -154,10 +154,9 @@
     return false;
   }
   std::string error;
-  // TODO(b/217560706): Accept should also delete the previous character instead
-  // of just appending.
   suggestion_handler_->AcceptSuggestionCandidate(
-      *focused_context_id_, current_suggestions[index], &error);
+      *focused_context_id_, current_suggestions[index],
+      /* delete_previous_utf16_len=*/1, &error);
 
   if (!error.empty()) {
     LOG(ERROR) << "Failed to accept suggestion. " << error;
diff --git a/chrome/browser/ash/input_method/longpress_diacritics_suggester_unittest.cc b/chrome/browser/ash/input_method/longpress_diacritics_suggester_unittest.cc
index 46a9b74..50c6633 100644
--- a/chrome/browser/ash/input_method/longpress_diacritics_suggester_unittest.cc
+++ b/chrome/browser/ash/input_method/longpress_diacritics_suggester_unittest.cc
@@ -325,6 +325,7 @@
   EXPECT_FALSE(suggestion_handler.GetShowingSuggestion());
   EXPECT_EQ(suggestion_handler.GetAcceptedSuggestionText(),
             GetParam().candidates[0]);
+  EXPECT_EQ(suggestion_handler.GetDeletePreviousUtf16Len(), 1);
 }
 
 TEST_P(LongpressDiacriticsSuggesterTest,
diff --git a/chrome/browser/ash/input_method/suggestion_handler_interface.h b/chrome/browser/ash/input_method/suggestion_handler_interface.h
index 4c835ee..49ba93e 100644
--- a/chrome/browser/ash/input_method/suggestion_handler_interface.h
+++ b/chrome/browser/ash/input_method/suggestion_handler_interface.h
@@ -54,6 +54,7 @@
 
   virtual bool AcceptSuggestionCandidate(int context_id,
                                          const std::u16string& candidate,
+                                         size_t delete_previous_utf16_len,
                                          std::string* error) = 0;
 
   // Shows/Hides given assistive window. No-op if context_id doesn't match or
diff --git a/chrome/browser/ash/input_method/ui/completion_suggestion_label_view.cc b/chrome/browser/ash/input_method/ui/completion_suggestion_label_view.cc
new file mode 100644
index 0000000..046adf96
--- /dev/null
+++ b/chrome/browser/ash/input_method/ui/completion_suggestion_label_view.cc
@@ -0,0 +1,65 @@
+// 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.
+
+#include "chrome/browser/ash/input_method/ui/completion_suggestion_label_view.h"
+
+#include "chrome/browser/ash/input_method/ui/colors.h"
+#include "ui/base/metadata/metadata_impl_macros.h"
+
+namespace ui {
+namespace ime {
+namespace {
+constexpr char kSuggestionFontStyle[] = "Roboto";
+constexpr int kSuggestionFontSize = 13;
+}  // namespace
+
+CompletionSuggestionLabelView::CompletionSuggestionLabelView() {
+  SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  SetAutoColorReadabilityEnabled(false);
+  // StyledLabel eats event, probably because it has to handle links.
+  // Explicitly sets can_process_events_within_subtree to false for
+  // hover to work correctly.
+  SetCanProcessEventsWithinSubtree(false);
+}
+
+void CompletionSuggestionLabelView::SetPrefixAndPrediction(
+    const std::u16string& prefix,
+    const std::u16string& prediction) {
+  const gfx::FontList kSuggestionFont({kSuggestionFontStyle}, gfx::Font::NORMAL,
+                                      kSuggestionFontSize,
+                                      gfx::Font::Weight::NORMAL);
+  // SetText clears the existing style only if the text to set is different from
+  // the previous one.
+  SetText(u"");
+  SetText(prefix + prediction);
+
+  // Create style range for prefix if it's not empty.
+  if (!prefix.empty()) {
+    views::StyledLabel::RangeStyleInfo prefix_style;
+    prefix_style.custom_font = kSuggestionFont;
+    prefix_style.override_color =
+        ResolveSemanticColor(cros_styles::ColorName::kTextColorPrimary);
+    AddStyleRange(gfx::Range(0, prefix.length()), prefix_style);
+  }
+
+  // Create style range for the prediction.
+  views::StyledLabel::RangeStyleInfo prediction_style;
+  prediction_style.custom_font = kSuggestionFont;
+  prediction_style.override_color =
+      ResolveSemanticColor(cros_styles::ColorName::kTextColorSecondary);
+  AddStyleRange(
+      gfx::Range(prefix.length(), prefix.length() + prediction.length()),
+      prediction_style);
+
+  // TODO(crbug/1099146): Add tests to check view's height and width with
+  // a non-empty prefix.
+  // Maximum width for suggestion.
+  SizeToFit(448);
+}
+
+BEGIN_METADATA(CompletionSuggestionLabelView, views::StyledLabel)
+END_METADATA
+
+}  // namespace ime
+}  // namespace ui
diff --git a/chrome/browser/ash/input_method/ui/completion_suggestion_label_view.h b/chrome/browser/ash/input_method/ui/completion_suggestion_label_view.h
new file mode 100644
index 0000000..699cc361
--- /dev/null
+++ b/chrome/browser/ash/input_method/ui/completion_suggestion_label_view.h
@@ -0,0 +1,52 @@
+// 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.
+
+#ifndef CHROME_BROWSER_ASH_INPUT_METHOD_UI_COMPLETION_SUGGESTION_LABEL_VIEW_H_
+#define CHROME_BROWSER_ASH_INPUT_METHOD_UI_COMPLETION_SUGGESTION_LABEL_VIEW_H_
+
+#include "ui/base/metadata/metadata_header_macros.h"
+#include "ui/chromeos/ui_chromeos_export.h"
+#include "ui/views/controls/styled_label.h"
+
+namespace ui {
+namespace ime {
+
+// A CompletionSuggestionLabelView renders the text of a completion suggestion.
+// A completion suggestion label has two parts:
+// - Prefix: The prefix in the suggestion that matches what the user has typed
+//   so far. This may be empty for next-word predictions.
+// - Prediction: The remaining part of the suggestion that is predicted by the
+//   input method.
+//
+// Examples:
+// - User types "how a". The input method suggests "how are you".
+//   The prefix is "how a" and the prediction is "re you".
+// - User types a space to begin a new word. The input method suggests "how".
+//   The prefix is "" and the prediction is "how".
+//
+// CompletionSuggestionLabelView renders the prefix differently from the
+// prediction to distinguish the two.
+class UI_CHROMEOS_EXPORT CompletionSuggestionLabelView
+    : public views::StyledLabel {
+ public:
+  METADATA_HEADER(CompletionSuggestionLabelView);
+
+  CompletionSuggestionLabelView();
+
+  // Set the prefix and prediction parts of the label.
+  void SetPrefixAndPrediction(const std::u16string& prefix,
+                              const std::u16string& prediction);
+};
+
+BEGIN_VIEW_BUILDER(UI_CHROMEOS_EXPORT,
+                   CompletionSuggestionLabelView,
+                   views::StyledLabel)
+END_VIEW_BUILDER
+
+}  // namespace ime
+}  // namespace ui
+
+DEFINE_VIEW_BUILDER(UI_CHROMEOS_EXPORT, ui::ime::CompletionSuggestionLabelView)
+
+#endif  // CHROME_BROWSER_ASH_INPUT_METHOD_UI_COMPLETION_SUGGESTION_LABEL_VIEW_H_
diff --git a/chrome/browser/ash/input_method/ui/completion_suggestion_label_view_unittest.cc b/chrome/browser/ash/input_method/ui/completion_suggestion_label_view_unittest.cc
new file mode 100644
index 0000000..664a6c34
--- /dev/null
+++ b/chrome/browser/ash/input_method/ui/completion_suggestion_label_view_unittest.cc
@@ -0,0 +1,95 @@
+// 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.
+
+#include "chrome/browser/ash/input_method/ui/completion_suggestion_label_view.h"
+
+#include <stddef.h>
+
+#include <string>
+
+#include "chrome/browser/ash/input_method/ui/colors.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/test/views_test_base.h"
+
+namespace ui {
+namespace ime {
+namespace {
+
+// Returns the child of `view` at `index` as a views::Label.
+views::Label* LabelAt(const views::View& view, size_t index) {
+  views::View* const child = view.children()[index];
+  EXPECT_EQ(child->GetClassName(), views::Label::kViewClassName);
+  return static_cast<views::Label*>(child);
+}
+
+class CompletionSuggestionLabelViewTest : public views::ViewsTestBase {
+ public:
+  CompletionSuggestionLabelViewTest() = default;
+};
+
+TEST_F(CompletionSuggestionLabelViewTest, EmptyPrefixHasCorrectText) {
+  CompletionSuggestionLabelView label;
+
+  label.SetPrefixAndPrediction(u"", u"good");
+
+  EXPECT_EQ(label.GetText(), u"good");
+}
+
+TEST_F(CompletionSuggestionLabelViewTest, NonEmptyPrefixHasCorrectText) {
+  CompletionSuggestionLabelView label;
+
+  label.SetPrefixAndPrediction(u"how a", u"re you");
+
+  EXPECT_EQ(label.GetText(), u"how are you");
+}
+
+TEST_F(CompletionSuggestionLabelViewTest,
+       ChildHasCorrectTextWhenPrefixIsEmpty) {
+  CompletionSuggestionLabelView label;
+
+  label.SetPrefixAndPrediction(u"", u"good");
+
+  ASSERT_EQ(label.children().size(), 1u);
+  EXPECT_EQ(LabelAt(label, 0)->GetText(), u"good");
+}
+
+TEST_F(CompletionSuggestionLabelViewTest,
+       ChildUsesSecondaryColorWhenPrefixIsEmpty) {
+  CompletionSuggestionLabelView label;
+
+  label.SetPrefixAndPrediction(u"", u"good");
+
+  ASSERT_EQ(label.children().size(), 1u);
+  EXPECT_EQ(LabelAt(label, 0)->GetEnabledColor(),
+            ResolveSemanticColor(cros_styles::ColorName::kTextColorSecondary));
+}
+
+TEST_F(CompletionSuggestionLabelViewTest,
+       ChildrenHaveCorrectTextWhenPrefixIsNotEmpty) {
+  CompletionSuggestionLabelView label;
+
+  label.SetPrefixAndPrediction(u"how a", u"re you");
+
+  ASSERT_EQ(label.children().size(), 2u);
+  EXPECT_EQ(LabelAt(label, 0)->GetText(), u"how a");
+  EXPECT_EQ(LabelAt(label, 1)->GetText(), u"re you");
+}
+
+TEST_F(CompletionSuggestionLabelViewTest,
+       ChildrenUsePrimaryAndSecondaryColorsWhenPrefixIsNotEmpty) {
+  CompletionSuggestionLabelView label;
+
+  label.SetPrefixAndPrediction(u"how a", u"re you");
+
+  ASSERT_EQ(label.children().size(), 2u);
+  EXPECT_EQ(LabelAt(label, 0)->GetEnabledColor(),
+            ResolveSemanticColor(cros_styles::ColorName::kTextColorPrimary));
+  EXPECT_EQ(LabelAt(label, 1)->GetEnabledColor(),
+            ResolveSemanticColor(cros_styles::ColorName::kTextColorSecondary));
+}
+
+}  // namespace
+}  // namespace ime
+}  // namespace ui
diff --git a/chrome/browser/ash/input_method/ui/suggestion_view.cc b/chrome/browser/ash/input_method/ui/suggestion_view.cc
index 5d6e42b..9f357b4 100644
--- a/chrome/browser/ash/input_method/ui/suggestion_view.cc
+++ b/chrome/browser/ash/input_method/ui/suggestion_view.cc
@@ -7,6 +7,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/ash/input_method/ui/colors.h"
+#include "chrome/browser/ash/input_method/ui/completion_suggestion_label_view.h"
 #include "chrome/browser/ash/input_method/ui/suggestion_details.h"
 #include "chrome/grit/generated_resources.h"
 #include "ui/accessibility/ax_enums.mojom.h"
@@ -49,21 +50,6 @@
   return index_label;
 }
 
-// Creates the suggestion label, and returns it (never returns nullptr).
-// The label text is not set in this function.
-std::unique_ptr<views::StyledLabel> CreateSuggestionLabel() {
-  auto suggestion_label = std::make_unique<views::StyledLabel>();
-  suggestion_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  suggestion_label->SetBorder(
-      views::CreateEmptyBorder(gfx::Insets::VH(kPadding / 2, 0)));
-  suggestion_label->SetAutoColorReadabilityEnabled(false);
-  // StyledLabel eats event, probably because it has to handle links.
-  // Explicitly sets can_process_events_within_subtree to false for
-  // SuggestionView's hover to work correctly.
-  suggestion_label->SetCanProcessEventsWithinSubtree(false);
-  return suggestion_label;
-}
-
 std::unique_ptr<views::ImageView> CreateDownIcon() {
   auto icon = std::make_unique<views::ImageView>();
   icon->SetBorder(views::CreateEmptyBorder(gfx::Insets::TLBR(
@@ -115,7 +101,10 @@
     : views::Button(std::move(callback)) {
   index_label_ = AddChildView(CreateIndexLabel());
   index_label_->SetVisible(false);
-  suggestion_label_ = AddChildView(CreateSuggestionLabel());
+  suggestion_label_ =
+      AddChildView(std::make_unique<CompletionSuggestionLabelView>());
+  suggestion_label_->SetBorder(
+      views::CreateEmptyBorder(gfx::Insets::VH(kPadding / 2, 0)));
 
   annotation_container_ = AddChildView(CreateAnnotationContainer());
   down_and_enter_annotation_label_ =
@@ -187,39 +176,14 @@
   index_label_->SetText(index);
   index_label_->SetVisible(true);
   index_width_ = index_label_->GetPreferredSize().width();
-  suggestion_label_->SetText(text);
+  suggestion_label_->SetPrefixAndPrediction(u"", text);
   suggestion_width_ = suggestion_label_->GetPreferredSize().width();
 }
 
 void SuggestionView::SetSuggestionText(const std::u16string& text,
                                        const size_t confirmed_length) {
-  // SetText clears the existing style only if the text to set is different from
-  // the previous one.
-  suggestion_label_->SetText(base::EmptyString16());
-  suggestion_label_->SetText(text);
-  gfx::FontList kSuggestionFont({kFontStyle}, gfx::Font::NORMAL,
-                                kSuggestionFontSize, gfx::Font::Weight::NORMAL);
-
-  if (confirmed_length != 0) {
-    views::StyledLabel::RangeStyleInfo confirmed_style;
-    confirmed_style.custom_font = kSuggestionFont;
-    confirmed_style.override_color =
-        ResolveSemanticColor(cros_styles::ColorName::kTextColorPrimary);
-    suggestion_label_->AddStyleRange(gfx::Range(0, confirmed_length),
-                                     confirmed_style);
-  }
-
-  views::StyledLabel::RangeStyleInfo suggestion_style;
-  suggestion_style.custom_font = kSuggestionFont;
-  suggestion_style.override_color =
-      ResolveSemanticColor(cros_styles::ColorName::kTextColorSecondary);
-  suggestion_label_->AddStyleRange(gfx::Range(confirmed_length, text.length()),
-                                   suggestion_style);
-
-  // TODO(crbug/1099146): Add tests to check view's height and width with
-  // confirmed length.
-  // Maximum width for suggestion.
-  suggestion_label_->SizeToFit(448);
+  suggestion_label_->SetPrefixAndPrediction(text.substr(0, confirmed_length),
+                                            text.substr(confirmed_length));
 }
 
 void SuggestionView::SetHighlighted(bool highlighted) {
@@ -292,6 +256,10 @@
   min_width_ = min_width;
 }
 
+gfx::Point SuggestionView::GetAnchorOrigin() const {
+  return gfx::Point(kPadding, 0);
+}
+
 std::u16string SuggestionView::GetSuggestionForTesting() {
   return suggestion_label_->GetText();
 }
diff --git a/chrome/browser/ash/input_method/ui/suggestion_view.h b/chrome/browser/ash/input_method/ui/suggestion_view.h
index 64f26d1..78207e4 100644
--- a/chrome/browser/ash/input_method/ui/suggestion_view.h
+++ b/chrome/browser/ash/input_method/ui/suggestion_view.h
@@ -23,10 +23,10 @@
 namespace ime {
 
 struct SuggestionDetails;
+class CompletionSuggestionLabelView;
 
 // Font-related constants
 constexpr char kFontStyle[] = "Roboto";
-constexpr int kSuggestionFontSize = 13;
 constexpr int kAnnotationFontSize = 10;
 constexpr int kIndexFontSize = 10;
 
@@ -58,6 +58,13 @@
   void SetHighlighted(bool highlighted);
   void SetMinWidth(int width);
 
+  // When this view is being anchored to some other view, returns the point in
+  // this view that this should be anchored to, in local coordinates.
+  // For example, if this method returns the bottom left corner of this view,
+  // then this view should be placed above the anchor so that the bottom left
+  // corner of this view corresponds to the anchor.
+  gfx::Point GetAnchorOrigin() const;
+
   std::u16string GetSuggestionForTesting();
 
  private:
@@ -79,8 +86,8 @@
                          const size_t confirmed_length);
 
   views::Label* index_label_ = nullptr;
-  // The suggestion label renders suggestions.
-  views::StyledLabel* suggestion_label_ = nullptr;
+  // The suggestion label renders the suggestion text.
+  CompletionSuggestionLabelView* suggestion_label_ = nullptr;
   // The annotation view renders annotations.
   views::View* annotation_container_ = nullptr;
   views::View* down_and_enter_annotation_label_ = nullptr;
diff --git a/chrome/browser/ash/input_method/ui/suggestion_view_unittest.cc b/chrome/browser/ash/input_method/ui/suggestion_view_unittest.cc
new file mode 100644
index 0000000..b77bb50
--- /dev/null
+++ b/chrome/browser/ash/input_method/ui/suggestion_view_unittest.cc
@@ -0,0 +1,35 @@
+// 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.
+
+#include "chrome/browser/ash/input_method/ui/suggestion_view.h"
+
+#include <stddef.h>
+
+#include <string>
+
+#include "chrome/browser/ash/input_method/ui/suggestion_details.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/views/test/views_test_base.h"
+
+namespace ui {
+namespace ime {
+namespace {
+
+class SuggestionViewTest : public views::ViewsTestBase {
+ public:
+  SuggestionViewTest() = default;
+};
+
+TEST_F(SuggestionViewTest, AnchorOriginIsPadding) {
+  SuggestionView suggestion({});
+  suggestion.SetView({
+      .text = u"good",
+  });
+
+  EXPECT_EQ(suggestion.GetAnchorOrigin(), gfx::Point(kPadding, 0));
+}
+
+}  // namespace
+}  // namespace ime
+}  // namespace ui
diff --git a/chrome/browser/ash/input_method/ui/suggestion_window_view.cc b/chrome/browser/ash/input_method/ui/suggestion_window_view.cc
index a8f131b..939ba73 100644
--- a/chrome/browser/ash/input_method/ui/suggestion_window_view.cc
+++ b/chrome/browser/ash/input_method/ui/suggestion_window_view.cc
@@ -133,6 +133,20 @@
   }
 }
 
+gfx::Rect SuggestionWindowView::GetBubbleBounds() {
+  // The bubble bounds must be shifted to align with the anchor.
+  // If there is more than one suggestion, use the anchor origin of the first
+  // (topmost) suggestion. This allows the alignment to work correctly for both
+  // vertical and horizontal orientations.
+  const views::View::Views& candidates = candidate_area_->children();
+  const gfx::Point anchor_origin =
+      !candidates.empty()
+          ? static_cast<SuggestionView*>(candidates[0])->GetAnchorOrigin()
+          : gfx::Point(0, 0);
+  return BubbleDialogDelegateView::GetBubbleBounds() -
+         anchor_origin.OffsetFromOrigin();
+}
+
 void SuggestionWindowView::OnThemeChanged() {
   BubbleDialogDelegateView::OnThemeChanged();
 
diff --git a/chrome/browser/ash/input_method/ui/suggestion_window_view.h b/chrome/browser/ash/input_method/ui/suggestion_window_view.h
index 6b38d47..6ec619b 100644
--- a/chrome/browser/ash/input_method/ui/suggestion_window_view.h
+++ b/chrome/browser/ash/input_method/ui/suggestion_window_view.h
@@ -77,6 +77,7 @@
 
  protected:
   // views::BubbleDialogDelegateView:
+  gfx::Rect GetBubbleBounds() override;
   void OnThemeChanged() override;
 
  private:
diff --git a/chrome/browser/ash/input_method/ui/suggestion_window_view_unittest.cc b/chrome/browser/ash/input_method/ui/suggestion_window_view_unittest.cc
index 4065d292..12a4bc7 100644
--- a/chrome/browser/ash/input_method/ui/suggestion_window_view_unittest.cc
+++ b/chrome/browser/ash/input_method/ui/suggestion_window_view_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/ash/input_method/assistive_window_properties.h"
 #include "chrome/browser/ash/input_method/ui/assistive_delegate.h"
+#include "chrome/browser/ash/input_method/ui/suggestion_details.h"
 #include "chrome/browser/ash/input_method/ui/suggestion_view.h"
 #include "chrome/test/views/chrome_views_test_base.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -312,5 +313,15 @@
   EXPECT_EQ(layout_orientation, expected_orientation);
 }
 
+TEST_P(SuggestionWindowViewTest, LeftBoundIsCloseToAnchor) {
+  suggestion_window_view_->Show({
+      .text = u"good",
+  });
+
+  suggestion_window_view_->SetAnchorRect(gfx::Rect(100, 0, 10, 10));
+
+  EXPECT_EQ(suggestion_window_view_->GetBoundsInScreen().x(), 100 - kPadding);
+}
+
 }  // namespace ime
 }  // namespace ui
diff --git a/chrome/browser/ash/login/screens/assistant_optin_flow_screen_browsertest.cc b/chrome/browser/ash/login/screens/assistant_optin_flow_screen_browsertest.cc
index 12078b0..175940f 100644
--- a/chrome/browser/ash/login/screens/assistant_optin_flow_screen_browsertest.cc
+++ b/chrome/browser/ash/login/screens/assistant_optin_flow_screen_browsertest.cc
@@ -31,6 +31,7 @@
 #include "chromeos/services/assistant/public/cpp/assistant_prefs.h"
 #include "chromeos/services/assistant/public/cpp/assistant_settings.h"
 #include "chromeos/services/assistant/public/cpp/features.h"
+#include "chromeos/services/assistant/public/proto/activity_control_settings_common.pb.h"
 #include "chromeos/services/assistant/public/proto/get_settings_ui.pb.h"
 #include "chromeos/services/assistant/public/proto/settings_ui.pb.h"
 #include "chromeos/services/assistant/service.h"
@@ -259,6 +260,7 @@
     setting->add_additional_info_paragraph();
     setting->set_additional_info_paragraph(0, "And it's really cool");
     setting->set_icon_uri("assistant_icon");
+    setting->set_setting_set_id(chromeos::assistant::SettingSetId::WAA);
   }
 
   void UpdateSettings(const std::string& update,
diff --git a/chrome/browser/ash/login/ui/webui_login_view.cc b/chrome/browser/ash/login/ui/webui_login_view.cc
index b4138bd3..457b651 100644
--- a/chrome/browser/ash/login/ui/webui_login_view.cc
+++ b/chrome/browser/ash/login/ui/webui_login_view.cc
@@ -21,7 +21,7 @@
 #include "chrome/browser/ash/login/ui/login_display_webui.h"
 #include "chrome/browser/ash/login/ui/web_contents_forced_title.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
-#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/lifetime/termination_notification.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
 #include "chrome/browser/renderer_preferences_util.h"
@@ -37,7 +37,6 @@
 #include "components/content_settings/core/common/content_settings_pattern.h"
 #include "components/password_manager/core/browser/password_manager.h"
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
-#include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host.h"
@@ -94,8 +93,9 @@
 WebUILoginView::WebUILoginView(const WebViewSettings& settings,
                                base::WeakPtr<LoginDisplayHostWebUI> controller)
     : settings_(settings), controller_(controller) {
-  registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
-                 content::NotificationService::AllSources());
+  on_app_terminating_subscription_ =
+      browser_shutdown::AddAppTerminatingCallback(base::BindOnce(
+          &WebUILoginView::OnAppTerminating, base::Unretained(this)));
 
   session_observation_.Observe(session_manager::SessionManager::Get());
 
@@ -296,12 +296,7 @@
     view->FocusReturned(reverse);
 }
 
-void WebUILoginView::Observe(int type,
-                             const content::NotificationSource& source,
-                             const content::NotificationDetails& details) {
-  DCHECK_EQ(chrome::NOTIFICATION_APP_TERMINATING, type)
-      << "Unexpected notification " << type;
-
+void WebUILoginView::OnAppTerminating() {
   // In some tests, WebUILoginView remains after LoginScreenClientImpl gets
   // deleted on shutdown. It should unregister itself before the deletion
   // happens.
diff --git a/chrome/browser/ash/login/ui/webui_login_view.h b/chrome/browser/ash/login/ui/webui_login_view.h
index b64357f..2ac3035 100644
--- a/chrome/browser/ash/login/ui/webui_login_view.h
+++ b/chrome/browser/ash/login/ui/webui_login_view.h
@@ -19,8 +19,6 @@
 // TODO(https://crbug.com/1164001): use forward declaration.
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "components/web_modal/web_contents_modal_dialog_host.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
@@ -45,7 +43,6 @@
 // WebUI based start up and lock screens. It contains a WebView.
 class WebUILoginView : public views::View,
                        public content::WebContentsDelegate,
-                       public content::NotificationObserver,
                        public session_manager::SessionManagerObserver,
                        public ChromeWebModalDialogManagerDelegate,
                        public web_modal::WebContentsModalDialogHost,
@@ -132,16 +129,13 @@
   void AboutToRequestFocusFromTabTraversal(bool reverse) override;
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
 
-  // Overridden from content::NotificationObserver.
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
-
   // session_manager::SessionManagerObserver:
   void OnNetworkErrorScreenShown() override;
   void OnLoginOrLockScreenVisible() override;
 
  private:
+  void OnAppTerminating();
+
   // Map type for the accelerator-to-identifier map.
   typedef std::map<ui::Accelerator, LoginAcceleratorAction> AccelMap;
 
@@ -172,7 +166,7 @@
   // 2. Notifies OOBE/sign classes.
   void OnLoginPromptVisible();
 
-  content::NotificationRegistrar registrar_;
+  base::CallbackListSubscription on_app_terminating_subscription_;
 
   base::ScopedObservation<session_manager::SessionManager,
                           session_manager::SessionManagerObserver>
diff --git a/chrome/browser/ash/mojo_service_manager/connection_helper.cc b/chrome/browser/ash/mojo_service_manager/connection_helper.cc
index b161dddb..a2f650a 100644
--- a/chrome/browser/ash/mojo_service_manager/connection_helper.cc
+++ b/chrome/browser/ash/mojo_service_manager/connection_helper.cc
@@ -19,7 +19,10 @@
 namespace service_manager = chromeos::mojo_service_manager;
 
 base::ScopedClosureRunner CreateRealConnectionAndPassCloser() {
-  service_manager::BootstrapServiceManagerConnection();
+  CHECK(service_manager::BootstrapServiceManagerConnection())
+      << "Cannot connect to ChromeOS mojo service manager after retries. "
+         "This result in the ash don't have a mojo broker and will not be "
+         "able to bootstrap any mojo connection to other processes.";
   return base::ScopedClosureRunner{
       base::BindOnce(&service_manager::ResetServiceManagerConnection)};
 }
diff --git a/chrome/browser/ash/system/automatic_reboot_manager.cc b/chrome/browser/ash/system/automatic_reboot_manager.cc
index 4cffc418..dfb7b44 100644
--- a/chrome/browser/ash/system/automatic_reboot_manager.cc
+++ b/chrome/browser/ash/system/automatic_reboot_manager.cc
@@ -34,15 +34,12 @@
 #include "base/time/time.h"
 #include "base/timer/wall_clock_timer.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/lifetime/termination_notification.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/user_manager/user_manager.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_source.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 #include "ui/base/user_activity/user_activity_detector.h"
 
@@ -160,8 +157,9 @@
       prefs::kRebootAfterUpdate,
       base::BindRepeating(&AutomaticRebootManager::Reschedule,
                           base::Unretained(this)));
-  notification_registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
-      content::NotificationService::AllSources());
+  on_app_terminating_subscription_ =
+      browser_shutdown::AddAppTerminatingCallback(base::BindOnce(
+          &AutomaticRebootManager::OnAppTerminating, base::Unretained(this)));
 
   PowerManagerClient::Get()->AddObserver(this);
   DBusThreadManager::Get()->GetUpdateEngineClient()->AddObserver(this);
@@ -270,18 +268,6 @@
   login_screen_idle_timer_.reset();
 }
 
-void AutomaticRebootManager::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  DCHECK_EQ(type, chrome::NOTIFICATION_APP_TERMINATING);
-  if (session_manager::SessionManager::Get()->IsSessionStarted()) {
-    // The browser is terminating during a session, either because the session
-    // is ending or because the browser is being restarted.
-    MaybeReboot(true);
-  }
-}
-
 // static
 void AutomaticRebootManager::RegisterPrefs(PrefRegistrySimple* registry) {
   registry->RegisterIntegerPref(prefs::kUptimeLimit, 0);
@@ -429,5 +415,13 @@
       power_manager::REQUEST_RESTART_OTHER, "automatic reboot manager");
 }
 
+void AutomaticRebootManager::OnAppTerminating() {
+  if (session_manager::SessionManager::Get()->IsSessionStarted()) {
+    // The browser is terminating during a session, either because the session
+    // is ending or because the browser is being restarted.
+    MaybeReboot(true);
+  }
+}
+
 }  // namespace system
 }  // namespace ash
diff --git a/chrome/browser/ash/system/automatic_reboot_manager.h b/chrome/browser/ash/system/automatic_reboot_manager.h
index 840e5e7..815d7bf1 100644
--- a/chrome/browser/ash/system/automatic_reboot_manager.h
+++ b/chrome/browser/ash/system/automatic_reboot_manager.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "base/callback_list.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/scoped_observation.h"
@@ -20,8 +21,6 @@
 #include "components/prefs/pref_change_registrar.h"
 #include "components/session_manager/core/session_manager.h"
 #include "components/session_manager/core/session_manager_observer.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
 #include "ui/base/user_activity/user_activity_observer.h"
 
 class PrefRegistrySimple;
@@ -76,8 +75,7 @@
 class AutomaticRebootManager : public PowerManagerClient::Observer,
                                public UpdateEngineClient::Observer,
                                public ui::UserActivityObserver,
-                               public session_manager::SessionManagerObserver,
-                               public content::NotificationObserver {
+                               public session_manager::SessionManagerObserver {
  public:
   AutomaticRebootManager(const base::Clock* clock,
                          const base::TickClock* tick_clock);
@@ -111,11 +109,6 @@
   // session_manager::SessionManagerObserver:
   void OnUserSessionStarted(bool is_primary_user) override;
 
-  // content::NotificationObserver:
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
-
   static void RegisterPrefs(PrefRegistrySimple* registry);
 
  private:
@@ -141,6 +134,9 @@
   // Reboots immediately unless a non-kiosk session is active.
   void Reboot();
 
+  // Callback invoked when Chrome shuts down.
+  void OnAppTerminating();
+
   // Event that is signaled when Init() runs.
   base::WaitableEvent initialized_{
       base::WaitableEvent::ResetPolicy::MANUAL,
@@ -152,7 +148,7 @@
 
   PrefChangeRegistrar local_state_registrar_;
 
-  content::NotificationRegistrar notification_registrar_;
+  base::CallbackListSubscription on_app_terminating_subscription_;
 
   // Fires when the user has been idle on the login screen for a set amount of
   // time.
diff --git a/chrome/browser/ash/system/automatic_reboot_manager_unittest.cc b/chrome/browser/ash/system/automatic_reboot_manager_unittest.cc
index 68c30bde8..d98ea10 100644
--- a/chrome/browser/ash/system/automatic_reboot_manager_unittest.cc
+++ b/chrome/browser/ash/system/automatic_reboot_manager_unittest.cc
@@ -27,7 +27,6 @@
 #include "chrome/browser/ash/login/users/mock_user_manager.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/ash/system/automatic_reboot_manager_observer.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
@@ -40,9 +39,6 @@
 #include "components/session_manager/session_manager_types.h"
 #include "components/user_manager/scoped_user_manager.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_source.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -423,10 +419,7 @@
 }
 
 void AutomaticRebootManagerBasicTest::NotifyTerminating(bool expect_reboot) {
-  automatic_reboot_manager_->Observe(
-      chrome::NOTIFICATION_APP_TERMINATING,
-      content::Source<AutomaticRebootManagerBasicTest>(this),
-      content::NotificationService::NoDetails());
+  automatic_reboot_manager_->OnAppTerminating();
   task_runner_->RunUntilIdle();
   EXPECT_EQ(expect_reboot ? 1 : 0,
             FakePowerManagerClient::Get()->num_request_restart_calls());
diff --git a/chrome/browser/ash/system_web_apps/system_web_app_manager.cc b/chrome/browser/ash/system_web_apps/system_web_app_manager.cc
index 3940176..596c27e 100644
--- a/chrome/browser/ash/system_web_apps/system_web_app_manager.cc
+++ b/chrome/browser/ash/system_web_apps/system_web_app_manager.cc
@@ -304,8 +304,11 @@
   externally_managed_app_manager_ = externally_managed_app_manager;
   registrar_ = registrar;
   sync_bridge_ = sync_bridge;
-  ui_manager_ = ui_manager;
   web_app_policy_manager_ = web_app_policy_manager;
+
+  // `SetSubsystems` and `Start` can be called multiple times in tests.
+  ui_manager_observation_.Reset();
+  ui_manager_observation_.Observe(ui_manager);
 }
 
 void SystemWebAppManager::Start() {
@@ -420,6 +423,11 @@
 void SystemWebAppManager::OnReadyToCommitNavigation(
     const web_app::AppId& app_id,
     content::NavigationHandle* navigation_handle) {
+  // Perform tab-specific setup when a navigation in a System Web App is about
+  // to be committed.
+  if (!IsSystemWebApp(app_id))
+    return;
+
   // No need to setup origin trials for intra-document navigation.
   if (navigation_handle->IsSameDocument())
     return;
@@ -478,6 +486,10 @@
   return type;
 }
 
+void SystemWebAppManager::OnWebAppUiManagerDestroyed() {
+  ui_manager_observation_.Reset();
+}
+
 void SystemWebAppManager::SetSystemAppsForTesting(
     SystemWebAppDelegateMap system_apps) {
   system_app_delegates_ = std::move(system_apps);
diff --git a/chrome/browser/ash/system_web_apps/system_web_app_manager.h b/chrome/browser/ash/system_web_apps/system_web_app_manager.h
index 1c101233..d4a3dd2 100644
--- a/chrome/browser/ash/system_web_apps/system_web_app_manager.h
+++ b/chrome/browser/ash/system_web_apps/system_web_app_manager.h
@@ -16,12 +16,14 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/one_shot_event.h"
+#include "base/scoped_observation.h"
 #include "chrome/browser/ash/system_web_apps/system_web_app_background_task.h"
 #include "chrome/browser/ash/system_web_apps/types/system_web_app_delegate.h"
 #include "chrome/browser/ash/system_web_apps/types/system_web_app_delegate_map.h"
 #include "chrome/browser/ash/system_web_apps/types/system_web_app_type.h"
 #include "chrome/browser/web_applications/externally_managed_app_manager.h"
 #include "chrome/browser/web_applications/web_app_install_info.h"
+#include "chrome/browser/web_applications/web_app_ui_manager.h"
 #include "chrome/browser/web_applications/web_app_url_loader.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "content/public/browser/web_contents.h"
@@ -56,7 +58,7 @@
 // Installs, uninstalls, and updates System Web Apps.
 // System Web Apps are built-in, highly-privileged Web Apps for Chrome OS. They
 // have access to more APIs and are part of the Chrome OS image.
-class SystemWebAppManager {
+class SystemWebAppManager : private web_app::WebAppUiManagerObserver {
  public:
   // Policy for when the SystemWebAppManager will update apps/install new apps.
   enum class UpdatePolicy {
@@ -77,7 +79,7 @@
   explicit SystemWebAppManager(Profile* profile);
   SystemWebAppManager(const SystemWebAppManager&) = delete;
   SystemWebAppManager& operator=(const SystemWebAppManager&) = delete;
-  virtual ~SystemWebAppManager();
+  ~SystemWebAppManager() override;
 
   // On Chrome OS: returns the SystemWebAppManager that hosts System Web Apps in
   // Ash; In Lacros, returns nullptr (unless
@@ -136,11 +138,6 @@
   // Returns whether |app_id| points to an installed System App.
   bool IsSystemWebApp(const web_app::AppId& app_id) const;
 
-  // Perform tab-specific setup when a navigation in a System Web App is about
-  // to be committed.
-  void OnReadyToCommitNavigation(const web_app::AppId& app_id,
-                                 content::NavigationHandle* navigation_handle);
-
   // Returns the SystemWebAppType that should capture the navigation to
   // |url|.
   absl::optional<SystemWebAppType> GetCapturingSystemAppForURL(
@@ -215,6 +212,12 @@
 
   void StartBackgroundTasks() const;
 
+  // web_app::WebAppUiManagerObserver:
+  void OnReadyToCommitNavigation(
+      const web_app::AppId& app_id,
+      content::NavigationHandle* navigation_handle) override;
+  void OnWebAppUiManagerDestroyed() override;
+
   raw_ptr<Profile> profile_;
 
   std::unique_ptr<base::OneShotEvent> on_apps_synchronized_;
@@ -238,12 +241,14 @@
 
   raw_ptr<web_app::WebAppSyncBridge> sync_bridge_ = nullptr;
 
-  raw_ptr<web_app::WebAppUiManager> ui_manager_ = nullptr;
-
   raw_ptr<web_app::WebAppPolicyManager> web_app_policy_manager_ = nullptr;
 
   std::vector<std::unique_ptr<SystemWebAppBackgroundTask>> tasks_;
 
+  base::ScopedObservation<web_app::WebAppUiManager,
+                          web_app::WebAppUiManagerObserver>
+      ui_manager_observation_{this};
+
   base::WeakPtrFactory<SystemWebAppManager> weak_ptr_factory_{this};
 };
 
diff --git a/chrome/browser/autofill_assistant/password_change/apc_external_action_delegate.cc b/chrome/browser/autofill_assistant/password_change/apc_external_action_delegate.cc
index 91380aa6..778a062e 100644
--- a/chrome/browser/autofill_assistant/password_change/apc_external_action_delegate.cc
+++ b/chrome/browser/autofill_assistant/password_change/apc_external_action_delegate.cc
@@ -3,6 +3,14 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/autofill_assistant/password_change/apc_external_action_delegate.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/autofill_assistant/password_change/proto/extensions.pb.h"
+#include "chrome/browser/ui/autofill_assistant/password_change/assistant_display_delegate.h"
+#include "chrome/browser/ui/autofill_assistant/password_change/password_change_run_controller.h"
 #include "chrome/browser/ui/autofill_assistant/password_change/password_change_run_display.h"
 
 // TODO(crbug.com/1324089): Implement once the side panel and
diff --git a/chrome/browser/autofill_assistant/password_change/proto/extensions.proto b/chrome/browser/autofill_assistant/password_change/proto/extensions.proto
index d8f9e6bc..dda9dc6 100644
--- a/chrome/browser/autofill_assistant/password_change/proto/extensions.proto
+++ b/chrome/browser/autofill_assistant/password_change/proto/extensions.proto
@@ -14,6 +14,16 @@
 
 enum TopIcon {
   TOP_ICON_UNSPECIFIED = 0;
+
+  TOP_ICON_OPEN_SITE_SETTINGS = 1;
+  TOP_ICON_ENTER_OLD_PASSWORD = 2;
+  TOP_ICON_CHOOSE_NEW_PASSWORD = 3;
+  TOP_ICON_SAVE_NEW_PASSWORD = 4;
+  TOP_ICON_CHANGED_PASSWORD = 5;
+
+  TOP_ICON_BAD_NEW_PASSWORD = 6;
+  TOP_ICON_ERROR_OCCURRED = 7;
+  TOP_ICON_USER_ACTION_REQUIRED = 8;
 }
 
 enum ProgressStep {
diff --git a/chrome/browser/autofill_assistant/password_change/vector_icons/BUILD.gn b/chrome/browser/autofill_assistant/password_change/vector_icons/BUILD.gn
new file mode 100644
index 0000000..ab138a8
--- /dev/null
+++ b/chrome/browser/autofill_assistant/password_change/vector_icons/BUILD.gn
@@ -0,0 +1,32 @@
+# 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.
+
+import("//components/vector_icons/vector_icons.gni")
+
+aggregate_vector_icons("apc_vector_icons") {
+  icon_directory = "."
+
+  sources = [
+    "bad_new_password.icon",
+    "changed_password.icon",
+    "choose_new_password.icon",
+    "enter_old_password.icon",
+    "error_occurred.icon",
+    "open_site_settings.icon",
+    "save_new_password.icon",
+    "unspecified_state.icon",
+    "user_action_required.icon",
+  ]
+}
+
+source_set("vector_icons") {
+  sources = get_target_outputs(":apc_vector_icons")
+
+  deps = [
+    ":apc_vector_icons",
+    "//base",
+    "//skia",
+    "//ui/gfx",
+  ]
+}
diff --git a/chrome/browser/autofill_assistant/password_change/vector_icons/bad_new_password.icon b/chrome/browser/autofill_assistant/password_change/vector_icons/bad_new_password.icon
new file mode 100644
index 0000000..5c6c631
--- /dev/null
+++ b/chrome/browser/autofill_assistant/password_change/vector_icons/bad_new_password.icon
@@ -0,0 +1,89 @@
+// 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.
+
+CANVAS_DIMENSIONS, 76,
+PATH_COLOR_ARGB, 0xFF, 0xF1, 0xF3, 0xF4,
+ROUND_RECT, 1, 1, 74, 64, 3,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+STROKE, 2,
+ROUND_RECT, 1, 1, 74, 64, 3,
+NEW_PATH,
+STROKE, 2,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+MOVE_TO, 22.33f, 1,
+CUBIC_TO, 23.81f, 1, 25, 2.19f, 25, 3.67f,
+V_LINE_TO, 5,
+R_H_LINE_TO, 50,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+MOVE_TO, 25, 1,
+R_H_LINE_TO, 49,
+R_V_LINE_TO, 4,
+H_LINE_TO, 25,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xFF, 0xFF, 0xFF,
+MOVE_TO, 50, 8,
+R_H_LINE_TO, 22,
+R_V_LINE_TO, 54,
+H_LINE_TO, 50,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xDA, 0xDC, 0xE0,
+STROKE, 2,
+MOVE_TO, 50, 8,
+R_H_LINE_TO, 22,
+R_V_LINE_TO, 54,
+H_LINE_TO, 50,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x1A, 0x73, 0xE8,
+STROKE, 2,
+MOVE_TO, 4, 8,
+R_H_LINE_TO, 44,
+R_V_LINE_TO, 54,
+H_LINE_TO, 4,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xEA, 0x43, 0x35,
+MOVE_TO, 26, 16.7f,
+R_CUBIC_TO, -5.52f, 0, -10, 4.48f, -10, 10,
+R_CUBIC_TO, 0, 5.52f, 4.48f, 10, 10, 10,
+R_CUBIC_TO, 5.52f, 0, 10, -4.48f, 10, -10,
+R_CUBIC_TO, 0, -5.52f, -4.48f, -10, -10, -10,
+CLOSE,
+R_MOVE_TO, -1, 15,
+R_V_LINE_TO, -2,
+R_H_LINE_TO, 2,
+R_V_LINE_TO, 2,
+R_H_LINE_TO, -2,
+CLOSE,
+R_MOVE_TO, 0, -10,
+R_V_LINE_TO, 6,
+R_H_LINE_TO, 2,
+R_V_LINE_TO, -6,
+R_H_LINE_TO, -2,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xFF, 0xFF, 0xFF,
+ROUND_RECT, 11, 39.704, 30, 12, 6,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xDA, 0xDC, 0xE0,
+STROKE, 2,
+ROUND_RECT, 11, 39.704, 30, 12, 6,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xEA, 0x43, 0x35,
+CIRCLE, 17, 45.704, 2,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xEA, 0x43, 0x35,
+CIRCLE, 23, 45.704, 2,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xEA, 0x43, 0x35,
+CIRCLE, 29, 45.704, 2,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xEA, 0x43, 0x35,
+CIRCLE, 35, 45.704, 2,
+CLOSE
diff --git a/chrome/browser/autofill_assistant/password_change/vector_icons/changed_password.icon b/chrome/browser/autofill_assistant/password_change/vector_icons/changed_password.icon
new file mode 100644
index 0000000..91bbe47
--- /dev/null
+++ b/chrome/browser/autofill_assistant/password_change/vector_icons/changed_password.icon
@@ -0,0 +1,98 @@
+// 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.
+
+CANVAS_DIMENSIONS, 76,
+PATH_COLOR_ARGB, 0xFF, 0xF1, 0xF3, 0xF4,
+ROUND_RECT, 1, 1, 74, 64, 3,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+STROKE, 2,
+ROUND_RECT, 1, 1, 74, 64, 3,
+NEW_PATH,
+STROKE, 2,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+MOVE_TO, 22.33f, 1,
+CUBIC_TO, 23.81f, 1, 25, 2.19f, 25, 3.67f,
+V_LINE_TO, 5,
+R_H_LINE_TO, 50,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+MOVE_TO, 25, 1,
+R_H_LINE_TO, 49,
+R_V_LINE_TO, 4,
+H_LINE_TO, 25,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xFF, 0xFF, 0xFF,
+MOVE_TO, 50, 8,
+R_H_LINE_TO, 22,
+R_V_LINE_TO, 54,
+H_LINE_TO, 50,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xDA, 0xDC, 0xE0,
+STROKE, 2,
+MOVE_TO, 50, 8,
+R_H_LINE_TO, 22,
+R_V_LINE_TO, 54,
+H_LINE_TO, 50,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x9A, 0xA0, 0xA6,
+MOVE_TO, 26, 16.89f,
+R_CUBIC_TO, -5.52f, 0, -10, 4.48f, -10, 10,
+R_CUBIC_TO, 0, 5.52f, 4.48f, 10, 10, 10,
+R_CUBIC_TO, 5.52f, 0, 10, -4.48f, 10, -10,
+R_CUBIC_TO, 0, -5.52f, -4.48f, -10, -10, -10,
+CLOSE,
+R_MOVE_TO, 6.36f, 14.83f,
+R_CUBIC_TO, -1.43f, -1.74f, -4.9f, -2.33f, -6.36f, -2.33f,
+R_CUBIC_TO, -1.46f, 0, -4.93f, 0.59f, -6.36f, 2.33f,
+R_CUBIC_TO, -1.02f, -1.34f, -1.64f, -3.01f, -1.64f, -4.83f,
+R_CUBIC_TO, 0, -4.41f, 3.59f, -8, 8, -8,
+R_CUBIC_TO, 4.41f, 0, 8, 3.59f, 8, 8,
+R_CUBIC_TO, 0, 1.82f, -0.62f, 3.49f, -1.64f, 4.83f,
+CLOSE,
+R_MOVE_TO, -9.86f, -7.33f,
+R_CUBIC_TO, 0, -1.94f, 1.56f, -3.5f, 3.5f, -3.5f,
+R_CUBIC_TO, 1.94f, 0, 3.5f, 1.56f, 3.5f, 3.5f,
+R_CUBIC_TO, 0, 1.94f, -1.56f, 3.5f, -3.5f, 3.5f,
+R_CUBIC_TO, -1.94f, 0, -3.5f, -1.56f, -3.5f, -3.5f,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xFF, 0xFF, 0xFF,
+ROUND_RECT, 11, 39.8936, 30, 12, 6,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xDA, 0xDC, 0xE0,
+STROKE, 2,
+ROUND_RECT, 11, 39.8936, 30, 12, 6,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x1E, 0x8E, 0x3E,
+CIRCLE, 17, 45.8936, 2,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x1E, 0x8E, 0x3E,
+CIRCLE, 23, 45.8936, 2,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x1E, 0x8E, 0x3E,
+CIRCLE, 29, 45.8936, 2,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x1E, 0x8E, 0x3E,
+CIRCLE, 35, 45.8936, 2,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x1E, 0x8E, 0x3E,
+MOVE_TO, 61, 26.56f,
+R_ARC_TO, 8.34f, 8.34f, 0, 0, 0, -8.33f, 8.33f,
+R_CUBIC_TO, 0, 4.6f, 3.73f, 8.33f, 8.33f, 8.33f,
+R_CUBIC_TO, 4.6f, 0, 8.33f, -3.73f, 8.33f, -8.33f,
+CUBIC_TO_SHORTHAND, 65.6f, 26.56f, 61, 26.56f,
+CLOSE,
+R_MOVE_TO, -1.67f, 12.5f,
+LINE_TO, 56, 35.73f,
+R_LINE_TO, 1.17f, -1.17f,
+R_LINE_TO, 2.17f, 2.17f,
+R_LINE_TO, 5.5f, -5.5f,
+LINE_TO, 66, 32.39f,
+R_LINE_TO, -6.67f, 6.67f,
+CLOSE
diff --git a/chrome/browser/autofill_assistant/password_change/vector_icons/choose_new_password.icon b/chrome/browser/autofill_assistant/password_change/vector_icons/choose_new_password.icon
new file mode 100644
index 0000000..1157469
--- /dev/null
+++ b/chrome/browser/autofill_assistant/password_change/vector_icons/choose_new_password.icon
@@ -0,0 +1,111 @@
+// 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.
+
+CANVAS_DIMENSIONS, 76,
+PATH_COLOR_ARGB, 0xFF, 0xF1, 0xF3, 0xF4,
+ROUND_RECT, 1, 1, 74, 64, 3,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+STROKE, 2,
+ROUND_RECT, 1, 1, 74, 64, 3,
+NEW_PATH,
+STROKE, 2,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+MOVE_TO, 22.33f, 1,
+CUBIC_TO, 23.81f, 1, 25, 2.19f, 25, 3.67f,
+V_LINE_TO, 5,
+R_H_LINE_TO, 50,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+MOVE_TO, 25, 1,
+R_H_LINE_TO, 49,
+R_V_LINE_TO, 4,
+H_LINE_TO, 25,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xFF, 0xFF, 0xFF,
+MOVE_TO, 50, 8,
+R_H_LINE_TO, 22,
+R_V_LINE_TO, 54,
+H_LINE_TO, 50,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x1A, 0x73, 0xE8,
+STROKE, 2,
+MOVE_TO, 50, 8,
+R_H_LINE_TO, 22,
+R_V_LINE_TO, 54,
+H_LINE_TO, 50,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x1A, 0x73, 0xE8,
+MOVE_TO, 61, 26.56f,
+R_CUBIC_TO, -4.6f, 0, -8.33f, 3.73f, -8.33f, 8.33f,
+R_CUBIC_TO, 0, 4.6f, 3.73f, 8.33f, 8.33f, 8.33f,
+R_CUBIC_TO, 4.6f, 0, 8.33f, -3.73f, 8.33f, -8.33f,
+R_CUBIC_TO, 0, -4.6f, -3.73f, -8.33f, -8.33f, -8.33f,
+CLOSE,
+R_MOVE_TO, -0.83f, 14.17f,
+R_V_LINE_TO, -1.67f,
+R_H_LINE_TO, 1.67f,
+R_V_LINE_TO, 1.67f,
+R_H_LINE_TO, -1.67f,
+CLOSE,
+R_MOVE_TO, 2.64f, -5.69f,
+R_LINE_TO, 0.75f, -0.77f,
+R_CUBIC_TO, 0.48f, -0.47f, 0.78f, -1.14f, 0.78f, -1.87f,
+R_CUBIC_TO, 0, -1.84f, -1.49f, -3.33f, -3.33f, -3.33f,
+R_CUBIC_TO, -1.84f, 0, -3.33f, 1.49f, -3.33f, 3.33f,
+R_H_LINE_TO, 1.67f,
+R_CUBIC_TO, 0, -0.92f, 0.75f, -1.67f, 1.67f, -1.67f,
+R_CUBIC_TO, 0.92f, 0, 1.67f, 0.75f, 1.67f, 1.67f,
+R_CUBIC_TO, 0, 0.46f, -0.18f, 0.88f, -0.49f, 1.18f,
+R_LINE_TO, -1.03f, 1.05f,
+R_CUBIC_TO, -0.6f, 0.61f, -0.97f, 1.44f, -0.97f, 2.36f,
+R_V_LINE_TO, 0.42f,
+R_H_LINE_TO, 1.67f,
+R_CUBIC_TO, 0, -1.25f, 0.38f, -1.75f, 0.98f, -2.36f,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x9A, 0xA0, 0xA6,
+MOVE_TO, 26, 16.89f,
+R_CUBIC_TO, -5.52f, 0, -10, 4.48f, -10, 10,
+R_CUBIC_TO, 0, 5.52f, 4.48f, 10, 10, 10,
+R_CUBIC_TO, 5.52f, 0, 10, -4.48f, 10, -10,
+R_CUBIC_TO, 0, -5.52f, -4.48f, -10, -10, -10,
+CLOSE,
+R_MOVE_TO, 6.36f, 14.83f,
+R_CUBIC_TO, -1.43f, -1.74f, -4.9f, -2.33f, -6.36f, -2.33f,
+R_CUBIC_TO, -1.46f, 0, -4.93f, 0.59f, -6.36f, 2.33f,
+R_CUBIC_TO, -1.02f, -1.34f, -1.64f, -3.01f, -1.64f, -4.83f,
+R_CUBIC_TO, 0, -4.41f, 3.59f, -8, 8, -8,
+R_CUBIC_TO, 4.41f, 0, 8, 3.59f, 8, 8,
+R_CUBIC_TO, 0, 1.82f, -0.62f, 3.49f, -1.64f, 4.83f,
+CLOSE,
+R_MOVE_TO, -9.86f, -7.33f,
+R_CUBIC_TO, 0, -1.94f, 1.56f, -3.5f, 3.5f, -3.5f,
+R_CUBIC_TO, 1.94f, 0, 3.5f, 1.56f, 3.5f, 3.5f,
+R_CUBIC_TO, 0, 1.94f, -1.56f, 3.5f, -3.5f, 3.5f,
+R_CUBIC_TO, -1.94f, 0, -3.5f, -1.56f, -3.5f, -3.5f,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xFF, 0xFF, 0xFF,
+ROUND_RECT, 11, 39.8936, 30, 12, 6,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xDA, 0xDC, 0xE0,
+STROKE, 2,
+ROUND_RECT, 11, 39.8936, 30, 12, 6,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x9A, 0xA0, 0xA6,
+CIRCLE, 17, 45.8936, 2,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x9A, 0xA0, 0xA6,
+CIRCLE, 23, 45.8936, 2,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x9A, 0xA0, 0xA6,
+CIRCLE, 29, 45.8936, 2,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x9A, 0xA0, 0xA6,
+CIRCLE, 35, 45.8936, 2
diff --git a/chrome/browser/autofill_assistant/password_change/vector_icons/enter_old_password.icon b/chrome/browser/autofill_assistant/password_change/vector_icons/enter_old_password.icon
new file mode 100644
index 0000000..a1dd313
--- /dev/null
+++ b/chrome/browser/autofill_assistant/password_change/vector_icons/enter_old_password.icon
@@ -0,0 +1,82 @@
+// 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.
+
+CANVAS_DIMENSIONS, 76,
+PATH_COLOR_ARGB, 0xFF, 0xF1, 0xF3, 0xF4,
+ROUND_RECT, 1, 1, 74, 64, 3,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+STROKE, 2,
+ROUND_RECT, 1, 1, 74, 64, 3,
+NEW_PATH,
+STROKE, 2,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+MOVE_TO, 22.33f, 1,
+CUBIC_TO, 23.81f, 1, 25, 2.19f, 25, 3.67f,
+V_LINE_TO, 5,
+R_H_LINE_TO, 50,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+MOVE_TO, 25, 1,
+R_H_LINE_TO, 49,
+R_V_LINE_TO, 4,
+H_LINE_TO, 25,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xFF, 0xFF, 0xFF,
+MOVE_TO, 50, 8,
+R_H_LINE_TO, 22,
+R_V_LINE_TO, 54,
+H_LINE_TO, 50,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xDA, 0xDC, 0xE0,
+STROKE, 2,
+MOVE_TO, 50, 8,
+R_H_LINE_TO, 22,
+R_V_LINE_TO, 54,
+H_LINE_TO, 50,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x9A, 0xA0, 0xA6,
+MOVE_TO, 26, 16.89f,
+R_CUBIC_TO, -5.52f, 0, -10, 4.48f, -10, 10,
+R_CUBIC_TO, 0, 5.52f, 4.48f, 10, 10, 10,
+R_CUBIC_TO, 5.52f, 0, 10, -4.48f, 10, -10,
+R_CUBIC_TO, 0, -5.52f, -4.48f, -10, -10, -10,
+CLOSE,
+R_MOVE_TO, 6.36f, 14.83f,
+R_CUBIC_TO, -1.43f, -1.74f, -4.9f, -2.33f, -6.36f, -2.33f,
+R_CUBIC_TO, -1.46f, 0, -4.93f, 0.59f, -6.36f, 2.33f,
+R_CUBIC_TO, -1.02f, -1.34f, -1.64f, -3.01f, -1.64f, -4.83f,
+R_CUBIC_TO, 0, -4.41f, 3.59f, -8, 8, -8,
+R_CUBIC_TO, 4.41f, 0, 8, 3.59f, 8, 8,
+R_CUBIC_TO, 0, 1.82f, -0.62f, 3.49f, -1.64f, 4.83f,
+CLOSE,
+R_MOVE_TO, -9.86f, -7.33f,
+R_CUBIC_TO, 0, -1.94f, 1.56f, -3.5f, 3.5f, -3.5f,
+R_CUBIC_TO, 1.94f, 0, 3.5f, 1.56f, 3.5f, 3.5f,
+R_CUBIC_TO, 0, 1.94f, -1.56f, 3.5f, -3.5f, 3.5f,
+R_CUBIC_TO, -1.94f, 0, -3.5f, -1.56f, -3.5f, -3.5f,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xFF, 0xFF, 0xFF,
+ROUND_RECT, 11, 39.8936, 30, 12, 6,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xDA, 0xDC, 0xE0,
+STROKE, 2,
+ROUND_RECT, 11, 39.8936, 30, 12, 6,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x9A, 0xA0, 0xA6,
+CIRCLE, 17, 45.8936, 2,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x9A, 0xA0, 0xA6,
+CIRCLE, 23, 45.8936, 2,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x9A, 0xA0, 0xA6,
+CIRCLE, 29, 45.8936, 2,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x9A, 0xA0, 0xA6,
+CIRCLE, 35, 45.8936, 2
diff --git a/chrome/browser/autofill_assistant/password_change/vector_icons/error_occurred.icon b/chrome/browser/autofill_assistant/password_change/vector_icons/error_occurred.icon
new file mode 100644
index 0000000..9277f0fd
--- /dev/null
+++ b/chrome/browser/autofill_assistant/password_change/vector_icons/error_occurred.icon
@@ -0,0 +1,71 @@
+// 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.
+
+CANVAS_DIMENSIONS, 76,
+PATH_COLOR_ARGB, 0xFF, 0xF1, 0xF3, 0xF4,
+ROUND_RECT, 1, 1, 74, 64, 3,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+STROKE, 2,
+ROUND_RECT, 1, 1, 74, 64, 3,
+NEW_PATH,
+STROKE, 2,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+MOVE_TO, 22.33f, 1,
+CUBIC_TO, 23.81f, 1, 25, 2.19f, 25, 3.67f,
+V_LINE_TO, 5,
+R_H_LINE_TO, 50,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+MOVE_TO, 25, 1,
+R_H_LINE_TO, 49,
+R_V_LINE_TO, 4,
+H_LINE_TO, 25,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xFF, 0xFF, 0xFF,
+MOVE_TO, 50, 8,
+R_H_LINE_TO, 22,
+R_V_LINE_TO, 54,
+H_LINE_TO, 50,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x42, 0x85, 0xF4,
+STROKE, 2,
+MOVE_TO, 4, 8,
+R_H_LINE_TO, 44,
+R_V_LINE_TO, 54,
+H_LINE_TO, 4,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x42, 0x85, 0xF4,
+MOVE_TO, 15.41f, 24,
+LINE_TO, 14, 25.41f,
+R_LINE_TO, 2, 2,
+R_V_LINE_TO, 11.98f,
+R_CUBIC_TO, 0, 1.1f, 0.9f, 2, 2, 2,
+R_H_LINE_TO, 11.98f,
+R_LINE_TO, 3.82f, 3.82f,
+R_LINE_TO, 1.41f, -1.41f,
+LINE_TO, 15.41f, 24,
+CLOSE,
+R_MOVE_TO, 2.59f, 5.41f,
+R_V_LINE_TO, 9.98f,
+R_H_LINE_TO, 9.98f,
+R_LINE_TO, -9.98f, -9.98f,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x42, 0x85, 0xF4,
+MOVE_TO, 34, 39.4f,
+R_H_LINE_TO, -0.36f,
+R_LINE_TO, 1.58f, 1.58f,
+R_CUBIC_TO, 0.47f, -0.37f, 0.78f, -0.94f, 0.78f, -1.58f,
+R_V_LINE_TO, -12,
+R_CUBIC_TO, 0, -1.1f, -0.9f, -2, -2, -2,
+R_H_LINE_TO, -14.36f,
+R_LINE_TO, 4, 4,
+R_H_LINE_TO, 10.36f,
+R_V_LINE_TO, 10,
+CLOSE
diff --git a/chrome/browser/autofill_assistant/password_change/vector_icons/open_site_settings.icon b/chrome/browser/autofill_assistant/password_change/vector_icons/open_site_settings.icon
new file mode 100644
index 0000000..0fc99a30
--- /dev/null
+++ b/chrome/browser/autofill_assistant/password_change/vector_icons/open_site_settings.icon
@@ -0,0 +1,70 @@
+// 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.
+
+CANVAS_DIMENSIONS, 76,
+PATH_COLOR_ARGB, 0xFF, 0xF1, 0xF3, 0xF4,
+ROUND_RECT, 1, 1, 74, 64, 3,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+STROKE, 2,
+ROUND_RECT, 1, 1, 74, 64, 3,
+NEW_PATH,
+STROKE, 2,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+MOVE_TO, 22.33f, 1,
+CUBIC_TO, 23.81f, 1, 25, 2.19f, 25, 3.67f,
+V_LINE_TO, 5,
+R_H_LINE_TO, 50,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+MOVE_TO, 25, 1,
+R_H_LINE_TO, 49,
+R_V_LINE_TO, 4,
+H_LINE_TO, 25,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xFF, 0xFF, 0xFF,
+MOVE_TO, 50, 8,
+R_H_LINE_TO, 22,
+R_V_LINE_TO, 54,
+H_LINE_TO, 50,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xDA, 0xDC, 0xE0,
+STROKE, 2,
+MOVE_TO, 50, 8,
+R_H_LINE_TO, 22,
+R_V_LINE_TO, 54,
+H_LINE_TO, 50,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x9A, 0xA0, 0xA6,
+MOVE_TO, 26, 16.89f,
+R_CUBIC_TO, -5.52f, 0, -10, 4.48f, -10, 10,
+R_CUBIC_TO, 0, 5.52f, 4.48f, 10, 10, 10,
+R_CUBIC_TO, 5.52f, 0, 10, -4.48f, 10, -10,
+R_CUBIC_TO, 0, -5.52f, -4.48f, -10, -10, -10,
+CLOSE,
+R_MOVE_TO, 6.36f, 14.83f,
+R_CUBIC_TO, -1.43f, -1.74f, -4.9f, -2.33f, -6.36f, -2.33f,
+R_CUBIC_TO, -1.46f, 0, -4.93f, 0.59f, -6.36f, 2.33f,
+R_CUBIC_TO, -1.02f, -1.34f, -1.64f, -3.01f, -1.64f, -4.83f,
+R_CUBIC_TO, 0, -4.41f, 3.59f, -8, 8, -8,
+R_CUBIC_TO, 4.41f, 0, 8, 3.59f, 8, 8,
+R_CUBIC_TO, 0, 1.82f, -0.62f, 3.49f, -1.64f, 4.83f,
+CLOSE,
+R_MOVE_TO, -9.86f, -7.33f,
+R_CUBIC_TO, 0, -1.94f, 1.56f, -3.5f, 3.5f, -3.5f,
+R_CUBIC_TO, 1.94f, 0, 3.5f, 1.56f, 3.5f, 3.5f,
+R_CUBIC_TO, 0, 1.94f, -1.56f, 3.5f, -3.5f, 3.5f,
+R_CUBIC_TO, -1.94f, 0, -3.5f, -1.56f, -3.5f, -3.5f,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xFF, 0xFF, 0xFF,
+ROUND_RECT, 11, 39.8936, 30, 12, 6,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xDA, 0xDC, 0xE0,
+STROKE, 2,
+ROUND_RECT, 11, 39.8936, 30, 12, 6
diff --git a/chrome/browser/autofill_assistant/password_change/vector_icons/save_new_password.icon b/chrome/browser/autofill_assistant/password_change/vector_icons/save_new_password.icon
new file mode 100644
index 0000000..91c1c09
--- /dev/null
+++ b/chrome/browser/autofill_assistant/password_change/vector_icons/save_new_password.icon
@@ -0,0 +1,110 @@
+// 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.
+
+CANVAS_DIMENSIONS, 76,
+PATH_COLOR_ARGB, 0xFF, 0xF1, 0xF3, 0xF4,
+ROUND_RECT, 1, 1, 74, 64, 3,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+STROKE, 2,
+ROUND_RECT, 1, 1, 74, 64, 3,
+NEW_PATH,
+STROKE, 2,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+MOVE_TO, 22.33f, 1,
+CUBIC_TO, 23.81f, 1, 25, 2.19f, 25, 3.67f,
+V_LINE_TO, 5,
+R_H_LINE_TO, 50,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+MOVE_TO, 25, 1,
+R_H_LINE_TO, 49,
+R_V_LINE_TO, 4,
+H_LINE_TO, 25,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xFF, 0xFF, 0xFF,
+MOVE_TO, 50, 8,
+R_H_LINE_TO, 22,
+R_V_LINE_TO, 54,
+H_LINE_TO, 50,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xDA, 0xDC, 0xE0,
+STROKE, 2,
+MOVE_TO, 50, 8,
+R_H_LINE_TO, 22,
+R_V_LINE_TO, 54,
+H_LINE_TO, 50,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x9A, 0xA0, 0xA6,
+MOVE_TO, 26, 16.89f,
+R_CUBIC_TO, -5.52f, 0, -10, 4.48f, -10, 10,
+R_CUBIC_TO, 0, 5.52f, 4.48f, 10, 10, 10,
+R_CUBIC_TO, 5.52f, 0, 10, -4.48f, 10, -10,
+R_CUBIC_TO, 0, -5.52f, -4.48f, -10, -10, -10,
+CLOSE,
+R_MOVE_TO, 6.36f, 14.83f,
+R_CUBIC_TO, -1.43f, -1.74f, -4.9f, -2.33f, -6.36f, -2.33f,
+R_CUBIC_TO, -1.46f, 0, -4.93f, 0.59f, -6.36f, 2.33f,
+R_CUBIC_TO, -1.02f, -1.34f, -1.64f, -3.01f, -1.64f, -4.83f,
+R_CUBIC_TO, 0, -4.41f, 3.59f, -8, 8, -8,
+R_CUBIC_TO, 4.41f, 0, 8, 3.59f, 8, 8,
+R_CUBIC_TO, 0, 1.82f, -0.62f, 3.49f, -1.64f, 4.83f,
+CLOSE,
+R_MOVE_TO, -9.86f, -7.33f,
+R_CUBIC_TO, 0, -1.94f, 1.56f, -3.5f, 3.5f, -3.5f,
+R_CUBIC_TO, 1.94f, 0, 3.5f, 1.56f, 3.5f, 3.5f,
+R_CUBIC_TO, 0, 1.94f, -1.56f, 3.5f, -3.5f, 3.5f,
+R_CUBIC_TO, -1.94f, 0, -3.5f, -1.56f, -3.5f, -3.5f,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xFF, 0xFF, 0xFF,
+ROUND_RECT, 11, 39.8936, 30, 12, 6,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xDA, 0xDC, 0xE0,
+STROKE, 2,
+ROUND_RECT, 11, 39.8936, 30, 12, 6,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x9A, 0xA0, 0xA6,
+CIRCLE, 17, 45.8936, 2,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x9A, 0xA0, 0xA6,
+CIRCLE, 23, 45.8936, 2,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x9A, 0xA0, 0xA6,
+CIRCLE, 29, 45.8936, 2,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x9A, 0xA0, 0xA6,
+CIRCLE, 35, 45.8936, 2,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x1A, 0x73, 0xE8,
+MOVE_TO, 68, 28.89f,
+R_H_LINE_TO, -1.74f,
+R_ARC_TO, 7.95f, 7.95f, 0, 0, 1, 2.74f, 6,
+R_CUBIC_TO, 0, 4.08f, -3.05f, 7.44f, -7, 7.93f,
+R_V_LINE_TO, -2.02f,
+R_CUBIC_TO, 2.83f, -0.48f, 5, -2.94f, 5, -5.91f,
+R_CUBIC_TO, 0, -2.22f, -1.21f, -4.15f, -3, -5.19f,
+R_V_LINE_TO, 3.19f,
+R_H_LINE_TO, -2,
+R_V_LINE_TO, -6,
+R_H_LINE_TO, 6,
+R_V_LINE_TO, 2,
+CLOSE,
+R_MOVE_TO, -12.26f, 12,
+R_ARC_TO, 7.95f, 7.95f, 0, 0, 1, -2.74f, -6,
+R_CUBIC_TO, 0, -4.08f, 3.05f, -7.44f, 7, -7.93f,
+R_V_LINE_TO, 2.02f,
+R_CUBIC_TO, -2.83f, 0.48f, -5, 2.94f, -5, 5.91f,
+R_CUBIC_TO, 0, 2.22f, 1.21f, 4.15f, 3, 5.19f,
+R_V_LINE_TO, -3.19f,
+R_H_LINE_TO, 2,
+R_V_LINE_TO, 6,
+R_H_LINE_TO, -6,
+R_V_LINE_TO, -2,
+R_H_LINE_TO, 1.74f,
+CLOSE
diff --git a/chrome/browser/autofill_assistant/password_change/vector_icons/unspecified_state.icon b/chrome/browser/autofill_assistant/password_change/vector_icons/unspecified_state.icon
new file mode 100644
index 0000000..cf76956
--- /dev/null
+++ b/chrome/browser/autofill_assistant/password_change/vector_icons/unspecified_state.icon
@@ -0,0 +1,41 @@
+// 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.
+
+CANVAS_DIMENSIONS, 76,
+PATH_COLOR_ARGB, 0xFF, 0xF1, 0xF3, 0xF4,
+ROUND_RECT, 1, 1, 74, 64, 3,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+STROKE, 2,
+ROUND_RECT, 1, 1, 74, 64, 3,
+NEW_PATH,
+STROKE, 2,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+MOVE_TO, 22.33f, 1,
+CUBIC_TO, 23.81f, 1, 25, 2.19f, 25, 3.67f,
+V_LINE_TO, 5,
+R_H_LINE_TO, 50,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+MOVE_TO, 25, 1,
+R_H_LINE_TO, 49,
+R_V_LINE_TO, 4,
+H_LINE_TO, 25,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xFF, 0xFF, 0xFF,
+MOVE_TO, 50, 8,
+R_H_LINE_TO, 22,
+R_V_LINE_TO, 54,
+H_LINE_TO, 50,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xDA, 0xDC, 0xE0,
+STROKE, 2,
+MOVE_TO, 50, 8,
+R_H_LINE_TO, 22,
+R_V_LINE_TO, 54,
+H_LINE_TO, 50,
+CLOSE
diff --git a/chrome/browser/autofill_assistant/password_change/vector_icons/user_action_required.icon b/chrome/browser/autofill_assistant/password_change/vector_icons/user_action_required.icon
new file mode 100644
index 0000000..5aecd7a2
--- /dev/null
+++ b/chrome/browser/autofill_assistant/password_change/vector_icons/user_action_required.icon
@@ -0,0 +1,122 @@
+// 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.
+
+CANVAS_DIMENSIONS, 76,
+PATH_COLOR_ARGB, 0xFF, 0xF1, 0xF3, 0xF4,
+ROUND_RECT, 1, 1, 74, 64, 3,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+STROKE, 2,
+ROUND_RECT, 1, 1, 74, 64, 3,
+NEW_PATH,
+STROKE, 2,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+MOVE_TO, 22.33f, 1,
+CUBIC_TO, 23.81f, 1, 25, 2.19f, 25, 3.67f,
+V_LINE_TO, 5,
+R_H_LINE_TO, 50,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+MOVE_TO, 25, 1,
+R_H_LINE_TO, 49,
+R_V_LINE_TO, 4,
+H_LINE_TO, 25,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xFF, 0xFF, 0xFF,
+MOVE_TO, 50, 8,
+R_H_LINE_TO, 22,
+R_V_LINE_TO, 54,
+H_LINE_TO, 50,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xDA, 0xDC, 0xE0,
+STROKE, 2,
+MOVE_TO, 50, 8,
+R_H_LINE_TO, 22,
+R_V_LINE_TO, 54,
+H_LINE_TO, 50,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x42, 0x85, 0xF4,
+STROKE, 2,
+MOVE_TO, 4, 8,
+R_H_LINE_TO, 44,
+R_V_LINE_TO, 54,
+H_LINE_TO, 4,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xFF, 0xFF, 0xFF,
+ROUND_RECT, 10, 17, 32, 36, 2,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x66, 0x9D, 0xF6,
+MOVE_TO, 12, 19,
+R_H_LINE_TO, 8,
+R_V_LINE_TO, 8,
+R_H_LINE_TO, -8,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x66, 0x9D, 0xF6,
+STROKE, 2,
+MOVE_TO, 23, 20,
+R_H_LINE_TO, 6,
+R_V_LINE_TO, 6,
+R_H_LINE_TO, -6,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+STROKE, 2,
+MOVE_TO, 33, 20,
+R_H_LINE_TO, 6,
+R_V_LINE_TO, 6,
+R_H_LINE_TO, -6,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+STROKE, 2,
+MOVE_TO, 13, 30,
+R_H_LINE_TO, 6,
+R_V_LINE_TO, 6,
+R_H_LINE_TO, -6,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+STROKE, 2,
+MOVE_TO, 23, 30,
+R_H_LINE_TO, 6,
+R_V_LINE_TO, 6,
+R_H_LINE_TO, -6,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x66, 0x9D, 0xF6,
+STROKE, 2,
+MOVE_TO, 33, 30,
+R_H_LINE_TO, 6,
+R_V_LINE_TO, 6,
+R_H_LINE_TO, -6,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+STROKE, 2,
+MOVE_TO, 13, 40,
+R_H_LINE_TO, 6,
+R_V_LINE_TO, 6,
+R_H_LINE_TO, -6,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x66, 0x9D, 0xF6,
+STROKE, 2,
+MOVE_TO, 23, 40,
+R_H_LINE_TO, 6,
+R_V_LINE_TO, 6,
+R_H_LINE_TO, -6,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xBD, 0xC1, 0xC6,
+MOVE_TO, 32, 39,
+R_H_LINE_TO, 8,
+R_V_LINE_TO, 8,
+R_H_LINE_TO, -8,
+CLOSE
diff --git a/chrome/browser/autofill_assistant/password_change/vector_icons/vector_icons.cc.template b/chrome/browser/autofill_assistant/password_change/vector_icons/vector_icons.cc.template
new file mode 100644
index 0000000..dfec36d6
--- /dev/null
+++ b/chrome/browser/autofill_assistant/password_change/vector_icons/vector_icons.cc.template
@@ -0,0 +1,20 @@
+// 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.
+
+// vector_icons.cc.template is used to generate vector_icons.cc. Edit the former
+// rather than the latter.
+
+#include "chrome/browser/autofill_assistant/password_change/vector_icons/vector_icons.h"
+
+#include "components/vector_icons/cc_macros.h"
+#include "ui/gfx/vector_icon_types.h"
+
+#define DECLARE_VECTOR_COMMAND(x) using gfx::x;
+DECLARE_VECTOR_COMMANDS
+
+namespace autofill_assistant::password_change {
+
+TEMPLATE_PLACEHOLDER
+
+}
diff --git a/chrome/browser/autofill_assistant/password_change/vector_icons/vector_icons.h.template b/chrome/browser/autofill_assistant/password_change/vector_icons/vector_icons.h.template
new file mode 100644
index 0000000..abab041
--- /dev/null
+++ b/chrome/browser/autofill_assistant/password_change/vector_icons/vector_icons.h.template
@@ -0,0 +1,26 @@
+// 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.
+
+// vector_icons.h.template is used to generate vector_icons.h. Edit the former
+// rather than the latter.
+
+#ifndef CHROME_BROWSER_AUTOFILL_ASSISTANT_PASSWORD_CHANGE_VECTOR_ICONS_VECTOR_ICONS_H
+#define CHROME_BROWSER_AUTOFILL_ASSISTANT_PASSWORD_CHANGE_VECTOR_ICONS_VECTOR_ICONS_H
+
+namespace gfx {
+struct VectorIcon;
+}
+
+namespace autofill_assistant::password_change {
+
+#define VECTOR_ICON_TEMPLATE_H(icon_name) \
+extern const gfx::VectorIcon icon_name;
+
+TEMPLATE_PLACEHOLDER
+
+#undef VECTOR_ICON_TEMPLATE_H
+
+}
+
+#endif  // CHROME_BROWSER_AUTOFILL_ASSISTANT_PASSWORD_CHANGE_VECTOR_ICONS_VECTOR_ICONS_H
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index e0ffa454..275721b 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -990,6 +990,8 @@
     "../ash/input_method/ui/candidate_window_view.h",
     "../ash/input_method/ui/colors.cc",
     "../ash/input_method/ui/colors.h",
+    "../ash/input_method/ui/completion_suggestion_label_view.cc",
+    "../ash/input_method/ui/completion_suggestion_label_view.h",
     "../ash/input_method/ui/grammar_suggestion_window.cc",
     "../ash/input_method/ui/grammar_suggestion_window.h",
     "../ash/input_method/ui/infolist_window.cc",
@@ -3599,9 +3601,11 @@
     "../ash/input_method/ui/assistive_accessibility_view_unittest.cc",
     "../ash/input_method/ui/candidate_view_unittest.cc",
     "../ash/input_method/ui/candidate_window_view_unittest.cc",
+    "../ash/input_method/ui/completion_suggestion_label_view_unittest.cc",
     "../ash/input_method/ui/grammar_suggestion_window_unittest.cc",
     "../ash/input_method/ui/input_method_menu_item_unittest.cc",
     "../ash/input_method/ui/input_method_menu_manager_unittest.cc",
+    "../ash/input_method/ui/suggestion_view_unittest.cc",
     "../ash/input_method/ui/suggestion_window_view_unittest.cc",
     "../ash/input_method/ui/undo_window_unittest.cc",
     "../ash/kerberos/kerberos_credentials_manager_test.cc",
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
index 78ce7c4d..81735dd 100644
--- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
+++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
@@ -2117,18 +2117,40 @@
   if (!swa_manager)
     return RespondNow(Error("System Web Apps are not available for profile."));
 
-  std::vector<api::autotest_private::SystemApp> result;
+  swa_manager->on_apps_synchronized().Post(
+      FROM_HERE,
+      base::BindOnce(&AutotestPrivateGetRegisteredSystemWebAppsFunction::
+                         OnSystemWebAppsInstalled,
+                     this));
+  return RespondLater();
+}
 
+void AutotestPrivateGetRegisteredSystemWebAppsFunction::
+    OnSystemWebAppsInstalled() {
+  Profile* profile = Profile::FromBrowserContext(browser_context());
+  ash::SystemWebAppManager* swa_manager =
+      ash::SystemWebAppManager::GetForTest(profile);
+  std::vector<api::autotest_private::SystemWebApp> result;
   for (const auto& type_and_info : swa_manager->system_app_delegates()) {
-    api::autotest_private::SystemApp system_app;
+    api::autotest_private::SystemWebApp system_web_app;
     ash::SystemWebAppDelegate* delegate = type_and_info.second.get();
-    system_app.internal_name = delegate->GetInternalName();
-    system_app.url =
+    system_web_app.internal_name = delegate->GetInternalName();
+    system_web_app.url =
         delegate->GetInstallUrl().DeprecatedGetOriginAsURL().spec();
-    result.push_back(std::move(system_app));
+    system_web_app.name = base::UTF16ToUTF8(delegate->GetWebAppInfo()->title);
+
+    absl::optional<web_app::AppId> app_id =
+        swa_manager->GetAppIdForSystemApp(type_and_info.first);
+    if (app_id) {
+      system_web_app.start_url = web_app::WebAppProvider::GetForTest(profile)
+                                     ->registrar()
+                                     .GetAppLaunchUrl(*app_id)
+                                     .spec();
+    }
+    result.push_back(std::move(system_web_app));
   }
 
-  return RespondNow(ArgumentList(
+  Respond(ArgumentList(
       api::autotest_private::GetRegisteredSystemWebApps::Results::Create(
           result)));
 }
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h
index 1659cf4..f4ff9cb 100644
--- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h
+++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h
@@ -378,6 +378,8 @@
  private:
   ~AutotestPrivateGetRegisteredSystemWebAppsFunction() override;
   ResponseAction Run() override;
+
+  void OnSystemWebAppsInstalled();
 };
 
 class AutotestPrivateIsSystemWebAppOpenFunction : public ExtensionFunction {
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/telemetry_api.cc b/chrome/browser/chromeos/extensions/telemetry/api/telemetry_api.cc
index 8f2bd22..ca01b03 100644
--- a/chrome/browser/chromeos/extensions/telemetry/api/telemetry_api.cc
+++ b/chrome/browser/chromeos/extensions/telemetry/api/telemetry_api.cc
@@ -22,84 +22,81 @@
     : probe_service_(remote_probe_service_.BindNewPipeAndPassReceiver()) {}
 TelemetryApiFunctionBase::~TelemetryApiFunctionBase() = default;
 
-// OsTelemetryGetVpdInfoFunction -----------------------------------------------
+// OsTelemetryGetBatteryInfoFunction -------------------------------------------
 
-OsTelemetryGetVpdInfoFunction::OsTelemetryGetVpdInfoFunction() = default;
-OsTelemetryGetVpdInfoFunction::~OsTelemetryGetVpdInfoFunction() = default;
+OsTelemetryGetBatteryInfoFunction::OsTelemetryGetBatteryInfoFunction() =
+    default;
+OsTelemetryGetBatteryInfoFunction::~OsTelemetryGetBatteryInfoFunction() =
+    default;
 
-void OsTelemetryGetVpdInfoFunction::RunIfAllowed() {
-  auto cb = base::BindOnce(&OsTelemetryGetVpdInfoFunction::OnResult, this);
+void OsTelemetryGetBatteryInfoFunction::RunIfAllowed() {
+  auto cb = base::BindOnce(&OsTelemetryGetBatteryInfoFunction::OnResult, this);
 
   remote_probe_service_->ProbeTelemetryInfo(
-      {ash::health::mojom::ProbeCategoryEnum::kCachedVpdData}, std::move(cb));
+      {ash::health::mojom::ProbeCategoryEnum::kBattery}, std::move(cb));
 }
 
-void OsTelemetryGetVpdInfoFunction::OnResult(
+void OsTelemetryGetBatteryInfoFunction::OnResult(
     ash::health::mojom::TelemetryInfoPtr ptr) {
-  if (!ptr || !ptr->vpd_result || !ptr->vpd_result->is_vpd_info()) {
+  if (!ptr || !ptr->battery_result || !ptr->battery_result->is_battery_info()) {
     Respond(Error("API internal error"));
     return;
   }
-
-  api::os_telemetry::VpdInfo result;
-
-  const auto& vpd_info = ptr->vpd_result->get_vpd_info();
-  if (vpd_info->first_power_date.has_value()) {
-    result.activate_date =
-        std::make_unique<std::string>(vpd_info->first_power_date.value());
-  }
-  if (vpd_info->model_name.has_value()) {
-    result.model_name =
-        std::make_unique<std::string>(vpd_info->model_name.value());
-  }
-  if (vpd_info->sku_number.has_value()) {
-    result.sku_number =
-        std::make_unique<std::string>(vpd_info->sku_number.value());
-  }
+  auto& battery_info = ptr->battery_result->get_battery_info();
 
   // Protect accessing the serial number by a permission.
+  std::unique_ptr<std::string> serial_number;
   if (extension()->permissions_data()->HasAPIPermission(
           extensions::mojom::APIPermissionID::kChromeOSTelemetrySerialNumber) &&
-      vpd_info->serial_number.has_value()) {
-    result.serial_number =
-        std::make_unique<std::string>(vpd_info->serial_number.value());
+      battery_info->serial_number.has_value()) {
+    serial_number = std::make_unique<std::string>(
+        std::move(battery_info->serial_number.value()));
   }
 
-  Respond(ArgumentList(api::os_telemetry::GetVpdInfo::Results::Create(result)));
-}
+  api::os_telemetry::BatteryInfo result =
+      converters::ConvertPtr<api::os_telemetry::BatteryInfo>(
+          std::move(battery_info));
 
-// OsTelemetryGetOemDataFunction -----------------------------------------------
-
-OsTelemetryGetOemDataFunction::OsTelemetryGetOemDataFunction() = default;
-OsTelemetryGetOemDataFunction::~OsTelemetryGetOemDataFunction() = default;
-
-void OsTelemetryGetOemDataFunction::RunIfAllowed() {
-  // Protect accessing the serial number by a permission.
-  if (!extension()->permissions_data()->HasAPIPermission(
-          extensions::mojom::APIPermissionID::kChromeOSTelemetrySerialNumber)) {
-    Respond(
-        Error("Unauthorized access to chrome.os.telemetry.getOemData. Extension"
-              " doesn't have the permission."));
-    return;
+  if (serial_number && !serial_number->empty()) {
+    result.serial_number = std::move(serial_number);
   }
 
-  auto cb = base::BindOnce(&OsTelemetryGetOemDataFunction::OnResult, this);
-
-  remote_probe_service_->GetOemData(std::move(cb));
+  Respond(
+      ArgumentList(api::os_telemetry::GetBatteryInfo::Results::Create(result)));
 }
 
-void OsTelemetryGetOemDataFunction::OnResult(
-    ash::health::mojom::OemDataPtr ptr) {
-  if (!ptr || !ptr->oem_data.has_value()) {
+// OsTelemetryGetCpuInfoFunction -----------------------------------------------
+
+OsTelemetryGetCpuInfoFunction::OsTelemetryGetCpuInfoFunction() = default;
+OsTelemetryGetCpuInfoFunction::~OsTelemetryGetCpuInfoFunction() = default;
+
+void OsTelemetryGetCpuInfoFunction::RunIfAllowed() {
+  auto cb = base::BindOnce(&OsTelemetryGetCpuInfoFunction::OnResult, this);
+
+  remote_probe_service_->ProbeTelemetryInfo(
+      {ash::health::mojom::ProbeCategoryEnum::kCpu}, std::move(cb));
+}
+
+void OsTelemetryGetCpuInfoFunction::OnResult(
+    ash::health::mojom::TelemetryInfoPtr ptr) {
+  if (!ptr || !ptr->cpu_result || !ptr->cpu_result->is_cpu_info()) {
     Respond(Error("API internal error"));
     return;
   }
 
-  api::os_telemetry::OemData result;
-  result.oem_data =
-      std::make_unique<std::string>(std::move(ptr->oem_data.value()));
+  const auto& cpu_info = ptr->cpu_result->get_cpu_info();
 
-  Respond(ArgumentList(api::os_telemetry::GetOemData::Results::Create(result)));
+  api::os_telemetry::CpuInfo result;
+  if (cpu_info->num_total_threads) {
+    result.num_total_threads =
+        std::make_unique<int32_t>(cpu_info->num_total_threads->value);
+  }
+  result.architecture = converters::Convert(cpu_info->architecture);
+  result.physical_cpus =
+      converters::ConvertPtrVector<api::os_telemetry::PhysicalCpuInfo>(
+          std::move(cpu_info->physical_cpus));
+
+  Respond(ArgumentList(api::os_telemetry::GetCpuInfo::Results::Create(result)));
 }
 
 // OsTelemetryGetMemoryInfoFunction --------------------------------------------
@@ -145,81 +142,84 @@
       ArgumentList(api::os_telemetry::GetMemoryInfo::Results::Create(result)));
 }
 
-// OsTelemetryGetCpuInfoFunction -----------------------------------------------
+// OsTelemetryGetOemDataFunction -----------------------------------------------
 
-OsTelemetryGetCpuInfoFunction::OsTelemetryGetCpuInfoFunction() = default;
-OsTelemetryGetCpuInfoFunction::~OsTelemetryGetCpuInfoFunction() = default;
+OsTelemetryGetOemDataFunction::OsTelemetryGetOemDataFunction() = default;
+OsTelemetryGetOemDataFunction::~OsTelemetryGetOemDataFunction() = default;
 
-void OsTelemetryGetCpuInfoFunction::RunIfAllowed() {
-  auto cb = base::BindOnce(&OsTelemetryGetCpuInfoFunction::OnResult, this);
+void OsTelemetryGetOemDataFunction::RunIfAllowed() {
+  // Protect accessing the serial number by a permission.
+  if (!extension()->permissions_data()->HasAPIPermission(
+          extensions::mojom::APIPermissionID::kChromeOSTelemetrySerialNumber)) {
+    Respond(
+        Error("Unauthorized access to chrome.os.telemetry.getOemData. Extension"
+              " doesn't have the permission."));
+    return;
+  }
 
-  remote_probe_service_->ProbeTelemetryInfo(
-      {ash::health::mojom::ProbeCategoryEnum::kCpu}, std::move(cb));
+  auto cb = base::BindOnce(&OsTelemetryGetOemDataFunction::OnResult, this);
+
+  remote_probe_service_->GetOemData(std::move(cb));
 }
 
-void OsTelemetryGetCpuInfoFunction::OnResult(
-    ash::health::mojom::TelemetryInfoPtr ptr) {
-  if (!ptr || !ptr->cpu_result || !ptr->cpu_result->is_cpu_info()) {
+void OsTelemetryGetOemDataFunction::OnResult(
+    ash::health::mojom::OemDataPtr ptr) {
+  if (!ptr || !ptr->oem_data.has_value()) {
     Respond(Error("API internal error"));
     return;
   }
 
-  const auto& cpu_info = ptr->cpu_result->get_cpu_info();
+  api::os_telemetry::OemData result;
+  result.oem_data =
+      std::make_unique<std::string>(std::move(ptr->oem_data.value()));
 
-  api::os_telemetry::CpuInfo result;
-  if (cpu_info->num_total_threads) {
-    result.num_total_threads =
-        std::make_unique<int32_t>(cpu_info->num_total_threads->value);
-  }
-  result.architecture = converters::Convert(cpu_info->architecture);
-  result.physical_cpus =
-      converters::ConvertPtrVector<api::os_telemetry::PhysicalCpuInfo>(
-          std::move(cpu_info->physical_cpus));
-
-  Respond(ArgumentList(api::os_telemetry::GetCpuInfo::Results::Create(result)));
+  Respond(ArgumentList(api::os_telemetry::GetOemData::Results::Create(result)));
 }
 
-// OsTelemetryGetBatteryInfoFunction -------------------------------------------
+// OsTelemetryGetVpdInfoFunction -----------------------------------------------
 
-OsTelemetryGetBatteryInfoFunction::OsTelemetryGetBatteryInfoFunction() =
-    default;
-OsTelemetryGetBatteryInfoFunction::~OsTelemetryGetBatteryInfoFunction() =
-    default;
+OsTelemetryGetVpdInfoFunction::OsTelemetryGetVpdInfoFunction() = default;
+OsTelemetryGetVpdInfoFunction::~OsTelemetryGetVpdInfoFunction() = default;
 
-void OsTelemetryGetBatteryInfoFunction::RunIfAllowed() {
-  auto cb = base::BindOnce(&OsTelemetryGetBatteryInfoFunction::OnResult, this);
+void OsTelemetryGetVpdInfoFunction::RunIfAllowed() {
+  auto cb = base::BindOnce(&OsTelemetryGetVpdInfoFunction::OnResult, this);
 
   remote_probe_service_->ProbeTelemetryInfo(
-      {ash::health::mojom::ProbeCategoryEnum::kBattery}, std::move(cb));
+      {ash::health::mojom::ProbeCategoryEnum::kCachedVpdData}, std::move(cb));
 }
 
-void OsTelemetryGetBatteryInfoFunction::OnResult(
+void OsTelemetryGetVpdInfoFunction::OnResult(
     ash::health::mojom::TelemetryInfoPtr ptr) {
-  if (!ptr || !ptr->battery_result || !ptr->battery_result->is_battery_info()) {
+  if (!ptr || !ptr->vpd_result || !ptr->vpd_result->is_vpd_info()) {
     Respond(Error("API internal error"));
     return;
   }
-  auto& battery_info = ptr->battery_result->get_battery_info();
+
+  api::os_telemetry::VpdInfo result;
+
+  const auto& vpd_info = ptr->vpd_result->get_vpd_info();
+  if (vpd_info->first_power_date.has_value()) {
+    result.activate_date =
+        std::make_unique<std::string>(vpd_info->first_power_date.value());
+  }
+  if (vpd_info->model_name.has_value()) {
+    result.model_name =
+        std::make_unique<std::string>(vpd_info->model_name.value());
+  }
+  if (vpd_info->sku_number.has_value()) {
+    result.sku_number =
+        std::make_unique<std::string>(vpd_info->sku_number.value());
+  }
 
   // Protect accessing the serial number by a permission.
-  std::unique_ptr<std::string> serial_number;
   if (extension()->permissions_data()->HasAPIPermission(
           extensions::mojom::APIPermissionID::kChromeOSTelemetrySerialNumber) &&
-      battery_info->serial_number.has_value()) {
-    serial_number = std::make_unique<std::string>(
-        std::move(battery_info->serial_number.value()));
+      vpd_info->serial_number.has_value()) {
+    result.serial_number =
+        std::make_unique<std::string>(vpd_info->serial_number.value());
   }
 
-  api::os_telemetry::BatteryInfo result =
-      converters::ConvertPtr<api::os_telemetry::BatteryInfo>(
-          std::move(battery_info));
-
-  if (serial_number && !serial_number->empty()) {
-    result.serial_number = std::move(serial_number);
-  }
-
-  Respond(
-      ArgumentList(api::os_telemetry::GetBatteryInfo::Results::Create(result)));
+  Respond(ArgumentList(api::os_telemetry::GetVpdInfo::Results::Create(result)));
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/telemetry_api.h b/chrome/browser/chromeos/extensions/telemetry/api/telemetry_api.h
index 61f2a61..cc0c35c 100644
--- a/chrome/browser/chromeos/extensions/telemetry/api/telemetry_api.h
+++ b/chrome/browser/chromeos/extensions/telemetry/api/telemetry_api.h
@@ -30,55 +30,19 @@
   ash::ProbeService probe_service_;
 };
 
-class OsTelemetryGetVpdInfoFunction : public TelemetryApiFunctionBase {
+class OsTelemetryGetBatteryInfoFunction : public TelemetryApiFunctionBase {
  public:
-  DECLARE_EXTENSION_FUNCTION("os.telemetry.getVpdInfo", OS_TELEMETRY_GETVPDINFO)
+  DECLARE_EXTENSION_FUNCTION("os.telemetry.getBatteryInfo",
+                             OS_TELEMETRY_GETBATTERYINFO)
 
-  OsTelemetryGetVpdInfoFunction();
-  OsTelemetryGetVpdInfoFunction(const OsTelemetryGetVpdInfoFunction&) = delete;
-  OsTelemetryGetVpdInfoFunction& operator=(
-      const OsTelemetryGetVpdInfoFunction&) = delete;
-
- private:
-  ~OsTelemetryGetVpdInfoFunction() override;
-
-  // BaseTelemetryExtensionApiGuardFunction:
-  void RunIfAllowed() override;
-
-  void OnResult(ash::health::mojom::TelemetryInfoPtr ptr);
-};
-
-class OsTelemetryGetOemDataFunction : public TelemetryApiFunctionBase {
- public:
-  DECLARE_EXTENSION_FUNCTION("os.telemetry.getOemData", OS_TELEMETRY_GETOEMDATA)
-
-  OsTelemetryGetOemDataFunction();
-  OsTelemetryGetOemDataFunction(const OsTelemetryGetOemDataFunction&) = delete;
-  OsTelemetryGetOemDataFunction& operator=(
-      const OsTelemetryGetOemDataFunction&) = delete;
-
- private:
-  ~OsTelemetryGetOemDataFunction() override;
-
-  // BaseTelemetryExtensionApiGuardFunction:
-  void RunIfAllowed() override;
-
-  void OnResult(ash::health::mojom::OemDataPtr ptr);
-};
-
-class OsTelemetryGetMemoryInfoFunction : public TelemetryApiFunctionBase {
- public:
-  DECLARE_EXTENSION_FUNCTION("os.telemetry.getMemoryInfo",
-                             OS_TELEMETRY_GETMEMORYINFO)
-
-  OsTelemetryGetMemoryInfoFunction();
-  OsTelemetryGetMemoryInfoFunction(const OsTelemetryGetMemoryInfoFunction&) =
+  OsTelemetryGetBatteryInfoFunction();
+  OsTelemetryGetBatteryInfoFunction(const OsTelemetryGetBatteryInfoFunction&) =
       delete;
-  OsTelemetryGetMemoryInfoFunction& operator=(
-      const OsTelemetryGetMemoryInfoFunction&) = delete;
+  OsTelemetryGetBatteryInfoFunction& operator=(
+      const OsTelemetryGetBatteryInfoFunction&) = delete;
 
  private:
-  ~OsTelemetryGetMemoryInfoFunction() override;
+  ~OsTelemetryGetBatteryInfoFunction() override;
 
   // BaseTelemetryExtensionApiGuardFunction:
   void RunIfAllowed() override;
@@ -104,19 +68,55 @@
   void OnResult(ash::health::mojom::TelemetryInfoPtr ptr);
 };
 
-class OsTelemetryGetBatteryInfoFunction : public TelemetryApiFunctionBase {
+class OsTelemetryGetMemoryInfoFunction : public TelemetryApiFunctionBase {
  public:
-  DECLARE_EXTENSION_FUNCTION("os.telemetry.getBatteryInfo",
-                             OS_TELEMETRY_GETBATTERYINFO)
+  DECLARE_EXTENSION_FUNCTION("os.telemetry.getMemoryInfo",
+                             OS_TELEMETRY_GETMEMORYINFO)
 
-  OsTelemetryGetBatteryInfoFunction();
-  OsTelemetryGetBatteryInfoFunction(const OsTelemetryGetBatteryInfoFunction&) =
+  OsTelemetryGetMemoryInfoFunction();
+  OsTelemetryGetMemoryInfoFunction(const OsTelemetryGetMemoryInfoFunction&) =
       delete;
-  OsTelemetryGetBatteryInfoFunction& operator=(
-      const OsTelemetryGetBatteryInfoFunction&) = delete;
+  OsTelemetryGetMemoryInfoFunction& operator=(
+      const OsTelemetryGetMemoryInfoFunction&) = delete;
 
  private:
-  ~OsTelemetryGetBatteryInfoFunction() override;
+  ~OsTelemetryGetMemoryInfoFunction() override;
+
+  // BaseTelemetryExtensionApiGuardFunction:
+  void RunIfAllowed() override;
+
+  void OnResult(ash::health::mojom::TelemetryInfoPtr ptr);
+};
+
+class OsTelemetryGetOemDataFunction : public TelemetryApiFunctionBase {
+ public:
+  DECLARE_EXTENSION_FUNCTION("os.telemetry.getOemData", OS_TELEMETRY_GETOEMDATA)
+
+  OsTelemetryGetOemDataFunction();
+  OsTelemetryGetOemDataFunction(const OsTelemetryGetOemDataFunction&) = delete;
+  OsTelemetryGetOemDataFunction& operator=(
+      const OsTelemetryGetOemDataFunction&) = delete;
+
+ private:
+  ~OsTelemetryGetOemDataFunction() override;
+
+  // BaseTelemetryExtensionApiGuardFunction:
+  void RunIfAllowed() override;
+
+  void OnResult(ash::health::mojom::OemDataPtr ptr);
+};
+
+class OsTelemetryGetVpdInfoFunction : public TelemetryApiFunctionBase {
+ public:
+  DECLARE_EXTENSION_FUNCTION("os.telemetry.getVpdInfo", OS_TELEMETRY_GETVPDINFO)
+
+  OsTelemetryGetVpdInfoFunction();
+  OsTelemetryGetVpdInfoFunction(const OsTelemetryGetVpdInfoFunction&) = delete;
+  OsTelemetryGetVpdInfoFunction& operator=(
+      const OsTelemetryGetVpdInfoFunction&) = delete;
+
+ private:
+  ~OsTelemetryGetVpdInfoFunction() override;
 
   // BaseTelemetryExtensionApiGuardFunction:
   void RunIfAllowed() override;
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/telemetry_api_browsertest.cc b/chrome/browser/chromeos/extensions/telemetry/api/telemetry_api_browsertest.cc
index 7e7d161..910361a 100644
--- a/chrome/browser/chromeos/extensions/telemetry/api/telemetry_api_browsertest.cc
+++ b/chrome/browser/chromeos/extensions/telemetry/api/telemetry_api_browsertest.cc
@@ -18,62 +18,6 @@
 using TelemetryExtensionTelemetryApiBrowserTest =
     BaseTelemetryExtensionBrowserTest;
 
-IN_PROC_BROWSER_TEST_F(TelemetryExtensionTelemetryApiBrowserTest,
-                       GetVpdInfoError) {
-  CreateExtensionAndRunServiceWorker(R"(
-    chrome.test.runTests([
-      async function getVpdInfo() {
-        await chrome.test.assertPromiseRejects(
-            chrome.os.telemetry.getVpdInfo(),
-            'Error: API internal error'
-        );
-        chrome.test.succeed();
-      }
-    ]);
-  )");
-}
-
-IN_PROC_BROWSER_TEST_F(TelemetryExtensionTelemetryApiBrowserTest,
-                       GetVpdInfoWithSerialNumberPermission) {
-  // Configure fake cros_healthd response.
-  {
-    auto telemetry_info = cros_healthd::mojom::TelemetryInfo::New();
-
-    {
-      auto os_version = cros_healthd::mojom::OsVersion::New();
-
-      auto system_info = cros_healthd::mojom::SystemInfo::New();
-      system_info->first_power_date = "2021-50";
-      system_info->product_model_name = "COOL-LAPTOP-CHROME";
-      system_info->product_serial_number = "5CD9132880";
-      system_info->product_sku_number = "sku15";
-      system_info->os_version = std::move(os_version);
-
-      telemetry_info->system_result =
-          cros_healthd::mojom::SystemResult::NewSystemInfo(
-              std::move(system_info));
-    }
-
-    ASSERT_TRUE(cros_healthd::FakeCrosHealthd::Get());
-
-    cros_healthd::FakeCrosHealthd::Get()
-        ->SetProbeTelemetryInfoResponseForTesting(telemetry_info);
-  }
-
-  CreateExtensionAndRunServiceWorker(R"(
-    chrome.test.runTests([
-      async function getVpdInfo() {
-        const result = await chrome.os.telemetry.getVpdInfo();
-        chrome.test.assertEq("2021-50", result.activateDate);
-        chrome.test.assertEq("COOL-LAPTOP-CHROME", result.modelName);
-        chrome.test.assertEq("5CD9132880", result.serialNumber);
-        chrome.test.assertEq("sku15", result.skuNumber);
-        chrome.test.succeed();
-      }
-    ]);
-  )");
-}
-
 namespace {
 
 class TestDebugDaemonClient : public FakeDebugDaemonClient {
@@ -91,15 +35,12 @@
 }  // namespace
 
 IN_PROC_BROWSER_TEST_F(TelemetryExtensionTelemetryApiBrowserTest,
-                       GetOemDataWithSerialNumberPermission_Error) {
-  DBusThreadManager::GetSetterForTesting()->SetDebugDaemonClient(
-      std::make_unique<TestDebugDaemonClient>());
-
+                       GetBatteryInfo_Error) {
   CreateExtensionAndRunServiceWorker(R"(
     chrome.test.runTests([
-      async function getOemData() {
+      async function getBatteryInfo() {
         await chrome.test.assertPromiseRejects(
-            chrome.os.telemetry.getOemData(),
+            chrome.os.telemetry.getBatteryInfo(),
             'Error: API internal error'
         );
         chrome.test.succeed();
@@ -109,67 +50,61 @@
 }
 
 IN_PROC_BROWSER_TEST_F(TelemetryExtensionTelemetryApiBrowserTest,
-                       GetOemDataWithSerialNumberPermission_Success) {
-  CreateExtensionAndRunServiceWorker(R"(
-    chrome.test.runTests([
-      async function getOemData() {
-        const result = await chrome.os.telemetry.getOemData();
-        chrome.test.assertEq(
-          "oemdata: response from GetLog", result.oemData);
-        chrome.test.succeed();
-      }
-    ]);
-  )");
-}
-
-IN_PROC_BROWSER_TEST_F(TelemetryExtensionTelemetryApiBrowserTest,
-                       GetMemoryInfo_Error) {
-  CreateExtensionAndRunServiceWorker(R"(
-    chrome.test.runTests([
-      async function getMemoryInfo() {
-        await chrome.test.assertPromiseRejects(
-            chrome.os.telemetry.getMemoryInfo(),
-            'Error: API internal error'
-        );
-        chrome.test.succeed();
-      }
-    ]);
-  )");
-}
-
-IN_PROC_BROWSER_TEST_F(TelemetryExtensionTelemetryApiBrowserTest,
-                       GetMemoryInfo_Success) {
+                       GetBatteryInfo_Success) {
   // Configure fake cros_healthd response.
   {
-    auto telemetry_info = cros_healthd::mojom::TelemetryInfo::New();
-
+    auto telemetry_info = chromeos::cros_healthd::mojom::TelemetryInfo::New();
     {
-      auto memory_info = chromeos::cros_healthd::mojom::MemoryInfo::New();
-      memory_info->total_memory_kib = 2147483647;
-      memory_info->free_memory_kib = 2147483646;
-      memory_info->available_memory_kib = 2147483645;
-      memory_info->page_faults_since_last_boot = 4611686018427388000;
+      auto battery_info = chromeos::cros_healthd::mojom::BatteryInfo::New();
+      battery_info->cycle_count = 100000000000000;
+      battery_info->voltage_now = 1234567890.123456;
+      battery_info->vendor = "Google";
+      battery_info->serial_number = "abcdef";
+      battery_info->charge_full_design = 3000000000000000;
+      battery_info->charge_full = 9000000000000000;
+      battery_info->voltage_min_design = 1000000000.1001;
+      battery_info->model_name = "Google Battery";
+      battery_info->charge_now = 7777777777.777;
+      battery_info->current_now = 0.9999999999999;
+      battery_info->technology = "Li-ion";
+      battery_info->status = "Charging";
+      battery_info->manufacture_date = "2020-07-30";
+      battery_info->temperature =
+          chromeos::cros_healthd::mojom::NullableUint64::New(7777777777777777);
 
-      telemetry_info->memory_result =
-          chromeos::cros_healthd::mojom::MemoryResult::NewMemoryInfo(
-              std::move(memory_info));
+      telemetry_info->battery_result =
+          chromeos::cros_healthd::mojom::BatteryResult::NewBatteryInfo(
+              std::move(battery_info));
     }
 
     ASSERT_TRUE(cros_healthd::FakeCrosHealthd::Get());
-
     cros_healthd::FakeCrosHealthd::Get()
         ->SetProbeTelemetryInfoResponseForTesting(telemetry_info);
   }
 
   CreateExtensionAndRunServiceWorker(R"(
     chrome.test.runTests([
-      async function getMemoryInfo() {
-        const result = await chrome.os.telemetry.getMemoryInfo();
-        chrome.test.assertEq(2147483647, result.totalMemoryKiB);
-        chrome.test.assertEq(2147483646, result.freeMemoryKiB);
-        chrome.test.assertEq(2147483645, result.availableMemoryKiB);
-        chrome.test.assertEq(4611686018427388000,
-          result.pageFaultsSinceLastBoot);
+      async function getBatteryInfo() {
+        const result = await chrome.os.telemetry.getBatteryInfo();
+         chrome.test.assertEq(
+          // The dictionary members are ordered lexicographically by the Unicode
+          // codepoints that comprise their identifiers.
+          {
+            chargeFull: 9000000000000000,
+            chargeFullDesign: 3000000000000000,
+            chargeNow: 7777777777.777,
+            currentNow: 0.9999999999999,
+            cycleCount: 100000000000000,
+            manufactureDate: '2020-07-30',
+            modelName: 'Google Battery',
+            serialNumber: 'abcdef',
+            status: 'Charging',
+            technology: 'Li-ion',
+            temperature: 7777777777777777,
+            vendor: 'Google',
+            voltageMinDesign: 1000000000.1001,
+            voltageNow: 1234567890.123456,
+          }, result);
         chrome.test.succeed();
       }
     ]);
@@ -313,12 +248,12 @@
 }
 
 IN_PROC_BROWSER_TEST_F(TelemetryExtensionTelemetryApiBrowserTest,
-                       GetBatteryInfo_Error) {
+                       GetMemoryInfo_Error) {
   CreateExtensionAndRunServiceWorker(R"(
     chrome.test.runTests([
-      async function getBatteryInfo() {
+      async function getMemoryInfo() {
         await chrome.test.assertPromiseRejects(
-            chrome.os.telemetry.getBatteryInfo(),
+            chrome.os.telemetry.getMemoryInfo(),
             'Error: API internal error'
         );
         chrome.test.succeed();
@@ -328,61 +263,126 @@
 }
 
 IN_PROC_BROWSER_TEST_F(TelemetryExtensionTelemetryApiBrowserTest,
-                       GetBatteryInfo_Success) {
+                       GetMemoryInfo_Success) {
   // Configure fake cros_healthd response.
   {
-    auto telemetry_info = chromeos::cros_healthd::mojom::TelemetryInfo::New();
-    {
-      auto battery_info = chromeos::cros_healthd::mojom::BatteryInfo::New();
-      battery_info->cycle_count = 100000000000000;
-      battery_info->voltage_now = 1234567890.123456;
-      battery_info->vendor = "Google";
-      battery_info->serial_number = "abcdef";
-      battery_info->charge_full_design = 3000000000000000;
-      battery_info->charge_full = 9000000000000000;
-      battery_info->voltage_min_design = 1000000000.1001;
-      battery_info->model_name = "Google Battery";
-      battery_info->charge_now = 7777777777.777;
-      battery_info->current_now = 0.9999999999999;
-      battery_info->technology = "Li-ion";
-      battery_info->status = "Charging";
-      battery_info->manufacture_date = "2020-07-30";
-      battery_info->temperature =
-          chromeos::cros_healthd::mojom::NullableUint64::New(7777777777777777);
+    auto telemetry_info = cros_healthd::mojom::TelemetryInfo::New();
 
-      telemetry_info->battery_result =
-          chromeos::cros_healthd::mojom::BatteryResult::NewBatteryInfo(
-              std::move(battery_info));
+    {
+      auto memory_info = chromeos::cros_healthd::mojom::MemoryInfo::New();
+      memory_info->total_memory_kib = 2147483647;
+      memory_info->free_memory_kib = 2147483646;
+      memory_info->available_memory_kib = 2147483645;
+      memory_info->page_faults_since_last_boot = 4611686018427388000;
+
+      telemetry_info->memory_result =
+          chromeos::cros_healthd::mojom::MemoryResult::NewMemoryInfo(
+              std::move(memory_info));
     }
 
     ASSERT_TRUE(cros_healthd::FakeCrosHealthd::Get());
+
     cros_healthd::FakeCrosHealthd::Get()
         ->SetProbeTelemetryInfoResponseForTesting(telemetry_info);
   }
 
   CreateExtensionAndRunServiceWorker(R"(
     chrome.test.runTests([
-      async function getBatteryInfo() {
-        const result = await chrome.os.telemetry.getBatteryInfo();
-         chrome.test.assertEq(
-          // The dictionary members are ordered lexicographically by the Unicode
-          // codepoints that comprise their identifiers.
-          {
-            chargeFull: 9000000000000000,
-            chargeFullDesign: 3000000000000000,
-            chargeNow: 7777777777.777,
-            currentNow: 0.9999999999999,
-            cycleCount: 100000000000000,
-            manufactureDate: '2020-07-30',
-            modelName: 'Google Battery',
-            serialNumber: 'abcdef',
-            status: 'Charging',
-            technology: 'Li-ion',
-            temperature: 7777777777777777,
-            vendor: 'Google',
-            voltageMinDesign: 1000000000.1001,
-            voltageNow: 1234567890.123456,
-          }, result);
+      async function getMemoryInfo() {
+        const result = await chrome.os.telemetry.getMemoryInfo();
+        chrome.test.assertEq(2147483647, result.totalMemoryKiB);
+        chrome.test.assertEq(2147483646, result.freeMemoryKiB);
+        chrome.test.assertEq(2147483645, result.availableMemoryKiB);
+        chrome.test.assertEq(4611686018427388000,
+          result.pageFaultsSinceLastBoot);
+        chrome.test.succeed();
+      }
+    ]);
+  )");
+}
+
+IN_PROC_BROWSER_TEST_F(TelemetryExtensionTelemetryApiBrowserTest,
+                       GetOemDataWithSerialNumberPermission_Error) {
+  DBusThreadManager::GetSetterForTesting()->SetDebugDaemonClient(
+      std::make_unique<TestDebugDaemonClient>());
+
+  CreateExtensionAndRunServiceWorker(R"(
+    chrome.test.runTests([
+      async function getOemData() {
+        await chrome.test.assertPromiseRejects(
+            chrome.os.telemetry.getOemData(),
+            'Error: API internal error'
+        );
+        chrome.test.succeed();
+      }
+    ]);
+  )");
+}
+
+IN_PROC_BROWSER_TEST_F(TelemetryExtensionTelemetryApiBrowserTest,
+                       GetOemDataWithSerialNumberPermission_Success) {
+  CreateExtensionAndRunServiceWorker(R"(
+    chrome.test.runTests([
+      async function getOemData() {
+        const result = await chrome.os.telemetry.getOemData();
+        chrome.test.assertEq(
+          "oemdata: response from GetLog", result.oemData);
+        chrome.test.succeed();
+      }
+    ]);
+  )");
+}
+
+IN_PROC_BROWSER_TEST_F(TelemetryExtensionTelemetryApiBrowserTest,
+                       GetVpdInfoError) {
+  CreateExtensionAndRunServiceWorker(R"(
+    chrome.test.runTests([
+      async function getVpdInfo() {
+        await chrome.test.assertPromiseRejects(
+            chrome.os.telemetry.getVpdInfo(),
+            'Error: API internal error'
+        );
+        chrome.test.succeed();
+      }
+    ]);
+  )");
+}
+
+IN_PROC_BROWSER_TEST_F(TelemetryExtensionTelemetryApiBrowserTest,
+                       GetVpdInfoWithSerialNumberPermission) {
+  // Configure fake cros_healthd response.
+  {
+    auto telemetry_info = cros_healthd::mojom::TelemetryInfo::New();
+
+    {
+      auto os_version = cros_healthd::mojom::OsVersion::New();
+
+      auto system_info = cros_healthd::mojom::SystemInfo::New();
+      system_info->first_power_date = "2021-50";
+      system_info->product_model_name = "COOL-LAPTOP-CHROME";
+      system_info->product_serial_number = "5CD9132880";
+      system_info->product_sku_number = "sku15";
+      system_info->os_version = std::move(os_version);
+
+      telemetry_info->system_result =
+          cros_healthd::mojom::SystemResult::NewSystemInfo(
+              std::move(system_info));
+    }
+
+    ASSERT_TRUE(cros_healthd::FakeCrosHealthd::Get());
+
+    cros_healthd::FakeCrosHealthd::Get()
+        ->SetProbeTelemetryInfoResponseForTesting(telemetry_info);
+  }
+
+  CreateExtensionAndRunServiceWorker(R"(
+    chrome.test.runTests([
+      async function getVpdInfo() {
+        const result = await chrome.os.telemetry.getVpdInfo();
+        chrome.test.assertEq("2021-50", result.activateDate);
+        chrome.test.assertEq("COOL-LAPTOP-CHROME", result.modelName);
+        chrome.test.assertEq("5CD9132880", result.serialNumber);
+        chrome.test.assertEq("sku15", result.skuNumber);
         chrome.test.succeed();
       }
     ]);
@@ -429,65 +429,6 @@
 
 IN_PROC_BROWSER_TEST_F(
     TelemetryExtensionTelemetryApiWithoutSerialNumberBrowserTest,
-    GetVpdInfoWithoutSerialNumberPermission) {
-  // Configure fake cros_healthd response.
-  {
-    auto telemetry_info = cros_healthd::mojom::TelemetryInfo::New();
-
-    {
-      auto os_version = cros_healthd::mojom::OsVersion::New();
-
-      auto system_info = cros_healthd::mojom::SystemInfo::New();
-      system_info->first_power_date = "2021-50";
-      system_info->product_model_name = "COOL-LAPTOP-CHROME";
-      system_info->product_serial_number = "5CD9132880";
-      system_info->product_sku_number = "sku15";
-      system_info->os_version = std::move(os_version);
-
-      telemetry_info->system_result =
-          cros_healthd::mojom::SystemResult::NewSystemInfo(
-              std::move(system_info));
-    }
-
-    ASSERT_TRUE(cros_healthd::FakeCrosHealthd::Get());
-
-    cros_healthd::FakeCrosHealthd::Get()
-        ->SetProbeTelemetryInfoResponseForTesting(telemetry_info);
-  }
-
-  CreateExtensionAndRunServiceWorker(R"(
-    chrome.test.runTests([
-      async function getVpdInfo() {
-        const result = await chrome.os.telemetry.getVpdInfo();
-        chrome.test.assertEq("2021-50", result.activateDate);
-        chrome.test.assertEq("COOL-LAPTOP-CHROME", result.modelName);
-        chrome.test.assertEq(null, result.serialNumber);
-        chrome.test.assertEq("sku15", result.skuNumber);
-        chrome.test.succeed();
-      }
-    ]);
-  )");
-}
-
-IN_PROC_BROWSER_TEST_F(
-    TelemetryExtensionTelemetryApiWithoutSerialNumberBrowserTest,
-    GetOemDataWithoutSerialNumberPermission) {
-  CreateExtensionAndRunServiceWorker(R"(
-    chrome.test.runTests([
-      async function getOemData() {
-        await chrome.test.assertPromiseRejects(
-            chrome.os.telemetry.getOemData(),
-            'Error: Unauthorized access to chrome.os.telemetry.getOemData. ' +
-            'Extension doesn\'t have the permission.'
-        );
-        chrome.test.succeed();
-      }
-    ]);
-  )");
-}
-
-IN_PROC_BROWSER_TEST_F(
-    TelemetryExtensionTelemetryApiWithoutSerialNumberBrowserTest,
     GetBatteryInfoWithoutSerialNumberPermission) {
   // Configure fake cros_healthd response.
   {
@@ -549,4 +490,63 @@
   )");
 }
 
+IN_PROC_BROWSER_TEST_F(
+    TelemetryExtensionTelemetryApiWithoutSerialNumberBrowserTest,
+    GetOemDataWithoutSerialNumberPermission) {
+  CreateExtensionAndRunServiceWorker(R"(
+    chrome.test.runTests([
+      async function getOemData() {
+        await chrome.test.assertPromiseRejects(
+            chrome.os.telemetry.getOemData(),
+            'Error: Unauthorized access to chrome.os.telemetry.getOemData. ' +
+            'Extension doesn\'t have the permission.'
+        );
+        chrome.test.succeed();
+      }
+    ]);
+  )");
+}
+
+IN_PROC_BROWSER_TEST_F(
+    TelemetryExtensionTelemetryApiWithoutSerialNumberBrowserTest,
+    GetVpdInfoWithoutSerialNumberPermission) {
+  // Configure fake cros_healthd response.
+  {
+    auto telemetry_info = cros_healthd::mojom::TelemetryInfo::New();
+
+    {
+      auto os_version = cros_healthd::mojom::OsVersion::New();
+
+      auto system_info = cros_healthd::mojom::SystemInfo::New();
+      system_info->first_power_date = "2021-50";
+      system_info->product_model_name = "COOL-LAPTOP-CHROME";
+      system_info->product_serial_number = "5CD9132880";
+      system_info->product_sku_number = "sku15";
+      system_info->os_version = std::move(os_version);
+
+      telemetry_info->system_result =
+          cros_healthd::mojom::SystemResult::NewSystemInfo(
+              std::move(system_info));
+    }
+
+    ASSERT_TRUE(cros_healthd::FakeCrosHealthd::Get());
+
+    cros_healthd::FakeCrosHealthd::Get()
+        ->SetProbeTelemetryInfoResponseForTesting(telemetry_info);
+  }
+
+  CreateExtensionAndRunServiceWorker(R"(
+    chrome.test.runTests([
+      async function getVpdInfo() {
+        const result = await chrome.os.telemetry.getVpdInfo();
+        chrome.test.assertEq("2021-50", result.activateDate);
+        chrome.test.assertEq("COOL-LAPTOP-CHROME", result.modelName);
+        chrome.test.assertEq(null, result.serialNumber);
+        chrome.test.assertEq("sku15", result.skuNumber);
+        chrome.test.succeed();
+      }
+    ]);
+  )");
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/feature_guide/notifications/internal/feature_notification_guide_service_impl_unittest.cc b/chrome/browser/feature_guide/notifications/internal/feature_notification_guide_service_impl_unittest.cc
index 23102f9..fcdd9cc 100644
--- a/chrome/browser/feature_guide/notifications/internal/feature_notification_guide_service_impl_unittest.cc
+++ b/chrome/browser/feature_guide/notifications/internal/feature_notification_guide_service_impl_unittest.cc
@@ -110,13 +110,13 @@
         OPTIMIZATION_TARGET_SEGMENTATION_CHROME_LOW_USER_ENGAGEMENT;
     return result;
   }
-  int RegisterOnDemandSegmentSelectionCallback(
+  segmentation_platform::CallbackId RegisterOnDemandSegmentSelectionCallback(
       const std::string& segmentation_key,
       const OnDemandSegmentSelectionCallback& callback) override {
-    return 0;
+    return segmentation_platform::CallbackId::FromUnsafeValue(0);
   }
   void UnregisterOnDemandSegmentSelectionCallback(
-      int callback_id,
+      segmentation_platform::CallbackId callback_id,
       const std::string& segmentation_key) override {}
   void OnTrigger(
       segmentation_platform::TriggerType trigger,
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index a659a06..3bc752f 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -3146,11 +3146,6 @@
     "expiry_milestone": 102
   },
   {
-    "name": "extended-open-vpn-settings",
-    "owners": [ "gflegar@google.com" ],
-    "expiry_milestone": 110
-  },
-  {
     "name": "extension-content-verification",
     "owners": [ "//extensions/OWNERS" ],
     "expiry_milestone": 86
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index fd1b597..4d7b3cb2 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -4913,11 +4913,6 @@
     "Enable experimental or in-progress Switch Access features for improved "
     "text input";
 
-const char kExtendedOpenVpnSettingsName[] = "Enable extended OpenVPN settings";
-const char kExtendedOpenVpnSettingsDescription[] =
-    "Enable displaying additional configuration properties of already "
-    "configured OpenVPN networks.";
-
 const char kMagnifierContinuousMouseFollowingModeSettingName[] =
     "Enable ability to choose continuous mouse following mode in Magnifier "
     "settings";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 08565d2..c2929c5 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -2802,9 +2802,6 @@
 extern const char kExperimentalAccessibilitySwitchAccessTextName[];
 extern const char kExperimentalAccessibilitySwitchAccessTextDescription[];
 
-extern const char kExtendedOpenVpnSettingsName[];
-extern const char kExtendedOpenVpnSettingsDescription[];
-
 extern const char kMagnifierContinuousMouseFollowingModeSettingName[];
 extern const char kMagnifierContinuousMouseFollowingModeSettingDescription[];
 
diff --git a/chrome/browser/hid/hid_chooser_context.cc b/chrome/browser/hid/hid_chooser_context.cc
index 450ac05..b8ceb6b 100644
--- a/chrome/browser/hid/hid_chooser_context.cc
+++ b/chrome/browser/hid/hid_chooser_context.cc
@@ -6,7 +6,6 @@
 
 #include <utility>
 
-#include "base/command_line.h"
 #include "base/containers/contains.h"
 #include "base/observer_list.h"
 #include "base/strings/string_number_conversions.h"
@@ -24,8 +23,6 @@
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "content/public/browser/device_service.h"
 #include "extensions/buildflags/buildflags.h"
-#include "services/device/public/cpp/hid/hid_blocklist.h"
-#include "services/device/public/cpp/hid/hid_switches.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
@@ -453,18 +450,12 @@
 bool HidChooserContext::HasDevicePermission(
     const url::Origin& origin,
     const device::mojom::HidDeviceInfo& device) {
-  const bool has_fido_collection =
-      base::Contains(device.collections, device::mojom::kPageFido,
-                     [](const auto& c) { return c->usage->usage_page; });
-  if (has_fido_collection) {
-    if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-            switches::kDisableHidBlocklist) &&
-        !IsFidoAllowedForOrigin(origin)) {
-      // Exclude `device` if it is FIDO and FIDO is not allowed for `origin`.
+  if (device.is_excluded_by_blocklist) {
+    const bool has_fido_collection =
+        base::Contains(device.collections, device::mojom::kPageFido,
+                       [](const auto& c) { return c->usage->usage_page; });
+    if (!has_fido_collection || !IsFidoAllowedForOrigin(origin))
       return false;
-    }
-  } else if (device::HidBlocklist::IsDeviceExcluded(device)) {
-    return false;
   }
 
   if (CanApplyPolicy() &&
diff --git a/chrome/browser/hid/hid_chooser_context_unittest.cc b/chrome/browser/hid/hid_chooser_context_unittest.cc
index 281f80f3..f27d4fd7 100644
--- a/chrome/browser/hid/hid_chooser_context_unittest.cc
+++ b/chrome/browser/hid/hid_chooser_context_unittest.cc
@@ -148,6 +148,9 @@
         device::HidBlocklist::Get().GetProtectedReportIds(
             device::HidBlocklist::kReportTypeFeature, kTestVendorId,
             kTestProductId, device->collections);
+    device->is_excluded_by_blocklist =
+        device::HidBlocklist::Get().IsVendorProductBlocked(kTestVendorId,
+                                                           kTestProductId);
     return device;
   }
 
@@ -644,8 +647,8 @@
     {nullptr, true},          {"", true},
     {"1234:abcd::::", false}, {"1234:0001::::", true},
     {"1234:::::", false},     {"2468:::::", true},
-    {"::0001:0005::", false}, {"::0001:0006::", true},
-    {"::0001:::", false},     {"::ff00:::", true},
+    {"::0001:0005::", true},  {"::0001:0006::", true},
+    {"::0001:::", true},      {"::ff00:::", true},
 };
 
 class HidChooserContextBlocklistTest
@@ -1144,38 +1147,18 @@
   EXPECT_EQ(0u, context()->GetAllGrantedObjects().size());
 }
 
-TEST_F(HidChooserContextTest, FidoAllowlistOverridesBlocklistFidoRule) {
-  const auto kFidoAllowedOrigin = url::Origin::Create(
-      GURL("chrome-extension://ckcendljdlmgnhghiaomidhiiclmapok"));
-  const auto kOtherOrigin = url::Origin::Create(GURL("https://other.origin"));
-
-  // Connect a FIDO device. It should be blocked by the blocklist because it
-  // has a top-level collection with a usage from the FIDO usage page.
-  auto device = ConnectFidoDeviceBlocking();
-  EXPECT_FALSE(context()->HasDevicePermission(kFidoAllowedOrigin, *device));
-  EXPECT_FALSE(context()->HasDevicePermission(kOtherOrigin, *device));
-
-  // Granting permission to the privileged origin succeeds.
-  GrantDevicePermissionBlocking(kFidoAllowedOrigin, *device);
-  EXPECT_TRUE(context()->HasDevicePermission(kFidoAllowedOrigin, *device));
-
-  // Granting permission to the non-privileged origin fails.
-  GrantDevicePermissionBlocking(kOtherOrigin, *device);
-  EXPECT_FALSE(context()->HasDevicePermission(kOtherOrigin, *device));
-}
-
 TEST_F(HidChooserContextTest, FidoAllowlistOverridesBlocklistDeviceIdRule) {
   const auto kFidoAllowedOrigin = url::Origin::Create(
       GURL("chrome-extension://ckcendljdlmgnhghiaomidhiiclmapok"));
   const auto kOtherOrigin = url::Origin::Create(GURL("https://other.origin"));
 
-  // Connect a FIDO device.
-  auto device = ConnectFidoDeviceBlocking();
-
   // Configure the blocklist to deny access to devices with kTestVendorId and
   // kTestProductId.
   SetDynamicBlocklist("1234:abcd::::");
 
+  // Connect a FIDO device.
+  auto device = ConnectFidoDeviceBlocking();
+
   // Check that the FIDO device is still blocked. Now it is blocked both for
   // being FIDO and also for matching the device ID rule.
   EXPECT_FALSE(context()->HasDevicePermission(kFidoAllowedOrigin, *device));
@@ -1195,6 +1178,10 @@
       GURL("chrome-extension://ckcendljdlmgnhghiaomidhiiclmapok"));
   const auto kOtherOrigin = url::Origin::Create(GURL("https://other.origin"));
 
+  // Configure the blocklist to deny access to devices with kTestVendorId and
+  // kTestProductId.
+  SetDynamicBlocklist("1234:abcd::::");
+
   SetAllowDevicesWithHidUsagesForUrlsPolicy(R"(
       [
         {
diff --git a/chrome/browser/password_manager/android/password_store_android_backend.cc b/chrome/browser/password_manager/android/password_store_android_backend.cc
index dd4581a..c091cf5d 100644
--- a/chrome/browser/password_manager/android/password_store_android_backend.cc
+++ b/chrome/browser/password_manager/android/password_store_android_backend.cc
@@ -208,10 +208,10 @@
       "PwdMgr.BackendError.origin");
 
   if (signon_realm.has_value()) {
-    signon_realm_key.Set(signon_realm->substr(1020));
+    signon_realm_key.Set(signon_realm->substr(0, 1020));
   }
   if (origin.has_value()) {
-    origin_key.Set(origin->substr(1020));
+    origin_key.Set(origin->substr(0, 1020));
   }
 
   base::debug::DumpWithoutCrashing();
diff --git a/chrome/browser/permissions/permissions_security_model_interactive_uitest.cc b/chrome/browser/permissions/permissions_security_model_interactive_uitest.cc
index 9670aa74..6f4c565 100644
--- a/chrome/browser/permissions/permissions_security_model_interactive_uitest.cc
+++ b/chrome/browser/permissions/permissions_security_model_interactive_uitest.cc
@@ -22,6 +22,7 @@
 #include "components/embedder_support/switches.h"
 #include "components/permissions/permissions_client.h"
 #include "components/permissions/test/mock_permission_prompt_factory.h"
+#include "components/permissions/test/permission_request_observer.h"
 #include "content/public/browser/disallow_activation_reason.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/permission_controller.h"
@@ -957,9 +958,8 @@
   content::WebContents::FromRenderFrameHost(main_rfh)->Focus();
 
   ASSERT_TRUE(main_rfh);
-  EXPECT_EQ(
-      GURL(chrome::kChromeUINewTabURL),
-      embedder_contents->GetLastCommittedURL().DeprecatedGetOriginAsURL());
+  EXPECT_EQ(GURL(chrome::kChromeUINewTabURL),
+            embedder_contents->GetLastCommittedURL());
   EXPECT_EQ(GURL(chrome::kChromeUINewTabPageURL),
             main_rfh->GetLastCommittedOrigin().GetURL());
 
@@ -999,9 +999,8 @@
   content::WebContents::FromRenderFrameHost(main_rfh)->Focus();
 
   ASSERT_TRUE(main_rfh);
-  EXPECT_EQ(
-      GURL(chrome::kChromeUINewTabURL),
-      embedder_contents->GetLastCommittedURL().DeprecatedGetOriginAsURL());
+  EXPECT_EQ(GURL(chrome::kChromeUINewTabURL),
+            embedder_contents->GetLastCommittedURL());
   EXPECT_EQ(GURL(chrome::kChromeUINewTabPageURL),
             main_rfh->GetLastCommittedOrigin().GetURL());
 
@@ -1041,6 +1040,52 @@
             GURL("https://www.google.com"));
 }
 
+// Test that a permission prompt bubble will be shown on NTP despite the empty
+// address bar.
+IN_PROC_BROWSER_TEST_F(PermissionsSecurityModelInteractiveUITest,
+                       PermissionRequestOnNtpIsNotAutoIgnored) {
+  content::WebContents* embedder_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  ASSERT_TRUE(embedder_contents);
+
+  content::RenderFrameHost* main_rfh =
+      ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
+          browser(), GURL(chrome::kChromeUINewTabURL), 1);
+  content::WebContents::FromRenderFrameHost(main_rfh)->Focus();
+
+  ASSERT_TRUE(main_rfh);
+  EXPECT_EQ(GURL(chrome::kChromeUINewTabURL),
+            embedder_contents->GetLastCommittedURL());
+  EXPECT_EQ(GURL(chrome::kChromeUINewTabPageURL),
+            main_rfh->GetLastCommittedOrigin().GetURL());
+
+  EXPECT_FALSE(content::EvalJs(main_rfh, kCheckMicrophone,
+                               content::EXECUTE_SCRIPT_DEFAULT_OPTIONS, 1)
+                   .value.GetBool());
+
+  auto* manager =
+      permissions::PermissionRequestManager::FromWebContents(embedder_contents);
+  permissions::PermissionRequestObserver observer(embedder_contents);
+
+  EXPECT_FALSE(manager->IsRequestInProgress());
+
+  EXPECT_TRUE(content::ExecJs(
+      main_rfh, kRequestMicrophone,
+      content::EvalJsOptions::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES));
+
+  // Wait until a permission request is shown.
+  observer.Wait();
+
+  EXPECT_TRUE(manager->IsRequestInProgress());
+  EXPECT_TRUE(observer.request_shown());
+
+  manager->Accept();
+
+  EXPECT_TRUE(content::EvalJs(main_rfh, kCheckMicrophone,
+                              content::EXECUTE_SCRIPT_DEFAULT_OPTIONS, 1)
+                  .value.GetBool());
+}
+
 class PermissionsSecurityModelHTTPS
     : public PermissionsSecurityModelInteractiveUITest {
  public:
diff --git a/chrome/browser/push_messaging/push_messaging_browsertest.cc b/chrome/browser/push_messaging/push_messaging_browsertest.cc
index f127fb13..ad78fb5 100644
--- a/chrome/browser/push_messaging/push_messaging_browsertest.cc
+++ b/chrome/browser/push_messaging/push_messaging_browsertest.cc
@@ -61,7 +61,6 @@
 #include "components/site_engagement/content/site_engagement_score.h"
 #include "components/site_engagement/content/site_engagement_service.h"
 #include "content/public/browser/browsing_data_remover.h"
-#include "content/public/browser/notification_service.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
@@ -1279,9 +1278,7 @@
   message.sender_id = GetTestApplicationServerKey();
   message.raw_data = "testdata";
   message.decrypted = true;
-  push_service()->Observe(chrome::NOTIFICATION_APP_TERMINATING,
-                          content::NotificationService::AllSources(),
-                          content::NotificationService::NoDetails());
+  push_service()->OnAppTerminating();
   push_service()->OnMessage(app_identifier.app_id(), message);
   EXPECT_TRUE(IsRegisteredKeepAliveEqualTo(false));
 }
diff --git a/chrome/browser/push_messaging/push_messaging_service_impl.cc b/chrome/browser/push_messaging/push_messaging_service_impl.cc
index 1ebc0004..5fd72d4 100644
--- a/chrome/browser/push_messaging/push_messaging_service_impl.cc
+++ b/chrome/browser/push_messaging/push_messaging_service_impl.cc
@@ -22,10 +22,10 @@
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/gcm/gcm_profile_service_factory.h"
 #include "chrome/browser/gcm/instance_id/instance_id_profile_service_factory.h"
+#include "chrome/browser/lifetime/termination_notification.h"
 #include "chrome/browser/permissions/abusive_origin_permission_revocation_request.h"
 #include "chrome/browser/profiles/keep_alive/profile_keep_alive_types.h"
 #include "chrome/browser/profiles/keep_alive/scoped_profile_keep_alive.h"
@@ -53,7 +53,6 @@
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/devtools_background_services_context.h"
-#include "content/public/browser/notification_service.h"
 #include "content/public/browser/permission_controller.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
@@ -251,8 +250,9 @@
   DCHECK(profile);
   HostContentSettingsMapFactory::GetForProfile(profile_)->AddObserver(this);
 
-  registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
-                 content::NotificationService::AllSources());
+  on_app_terminating_subscription_ =
+      browser_shutdown::AddAppTerminatingCallback(base::BindOnce(
+          &PushMessagingServiceImpl::OnAppTerminating, base::Unretained(this)));
   refresh_observation_.Observe(&refresher_);
 }
 
@@ -1462,13 +1462,7 @@
   HostContentSettingsMapFactory::GetForProfile(profile_)->RemoveObserver(this);
 }
 
-// content::NotificationObserver methods ---------------------------------------
-
-void PushMessagingServiceImpl::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  DCHECK_EQ(chrome::NOTIFICATION_APP_TERMINATING, type);
+void PushMessagingServiceImpl::OnAppTerminating() {
   shutdown_started_ = true;
 #if BUILDFLAG(ENABLE_BACKGROUND_MODE)
   in_flight_keep_alive_.reset();
diff --git a/chrome/browser/push_messaging/push_messaging_service_impl.h b/chrome/browser/push_messaging/push_messaging_service_impl.h
index 71cad8a..d92582ce 100644
--- a/chrome/browser/push_messaging/push_messaging_service_impl.h
+++ b/chrome/browser/push_messaging/push_messaging_service_impl.h
@@ -13,6 +13,7 @@
 
 #include "base/callback.h"
 #include "base/callback_helpers.h"
+#include "base/callback_list.h"
 #include "base/containers/flat_map.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/raw_ptr.h"
@@ -30,8 +31,6 @@
 #include "components/gcm_driver/gcm_client.h"
 #include "components/gcm_driver/instance_id/instance_id.h"
 #include "components/keyed_service/core/keyed_service.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/push_messaging_service.h"
 #include "content/public/common/child_process_host.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -82,7 +81,6 @@
                                  public gcm::GCMAppHandler,
                                  public content_settings::Observer,
                                  public KeyedService,
-                                 public content::NotificationObserver,
                                  public PushMessagingRefresher::Observer {
  public:
   // If any Service Workers are using push, starts GCM and adds an app handler.
@@ -166,11 +164,6 @@
   // KeyedService implementation.
   void Shutdown() override;
 
-  // content::NotificationObserver implementation
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
-
   // WARNING: Only call this function if features::kPushSubscriptionChangeEvent
   // is enabled, will be later used by the Push Service to trigger subscription
   // refreshes
@@ -198,6 +191,7 @@
  private:
   friend class PushMessagingBrowserTestBase;
   friend class PushMessagingServiceTest;
+  FRIEND_TEST_ALL_PREFIXES(PushMessagingBrowserTest, PushEventOnShutdown);
   FRIEND_TEST_ALL_PREFIXES(PushMessagingServiceTest, NormalizeSenderInfo);
   FRIEND_TEST_ALL_PREFIXES(PushMessagingServiceTest, PayloadEncryptionTest);
   FRIEND_TEST_ALL_PREFIXES(PushMessagingServiceTest,
@@ -418,6 +412,8 @@
     message_dispatched_callback_for_testing_ = callback;
   }
 
+  void OnAppTerminating();
+
   raw_ptr<Profile> profile_;
   std::unique_ptr<AbusiveOriginPermissionRevocationRequest>
       abusive_origin_revocation_request_;
@@ -463,7 +459,7 @@
   std::unique_ptr<ScopedProfileKeepAlive> in_flight_profile_keep_alive_;
 #endif
 
-  content::NotificationRegistrar registrar_;
+  base::CallbackListSubscription on_app_terminating_subscription_;
 
   // True when shutdown has started. Do not allow processing of incoming
   // messages when this is true.
diff --git a/chrome/browser/resources/app_service_internals/BUILD.gn b/chrome/browser/resources/app_service_internals/BUILD.gn
index b2e43cb..1693618a 100644
--- a/chrome/browser/resources/app_service_internals/BUILD.gn
+++ b/chrome/browser/resources/app_service_internals/BUILD.gn
@@ -3,14 +3,19 @@
 # found in the LICENSE file.
 
 import("//tools/grit/grit_rule.gni")
-import("//tools/polymer/html_to_js.gni")
+import("//tools/polymer/html_to_wrapper.gni")
 import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 
 resources_grd_file = "$target_gen_dir/resources.grd"
 
-html_to_js("components") {
-  js_files = [ "app_service_internals.ts" ]
+html_to_wrapper("html_wrapper_files") {
+  in_files = [ "app_service_internals.html" ]
+}
+
+copy("copy_src") {
+  sources = [ "app_service_internals.ts" ]
+  outputs = [ "$target_gen_dir/{{source_file_part}}" ]
 }
 
 copy("copy_mojo") {
@@ -24,18 +29,20 @@
 }
 
 ts_library("build_ts") {
-  root_dir = "$target_gen_dir"
+  root_dir = target_gen_dir
   out_dir = "$target_gen_dir/tsc"
   tsconfig_base = "tsconfig_base.json"
   in_files = [
     "app_service_internals.ts",
+    "app_service_internals.html.ts",
     "app_service_internals.mojom-webui.js",
   ]
 
   deps = [ "//third_party/polymer/v3_0:library" ]
   extra_deps = [
-    ":components",
     ":copy_mojo",
+    ":copy_src",
+    ":html_wrapper_files",
   ]
 }
 
diff --git a/chrome/browser/resources/app_service_internals/app_service_internals.ts b/chrome/browser/resources/app_service_internals/app_service_internals.ts
index 070d580..6562e8e 100644
--- a/chrome/browser/resources/app_service_internals/app_service_internals.ts
+++ b/chrome/browser/resources/app_service_internals/app_service_internals.ts
@@ -2,8 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
+import {getTemplate} from './app_service_internals.html.js';
 import {AppInfo, AppServiceInternalsPageHandler, PreferredAppInfo} from './app_service_internals.mojom-webui.js';
 
 export class AppServiceInternalsElement extends PolymerElement {
@@ -12,7 +13,7 @@
   }
 
   static get template() {
-    return html`{__html_template__}`;
+    return getTemplate();
   }
 
   static get properties() {
diff --git a/chrome/browser/resources/app_settings/BUILD.gn b/chrome/browser/resources/app_settings/BUILD.gn
index 34c01bf..669b3815 100644
--- a/chrome/browser/resources/app_settings/BUILD.gn
+++ b/chrome/browser/resources/app_settings/BUILD.gn
@@ -4,37 +4,25 @@
 
 import("//chrome/common/features.gni")
 import("//tools/grit/grit_rule.gni")
-import("//tools/grit/preprocess_if_expr.gni")
-import("//tools/polymer/html_to_js.gni")
+import("//tools/polymer/html_to_wrapper.gni")
 import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
+import("./app_settings.gni")
 
 assert(is_win || is_mac || is_linux || is_fuchsia)
-preprocess_folder = "preprocessed"
+
 resources_grd_file = "$target_gen_dir/resources.grd"
 
-web_component_files = [ "app.ts" ]
-
-html_to_js("web_components") {
-  js_files = web_component_files
-}
-
-preprocess_if_expr("preprocess_web_components") {
-  deps = [ ":web_components" ]
-  in_folder = target_gen_dir
-  out_folder = "$target_gen_dir/$preprocess_folder"
-  in_files = web_component_files
+html_to_wrapper("html_wrapper_files") {
+  in_files = html_files
 }
 
 ts_library("build_ts") {
-  root_dir = "$target_gen_dir/$preprocess_folder"
+  root_dir = target_gen_dir
   out_dir = "$target_gen_dir/tsc"
   composite = true
   tsconfig_base = "tsconfig_base.json"
-  in_files = web_component_files + [
-               "app_management.mojom-webui.js",
-               "web_app_settings.ts",
-             ]
+  in_files = ts_files + html_wrapper_files + [ "app_management.mojom-webui.js" ]
   deps = [
     "//third_party/polymer/v3_0:library",
     "//ui/webui/resources:library",
@@ -42,20 +30,20 @@
   ]
   extra_deps = [
     ":copy_mojo",
-    ":copy_ts",
-    ":preprocess_web_components",
+    ":copy_src",
+    ":html_wrapper_files",
   ]
 }
 
-copy("copy_ts") {
-  sources = [ "web_app_settings.ts" ]
-  outputs = [ "$target_gen_dir/$preprocess_folder/{{source_file_part}}" ]
+copy("copy_src") {
+  sources = ts_files
+  outputs = [ "$target_gen_dir/{{source_file_part}}" ]
 }
 
 copy("copy_mojo") {
   deps = [ "//ui/webui/resources/cr_components/app_management:mojo_bindings_js__generator" ]
   sources = [ "$root_gen_dir/mojom-webui/ui/webui/resources/cr_components/app_management/app_management.mojom-webui.js" ]
-  outputs = [ "$target_gen_dir/$preprocess_folder/{{source_file_part}}" ]
+  outputs = [ "$target_gen_dir/{{source_file_part}}" ]
 }
 
 generate_grd("build_grd") {
diff --git a/chrome/browser/resources/app_settings/app.ts b/chrome/browser/resources/app_settings/app.ts
index fd797da1..6a8f91c 100644
--- a/chrome/browser/resources/app_settings/app.ts
+++ b/chrome/browser/resources/app_settings/app.ts
@@ -18,7 +18,9 @@
 import {BrowserProxy} from 'chrome://resources/cr_components/app_management/browser_proxy.js';
 import {getAppIcon} from 'chrome://resources/cr_components/app_management/util.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
-import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {getTemplate} from './app.html.js';
 
 // TODO(crbug.com/1294060): Investigate end-to-end WebAppSettings tests
 export class WebAppSettingsAppElement extends PolymerElement {
@@ -27,7 +29,7 @@
   }
 
   static get template() {
-    return html`{__html_template__}`;
+    return getTemplate();
   }
 
   static get properties() {
diff --git a/chrome/browser/resources/app_settings/app_settings.gni b/chrome/browser/resources/app_settings/app_settings.gni
new file mode 100644
index 0000000..e49a08d1
--- /dev/null
+++ b/chrome/browser/resources/app_settings/app_settings.gni
@@ -0,0 +1,22 @@
+# 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.
+
+_non_web_component_files = [ "web_app_settings.ts" ]
+
+# Files holding a Polymer element definition and have an equivalent .html file.
+_web_component_files = [ "app.ts" ]
+
+# Files that are passed as input to html_to_wrapper().
+html_files = []
+foreach(f, _web_component_files) {
+  html_files += [ string_replace(f, ".ts", ".html") ]
+}
+
+# Files that are generated by html_to_wrapper().
+html_wrapper_files = []
+foreach(f, html_files) {
+  html_wrapper_files += [ f + ".ts" ]
+}
+
+ts_files = _non_web_component_files + _web_component_files
diff --git a/chrome/browser/resources/browsing_topics/BUILD.gn b/chrome/browser/resources/browsing_topics/BUILD.gn
index 980bacf..e0e01c8 100644
--- a/chrome/browser/resources/browsing_topics/BUILD.gn
+++ b/chrome/browser/resources/browsing_topics/BUILD.gn
@@ -3,7 +3,6 @@
 # found in the LICENSE file.
 
 import("//tools/grit/grit_rule.gni")
-import("//tools/polymer/html_to_js.gni")
 import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_related_info.js b/chrome/browser/resources/chromeos/assistant_optin/assistant_related_info.js
index 5a075e1..99ea8ac 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_related_info.js
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_related_info.js
@@ -259,17 +259,22 @@
   reloadContent(data) {
     this.skipActivityControl_ = !data['activityControlNeeded'];
     this.childName_ = data['childName'];
-    const url = this.isDarkModeActive_ ? 'info_outline_gm_grey500_24dp.png' :
-                                         'info_outline_gm_grey600_24dp.png';
-    this.$.zippy.setAttribute(
-        'icon-src',
-        'data:text/html;charset=utf-8,' +
-            encodeURIComponent(this.$.zippy.getWrappedIcon(
-                'https://www.gstatic.com/images/icons/material/system/2x/' +
-                    url,
-                this.i18n('assistantScreenContextTitle'),
-                getComputedStyle(document.body)
-                    .getPropertyValue('--cros-bg-color'))));
+    if (!data['useNativeIcons']) {
+      const url = this.isDarkModeActive_ ? 'info_outline_gm_grey500_24dp.png' :
+                                           'info_outline_gm_grey600_24dp.png';
+      this.$.zippy.setAttribute(
+          'icon-src',
+          'data:text/html;charset=utf-8,' +
+              encodeURIComponent(this.$.zippy.getWrappedIcon(
+                  'https://www.gstatic.com/images/icons/material/system/2x/' +
+                      url,
+                  this.i18n('assistantScreenContextTitle'),
+                  getComputedStyle(document.body)
+                      .getPropertyValue('--cros-bg-color'))));
+      this.$.zippy.nativeIconType = AssistantNativeIconType.NONE;
+    } else {
+      this.$.zippy.nativeIconType = AssistantNativeIconType.INFO;
+    }
     this.equalWeightButtons_ = data['equalWeightButtons'];
 
     this.consentStringLoaded_ = true;
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.js b/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.js
index 3a171143..2911a8c3 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.js
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.js
@@ -367,21 +367,25 @@
       for (const j in zippy_data[i]) {
         const data = zippy_data[i][j];
         const zippy = document.createElement('setting-zippy');
-        // TODO(crbug.com/1313994) - Remove hard coded colors in OOBE
-        const background = this.isMinorMode_ ?
-            getComputedStyle(document.body)
-                .getPropertyValue('--cros-highlight-color' /* gblue50 */) :
-            getComputedStyle(document.body).getPropertyValue('--cros-bg-color');
-        zippy.setAttribute(
-            'icon-src',
-            'data:text/html;charset=utf-8,' +
-                encodeURIComponent(zippy.getWrappedIcon(
-                    data['iconUri'], data['title'], background)));
-        zippy.setAttribute('step', i);
-        if (this.isMinorMode_) {
-          zippy.setAttribute('hide-line', true);
-          zippy.setAttribute('card-style', true);
+        if (data['useNativeIcons']) {
+          zippy.nativeIconType = data['nativeIconType'];
+          zippy.setAttribute('nativeIconLabel', data['title']);
+        } else {
+          // TODO(crbug.com/1313994) - Remove hard coded colors in OOBE
+          const background = this.isMinorMode_ ?
+              getComputedStyle(document.body)
+                  .getPropertyValue('--cros-highlight-color' /* gblue50 */) :
+              getComputedStyle(document.body)
+                  .getPropertyValue('--cros-bg-color');
+          zippy.setAttribute(
+              'icon-src',
+              'data:text/html;charset=utf-8,' +
+                  encodeURIComponent(zippy.getWrappedIcon(
+                      data['iconUri'], data['title'], background)));
         }
+        zippy.setAttribute('step', i);
+        zippy.hideLine = this.isMinorMode_;
+        zippy.cardStyle = this.isMinorMode_;
 
         const title = document.createElement('div');
         title.slot = 'title';
diff --git a/chrome/browser/resources/chromeos/assistant_optin/setting_zippy.html b/chrome/browser/resources/chromeos/assistant_optin/setting_zippy.html
index d26b43c..935b11b 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/setting_zippy.html
+++ b/chrome/browser/resources/chromeos/assistant_optin/setting_zippy.html
@@ -9,6 +9,7 @@
 <link rel="import" href="../components/common_styles/common_styles.html">
 
 <link rel="import" href="./assistant_common_styles.html">
+<link rel="import" href="./utils.html">
 
 <dom-module id="setting-zippy">
   <template>
@@ -30,6 +31,8 @@
       }
 
       .icon {
+        color: var(--cros-icon-color-secondary);
+        display: flex;
         min-width: 36px;
       }
 
@@ -70,9 +73,14 @@
         padding: 0;
       }
 
+      #container[cardStyle] .icon svg {
+        margin: auto;
+      }
+
       #container[cardStyle] .icon {
         background: var(--cros-highlight-color);
         border-radius: 50%;
+        color: var(--cros-icon-color-blue);
         height: 40px;
         margin-inline-end: 16px;
         margin-top: 4px;
@@ -86,7 +94,26 @@
     <div id="container" class="flex layout horizontal"
         cardStyle$="[[cardStyle]]">
       <div class="icon">
-        <webview class="icon-view" src="[[iconSrc]]" tabindex="-1"></webview>
+        <template is="dom-if"
+            if="[[shouldUseWebviewIcon_(iconSrc, nativeIconType)]]">
+          <webview class="icon-view" src="[[iconSrc]]" tabindex="-1">
+          </webview>
+        </template>
+        <template is="dom-if" if="[[shouldUseWAANativeIcon_(nativeIconType)]]">
+          <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+            <path fill-rule="evenodd" clip-rule="evenodd" d="M12 9V7h3.198A5.996 5.996 0 0 0 10 4c-3.315 0-6 2.685-6 6s2.685 6 6 6a6 6 0 0 0 5.917-4.999h2.02A8.007 8.007 0 0 1 9.993 18C5.576 18 2 14.416 2 10s3.576-8 7.992-8a7.992 7.992 0 0 1 6.009 2.712L16 3h2v6h-6Zm-1.5-3v4l2.5 2.5-1.5 1.5-3-3V6h2Z"fill="currentColor"></path>
+          </svg>
+        </template>
+        <template is="dom-if" if="[[shouldUseDANativeIcon_(nativeIconType)]]">
+          <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+            <path fill-rule="evenodd" clip-rule="evenodd" d="M18 15h1a1 1 0 1 1 0 2H1a1 1 0 1 1 0-2h1V4a1 1 0 0 1 1-1h14a.997.997 0 0 1 1 1v11Zm-2-3V5H4v7h12Zm-8 2v1h4v-1H8Z" fill="currentColor"></path>
+          </svg>
+        </template>
+        <template is="dom-if" if="[[shouldUseInfoNativeIcon_(nativeIconType)]]">
+          <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+            <path fill-rule="evenodd" clip-rule="evenodd" d="M9 14h2v-4H9v4Zm1-12c-4.416 0-8 3.584-8 8s3.584 8 8 8 8-3.584 8-8-3.584-8-8-8Zm0 14c-3.308 0-6-2.693-6-6 0-3.308 2.692-6 6-6 3.307 0 6 2.692 6 6 0 3.307-2.693 6-6 6ZM9 8h2V6H9v2Z" fill="currentColor"></path>
+          </svg>
+        </template>
       </div>
       <div>
         <div class="sub-title">
diff --git a/chrome/browser/resources/chromeos/assistant_optin/setting_zippy.js b/chrome/browser/resources/chromeos/assistant_optin/setting_zippy.js
index b1ec30c..c2a894a 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/setting_zippy.js
+++ b/chrome/browser/resources/chromeos/assistant_optin/setting_zippy.js
@@ -30,6 +30,16 @@
         type: Boolean,
         value: false,
       },
+
+      nativeIconType: {
+        type: Number,
+        value: AssistantNativeIconType.NONE,
+      },
+
+      nativeIconLabel: {
+        type: String,
+        value: null,
+      }
     };
   }
 
@@ -62,6 +72,22 @@
     <body><img id="icon" aria-label="` +
         imageLabel + `" src="` + iconUri + '"></body></html>';
   }
+
+  shouldUseWebviewIcon_(iconSrc, nativeIconType) {
+    return iconSrc !== null && nativeIconType === AssistantNativeIconType.NONE;
+  }
+
+  shouldUseWAANativeIcon_(nativeIconType) {
+    return nativeIconType === AssistantNativeIconType.WAA;
+  }
+
+  shouldUseDANativeIcon_(nativeIconType) {
+    return nativeIconType === AssistantNativeIconType.DA;
+  }
+
+  shouldUseInfoNativeIcon_(nativeIconType) {
+    return nativeIconType === AssistantNativeIconType.INFO;
+  }
 }
 
 customElements.define(SettingZippy.is, SettingZippy);
diff --git a/chrome/browser/resources/chromeos/assistant_optin/utils.js b/chrome/browser/resources/chromeos/assistant_optin/utils.js
index 35b0663..f1fb288 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/utils.js
+++ b/chrome/browser/resources/chromeos/assistant_optin/utils.js
@@ -70,3 +70,20 @@
     return copy;
   }
 }
+
+/**
+ * Possible native assistant icons
+ * Must be in sync with the corresponding c++ enum
+ * @enum {number}
+ */
+/* #export */ const AssistantNativeIconType = {
+  NONE: 0,
+
+  // Web & App Activity.
+  WAA: 1,
+
+  // Device Applications Information.
+  DA: 2,
+
+  INFO: 3,
+};
diff --git a/chrome/browser/resources/chromeos/launcher_internals/BUILD.gn b/chrome/browser/resources/chromeos/launcher_internals/BUILD.gn
index 69f11d9..bbc66cfc 100644
--- a/chrome/browser/resources/chromeos/launcher_internals/BUILD.gn
+++ b/chrome/browser/resources/chromeos/launcher_internals/BUILD.gn
@@ -3,23 +3,21 @@
 # found in the LICENSE file.
 
 import("//tools/grit/grit_rule.gni")
-import("//tools/polymer/html_to_js.gni")
+import("//tools/polymer/html_to_wrapper.gni")
 import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
+import("./launcher_internals.gni")
 
 assert(is_chromeos, "Launcher internals is Chrome OS only.")
 
 resources_grd_file = "$target_gen_dir/resources.grd"
 
-html_to_js("web_components") {
-  js_files = [
-    "launcher_internals.ts",
-    "results_table.ts",
-  ]
+html_to_wrapper("html_wrapper_files") {
+  in_files = html_files
 }
 
-copy("copy_browser_proxy") {
-  sources = [ "browser_proxy.ts" ]
+copy("copy_src") {
+  sources = ts_files
   outputs = [ "$target_gen_dir/{{source_file_part}}" ]
 }
 
@@ -33,19 +31,15 @@
 ts_library("build_ts") {
   deps = [ "//third_party/polymer/v3_0:library" ]
   extra_deps = [
-    ":copy_browser_proxy",
     ":copy_mojo",
-    ":web_components",
+    ":copy_src",
+    ":html_wrapper_files",
   ]
-  root_dir = "$target_gen_dir"
+  root_dir = target_gen_dir
   out_dir = "$target_gen_dir/tsc"
   tsconfig_base = "tsconfig_base.json"
-  in_files = [
-    "browser_proxy.ts",
-    "launcher_internals.mojom-webui.js",
-    "launcher_internals.ts",
-    "results_table.ts",
-  ]
+  in_files =
+      ts_files + html_wrapper_files + [ "launcher_internals.mojom-webui.js" ]
 }
 
 generate_grd("build_grd") {
diff --git a/chrome/browser/resources/chromeos/launcher_internals/launcher_internals.gni b/chrome/browser/resources/chromeos/launcher_internals/launcher_internals.gni
new file mode 100644
index 0000000..915be45
--- /dev/null
+++ b/chrome/browser/resources/chromeos/launcher_internals/launcher_internals.gni
@@ -0,0 +1,25 @@
+# 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.
+
+_non_web_component_files = [ "browser_proxy.ts" ]
+
+# Files holding a Polymer element definition and have an equivalent .html file.
+_web_component_files = [
+  "launcher_internals.ts",
+  "results_table.ts",
+]
+
+# Files that are passed as input to html_to_wrapper().
+html_files = []
+foreach(f, _web_component_files) {
+  html_files += [ string_replace(f, ".ts", ".html") ]
+}
+
+# Files that are generated by html_to_wrapper().
+html_wrapper_files = []
+foreach(f, html_files) {
+  html_wrapper_files += [ f + ".ts" ]
+}
+
+ts_files = _non_web_component_files + _web_component_files
diff --git a/chrome/browser/resources/chromeos/launcher_internals/launcher_internals.ts b/chrome/browser/resources/chromeos/launcher_internals/launcher_internals.ts
index 6d344665..d7505020 100644
--- a/chrome/browser/resources/chromeos/launcher_internals/launcher_internals.ts
+++ b/chrome/browser/resources/chromeos/launcher_internals/launcher_internals.ts
@@ -4,9 +4,10 @@
 
 import './results_table.js';
 
-import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {BrowserProxy} from './browser_proxy.js';
+import {getTemplate} from './launcher_internals.html.js';
 import {PageCallbackRouter, Result} from './launcher_internals.mojom-webui.js';
 import {LauncherResultsTableElement} from './results_table.js';
 
@@ -23,7 +24,7 @@
   }
 
   static get template() {
-    return html`{__html_template__}`;
+    return getTemplate();
   }
 
   static get properties() {
diff --git a/chrome/browser/resources/chromeos/launcher_internals/results_table.ts b/chrome/browser/resources/chromeos/launcher_internals/results_table.ts
index 6d08449..330d7a1 100644
--- a/chrome/browser/resources/chromeos/launcher_internals/results_table.ts
+++ b/chrome/browser/resources/chromeos/launcher_internals/results_table.ts
@@ -2,9 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {Result} from './launcher_internals.mojom-webui.js';
+import {getTemplate} from './results_table.html.js';
 
 export interface LauncherResultsTableElement {
   $: {
@@ -20,7 +21,7 @@
   }
 
   static get template() {
-    return html`{__html_template__}`;
+    return getTemplate();
   }
 
   // Current results keyed by result id.
diff --git a/chrome/browser/resources/chromeos/login/debug/debug.js b/chrome/browser/resources/chromeos/login/debug/debug.js
index 639d5a6..b69052b4 100644
--- a/chrome/browser/resources/chromeos/login/debug/debug.js
+++ b/chrome/browser/resources/chromeos/login/debug/debug.js
@@ -11,6 +11,7 @@
 // #import {Oobe} from '../cr_ui.m.js'
 // #import {$} from 'chrome://resources/js/util.m.js';
 // #import './debug_util.js';
+// #import {AssistantNativeIconType} from '../../assistant_optin/utils.m.js';
 
 // #import {MessageType, ProblemType} from 'chrome://resources/cr_components/chromeos/quick_unlock/setup_pin_keyboard.m.js';
 
@@ -22,10 +23,13 @@
   data['valuePropSkipButton'] = 'Value prop skip button';
   data['valuePropFooter'] = 'Value prop footer';
   data['equalWeightButtons'] = isMinor;
+  if (isMinor) {
+    data['childName'] = 'Child name';
+  }
   return data;
 };
 
-const createAssistantZippy = (type, isMinor) => {
+const createAssistantZippy = (type, isMinor, isNativeIcons) => {
   const zippy = {};
   zippy['isMinorMode'] = isMinor;
   zippy['title'] = 'Zippy ' + (isMinor ? 'minor ' : 'regular') + ' title';
@@ -33,28 +37,43 @@
   zippy['intro'] = 'Zippy intro';
   zippy['name'] = 'Zippy ' + type + ' name';
   zippy['description'] = 'Zippy ' + type + ' description';
+  if (isMinor) {
+    zippy['additionalInfo'] = 'Zippy additional info';
+  }
   zippy['popupLink'] = 'Zippy popup link';
   zippy['learnMoreDialogTitle'] = 'Zippy learn more dialog title';
   zippy['learnMoreDialogContent'] = 'Zippy learn more dialog content';
   zippy['learnMoreDialogButton'] = 'Zippy learn more dialog button';
-  if (type === 'WAA') {
-    if (isMinor) {
-      zippy['iconUri'] =
-          'https://www.gstatic.com/myactivity/icon/icon_fp_history_blue.svg';
+  zippy['useNativeIcons'] = !!isNativeIcons;
+
+  if (isNativeIcons) {
+    if (type === 'WAA') {
+      zippy['nativeIconType'] = AssistantNativeIconType.WAA;
+    } else if (type == 'DA') {
+      zippy['nativeIconType'] = AssistantNativeIconType.DA;
     } else {
-      zippy['iconUri'] =
-          'https://ssl.gstatic.com/identity/boq/consentflowtexts/icon_web_and_app_activity_grey600_72-fb2e66730dca510849d22bee9f0f29ba.png';
-    }
-  } else if (type === 'DA') {
-    if (isMinor) {
-      zippy['iconUri'] =
-          'https://www.gstatic.com/myactivity/icon/icon_fp_chromebook_blue.svg';
-    } else {
-      zippy['iconUri'] =
-          'https://ssl.gstatic.com/identity/boq/consentflowtexts/icon_device_information_vertical_grey600_72-be6f9c8691213019712cfa4106a509e0.png';
+      console.error('### Uknown zippy type ' + type);
     }
   } else {
-    console.error('### Uknown zippy type ' + type);
+    if (type === 'WAA') {
+      if (isMinor) {
+        zippy['iconUri'] =
+            'https://www.gstatic.com/myactivity/icon/icon_fp_history_blue.svg';
+      } else {
+        zippy['iconUri'] =
+            'https://ssl.gstatic.com/identity/boq/consentflowtexts/icon_web_and_app_activity_grey600_72-fb2e66730dca510849d22bee9f0f29ba.png';
+      }
+    } else if (type === 'DA') {
+      if (isMinor) {
+        zippy['iconUri'] =
+            'https://www.gstatic.com/myactivity/icon/icon_fp_chromebook_blue.svg';
+      } else {
+        zippy['iconUri'] =
+            'https://ssl.gstatic.com/identity/boq/consentflowtexts/icon_device_information_vertical_grey600_72-be6f9c8691213019712cfa4106a509e0.png';
+      }
+    } else {
+      console.error('### Uknown zippy type ' + type);
+    }
   }
   return zippy;
 };
@@ -1319,8 +1338,10 @@
                 createAssistantData(/*isMinor=*/ false));
 
             const zippies = [[]];
-            zippies[0].push(createAssistantZippy('WAA', /*isMinor=*/ false));
-            zippies[0].push(createAssistantZippy('DA', /*isMinor=*/ false));
+            zippies[0].push(createAssistantZippy(
+                'WAA', /*isMinor=*/ false, /*isNativeIcons=*/ false));
+            zippies[0].push(createAssistantZippy(
+                'DA', /*isMinor=*/ false, /*isNativeIcons=*/ false));
 
             (screen.$).card.addSettingZippy('settings', zippies);
           },
@@ -1341,16 +1362,74 @@
           },
         },
         {
-          id: 'related_info skip_activity_control=true',
+          id: 'value_prop_native_icons',
           trigger: (screen) => {
-            ((screen.$).card.$).relatedInfo.skipActivityControl_ = true;
+            (screen.$).card.onReload();
+            (screen.$).card.showStep('value-prop');
+            (screen.$).card.reloadContent(
+                createAssistantData(/*isMinor=*/ false));
+
+            const zippies = [[]];
+            zippies[0].push(createAssistantZippy(
+                'WAA', /*isMinor=*/ false, /*isNativeIcons=*/ true));
+            zippies[0].push(createAssistantZippy(
+                'DA', /*isMinor=*/ false, /*isNativeIcons=*/ true));
+
+            (screen.$).card.addSettingZippy('settings', zippies);
+          },
+        },
+        {
+          id: 'value_prop_minor_native_icons',
+          trigger: (screen) => {
+            (screen.$).card.onReload();
+            (screen.$).card.showStep('value-prop');
+            (screen.$).card.reloadContent(
+                createAssistantData(/*isMinor=*/ false));
+
+            const zippies = [[]];
+            zippies[0].push(createAssistantZippy(
+                'WAA', /*isMinor=*/ true, /*isNativeIcons=*/ true));
+            zippies[0].push(createAssistantZippy(
+                'DA', /*isMinor=*/ true, /*isNativeIcons=*/ true));
+
+            (screen.$).card.addSettingZippy('settings', zippies);
+          },
+        },
+        {
+          id: 'related_info',
+          trigger: (screen) => {
+            const data = createAssistantData(/*isMinor=*/ false);
+            data['activityControlNeeded'] = false;
+            (screen.$).card.reloadContent(data);
             (screen.$).card.showStep('related-info');
           },
         },
         {
-          id: 'related_info skip_activity_control=false',
+          id: 'related_info activityControlNeeded',
           trigger: (screen) => {
-            ((screen.$).card.$).relatedInfo.skipActivityControl_ = false;
+            const data = createAssistantData(/*isMinor=*/ false);
+            data['activityControlNeeded'] = true;
+            (screen.$).card.reloadContent(data);
+            (screen.$).card.showStep('related-info');
+          },
+        },
+        {
+          id: 'related_info native icons',
+          trigger: (screen) => {
+            const data = createAssistantData(/*isMinor=*/ false);
+            data['activityControlNeeded'] = false;
+            data['useNativeIcons'] = true;
+            (screen.$).card.reloadContent(data);
+            (screen.$).card.showStep('related-info');
+          },
+        },
+        {
+          id: 'related_info isMinor nativeIcons',
+          trigger: (screen) => {
+            const data = createAssistantData(/*isMinor=*/ true);
+            data['activityControlNeeded'] = false;
+            data['useNativeIcons'] = true;
+            (screen.$).card.reloadContent(data);
             (screen.$).card.showStep('related-info');
           },
         },
diff --git a/chrome/browser/resources/identity_internals/BUILD.gn b/chrome/browser/resources/identity_internals/BUILD.gn
index 60e52478..2958067 100644
--- a/chrome/browser/resources/identity_internals/BUILD.gn
+++ b/chrome/browser/resources/identity_internals/BUILD.gn
@@ -4,42 +4,31 @@
 
 import("//chrome/common/features.gni")
 import("//tools/grit/grit_rule.gni")
-import("//tools/grit/preprocess_if_expr.gni")
-import("//tools/polymer/html_to_js.gni")
+import("//tools/polymer/html_to_wrapper.gni")
 import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
+import("./identity_internals.gni")
 
 assert(!is_android)
 
-preprocess_folder = "preprocessed"
-html_to_js("web_components") {
-  js_files = [ "token_list_item.ts" ]
+html_to_wrapper("html_wrapper_files") {
+  in_files = html_files
+  template = "native"
 }
 
-preprocess_if_expr("preprocess_src") {
-  in_folder = "."
-  in_files = [ "identity_internals.ts" ]
-  out_folder = "$target_gen_dir/$preprocess_folder"
-}
-
-preprocess_if_expr("preprocess_gen") {
-  in_folder = target_gen_dir
-  in_files = [ "token_list_item.ts" ]
-  deps = [ ":web_components" ]
-  out_folder = "$target_gen_dir/$preprocess_folder"
+copy("copy_src") {
+  sources = ts_files
+  outputs = [ "$target_gen_dir/{{source_file_part}}" ]
 }
 
 ts_library("build_ts") {
-  root_dir = "$target_gen_dir/$preprocess_folder"
+  root_dir = target_gen_dir
   out_dir = "$target_gen_dir/tsc"
-  in_files = [
-    "identity_internals.ts",
-    "token_list_item.ts",
-  ]
+  in_files = ts_files + html_wrapper_files
   deps = [ "//ui/webui/resources:library" ]
   extra_deps = [
-    ":preprocess_gen",
-    ":preprocess_src",
+    ":copy_src",
+    ":html_wrapper_files",
   ]
   definitions = [ "//tools/typescript/definitions/chrome_send.d.ts" ]
 }
diff --git a/chrome/browser/resources/identity_internals/identity_internals.gni b/chrome/browser/resources/identity_internals/identity_internals.gni
new file mode 100644
index 0000000..d6fae7dc
--- /dev/null
+++ b/chrome/browser/resources/identity_internals/identity_internals.gni
@@ -0,0 +1,21 @@
+# 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.
+
+_non_web_component_files = [ "identity_internals.ts" ]
+
+_web_component_files = [ "token_list_item.ts" ]
+
+# Files that are passed as input to html_to_wrapper().
+html_files = []
+foreach(f, _web_component_files) {
+  html_files += [ string_replace(f, ".ts", ".html") ]
+}
+
+ts_files = _non_web_component_files + _web_component_files
+
+# Files that are generated by html_to_wrapper().
+html_wrapper_files = []
+foreach(f, html_files) {
+  html_wrapper_files += [ f + ".ts" ]
+}
diff --git a/chrome/browser/resources/identity_internals/token_list_item.ts b/chrome/browser/resources/identity_internals/token_list_item.ts
index f10fd74..37ceb66b 100644
--- a/chrome/browser/resources/identity_internals/token_list_item.ts
+++ b/chrome/browser/resources/identity_internals/token_list_item.ts
@@ -5,7 +5,8 @@
 import {assert} from 'chrome://resources/js/assert_ts.js';
 import {sendWithPromise} from 'chrome://resources/js/cr.m.js';
 import {CustomElement} from 'chrome://resources/js/custom_element.js';
-import {getTrustedHTML} from 'chrome://resources/js/static_types.js';
+
+import {getTemplate} from './token_list_item.html.js';
 
 declare global {
   interface HTMLElementEventMap {
@@ -25,7 +26,7 @@
 
 class TokenListItemElement extends CustomElement {
   static override get template() {
-    return getTrustedHTML`{__html_template__}`;
+    return getTemplate();
   }
 
   extensionId: string = '';
diff --git a/chrome/browser/resources/image_editor/BUILD.gn b/chrome/browser/resources/image_editor/BUILD.gn
index 91fb523..a2ddecc 100644
--- a/chrome/browser/resources/image_editor/BUILD.gn
+++ b/chrome/browser/resources/image_editor/BUILD.gn
@@ -7,7 +7,6 @@
 import("//third_party/closure_compiler/compile_js.gni")
 import("//tools/grit/grit_rule.gni")
 import("//tools/grit/preprocess_if_expr.gni")
-import("//tools/polymer/html_to_js.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 
 js_type_check("closure_compile") {
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_page.js b/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_page.js
index f04a0be..a536336 100644
--- a/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_page.js
+++ b/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_page.js
@@ -288,15 +288,6 @@
     },
 
     /** @private {boolean} */
-    isExtendedOpenVpnSettingsEnabled_: {
-      type: Boolean,
-      value() {
-        return loadTimeData.valueExists('extendedOpenVpnSettingsEnabled') &&
-            loadTimeData.getBoolean('extendedOpenVpnSettingsEnabled');
-      }
-    },
-
-    /** @private {boolean} */
     isTrafficCountersEnabled_: {
       type: Boolean,
       value() {
@@ -2272,13 +2263,10 @@
         switch (vpnType) {
           case chromeos.networkConfig.mojom.VpnType.kOpenVPN:
             if (this.isManagedByPolicy_()) {
-              // TODO(b/215180522): Clean up the guard once this is launched.
-              if (this.isExtendedOpenVpnSettingsEnabled_) {
-                fields.push(
-                    'vpn.openVpn.auth', 'vpn.openVpn.cipher',
-                    'vpn.openVpn.compressionAlgorithm',
-                    'vpn.openVpn.tlsAuthContents', 'vpn.openVpn.keyDirection');
-              }
+              fields.push(
+                  'vpn.openVpn.auth', 'vpn.openVpn.cipher',
+                  'vpn.openVpn.compressionAlgorithm',
+                  'vpn.openVpn.tlsAuthContents', 'vpn.openVpn.keyDirection');
             }
             break;
         }
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_completion_fragment.html b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_completion_fragment.html
index 4b557c6..4b69169 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_completion_fragment.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_completion_fragment.html
@@ -5,8 +5,11 @@
     min-height: calc(432px - var(--privacy-guide-footer-total-height));
   }
 
-  .headline-container {
+  .headline {
     outline: none;
+  }
+
+  .headline-container {
     padding: 36px 120px 16px 120px;
     row-gap: 8px;
   }
@@ -142,7 +145,7 @@
   }
 </style>
 <template is="dom-if" if="[[enablePrivacyGuide2_]]">
-  <div class="header-phase2" focus-element tabindex="-1">
+  <div class="header-phase2">
     <div id="picture-container">
       <div class="picture-shapes-container">
         <div id="circle" class="picture-shape"></div>
@@ -158,19 +161,23 @@
         <img alt="" src="./images/privacy_guide/completion_banner_v2.svg">
       </picture>
     </div>
-    <div class="headline">$i18n{privacyGuideCompletionCardHeader}</div>
+    <div class="headline" tabindex="-1">
+      $i18n{privacyGuideCompletionCardHeader}
+    </div>
     <div class="cr-secondary-text">[[subheader_]]</div>
   </div>
 </template>
 <template is="dom-if" if="[[!enablePrivacyGuide2_]]">
-  <div class="headline-container" focus-element tabindex="-1">
+  <div class="headline-container">
     <picture>
       <source
           srcset="./images/privacy_guide/completion_banner_dark.svg"
           media="(prefers-color-scheme: dark)">
       <img alt="" src="./images/privacy_guide/completion_banner.svg">
     </picture>
-    <div class="headline">$i18n{privacyGuideCompletionCardHeader}</div>
+    <div class="headline" tabindex="-1">
+      $i18n{privacyGuideCompletionCardHeader}
+    </div>
     <div class="cr-secondary-text">[[subheader_]]</div>
   </div>
 </template>
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_completion_fragment.ts b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_completion_fragment.ts
index a89dd83e..05e53d8b4 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_completion_fragment.ts
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_completion_fragment.ts
@@ -84,7 +84,7 @@
   }
 
   override focus() {
-    this.shadowRoot!.querySelector<HTMLElement>('[focus-element]')!.focus();
+    this.shadowRoot!.querySelector<HTMLElement>('.headline')!.focus();
   }
 
   private computeIsNoLinkLayout_() {
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_dialog.html b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_dialog.html
index 9facbb7..37c7d0ea 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_dialog.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_dialog.html
@@ -34,7 +34,8 @@
     min-width: 550px;
   }
 </style>
-<dialog id="dialog" on-cancel="onDialogCancel_" on-close="onDialogClose_">
+<dialog id="dialog" on-cancel="onDialogCancel_" on-close="onDialogClose_"
+    aria-label="$i18n{privacyGuideLabel}">
   <div class="cr-row first" id="headerLine" slot="title">
     <cr-icon-button class="icon-arrow-back" id="backToSettingsButton"
         on-click="onSettingsBackClick_"
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_dialog.ts b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_dialog.ts
index 77e38f6d..4c446af 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_dialog.ts
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_dialog.ts
@@ -49,11 +49,6 @@
 
     this.$.dialog.showModal();
 
-    // TODO(crbug/1215630): Instead of this focus code, it should be possible to
-    // use |autofocus| on the corresponding element in the cr-dialog to put the
-    // focus on it when the dialog is shown. For an unknown reason this does not
-    // work atm [1]. Use |autofocus| once this reason has been found and fixed.
-    // [1] https://crrev.com/c/3541986/comments/a3a6bdfb_3e1e0e29
     const elementToFocus =
         this.shadowRoot!.querySelector<HTMLElement>('#backToSettingsButton')!;
     afterNextRender(this, () => elementToFocus!.focus());
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_welcome_fragment.html b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_welcome_fragment.html
index 7f2d6a9..0bde901 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_welcome_fragment.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_welcome_fragment.html
@@ -5,8 +5,11 @@
     min-height: calc(432px - var(--privacy-guide-footer-total-height));
   }
 
-  .headline-container {
+  .headline {
     outline: none;
+  }
+
+  .headline-container {
     padding: 48px 116px var(--cr-section-padding) 116px;
     row-gap: 12px;
   }
@@ -29,14 +32,16 @@
     animation: fade-in var(--privacy-guide-animation-duration);
   }
 </style>
-<div class="headline-container" tabindex="-1">
+<div class="headline-container">
   <picture>
     <source
         srcset="./images/privacy_guide/welcome_banner_dark.svg"
         media="(prefers-color-scheme: dark)">
     <img alt="" src="./images/privacy_guide/welcome_banner.svg">
   </picture>
-  <div class="headline">$i18n{privacyGuideWelcomeCardHeader}</div>
+  <div class="headline" tabindex="-1">
+    $i18n{privacyGuideWelcomeCardHeader}
+  </div>
   <div class="cr-secondary-text">$i18n{privacyGuideWelcomeCardSubHeader}</div>
 </div>
 <div class="footer">
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_welcome_fragment.ts b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_welcome_fragment.ts
index cdd0587..c939758 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_welcome_fragment.ts
+++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_welcome_fragment.ts
@@ -30,7 +30,7 @@
   }
 
   override focus() {
-    this.shadowRoot!.querySelector<HTMLElement>('.headline-container')!.focus();
+    this.shadowRoot!.querySelector<HTMLElement>('.headline')!.focus();
   }
 
   private onStartButtonClick_(e: Event) {
diff --git a/chrome/browser/segmentation_platform/segmentation_platform_profile_observer_unittest.cc b/chrome/browser/segmentation_platform/segmentation_platform_profile_observer_unittest.cc
index 73fa5fe..6e6585f 100644
--- a/chrome/browser/segmentation_platform/segmentation_platform_profile_observer_unittest.cc
+++ b/chrome/browser/segmentation_platform/segmentation_platform_profile_observer_unittest.cc
@@ -33,12 +33,12 @@
   MOCK_METHOD(SegmentSelectionResult,
               GetCachedSegmentResult,
               (const std::string&));
-  MOCK_METHOD(int,
+  MOCK_METHOD(CallbackId,
               RegisterOnDemandSegmentSelectionCallback,
               (const std::string&, const OnDemandSegmentSelectionCallback&));
   MOCK_METHOD(void,
               UnregisterOnDemandSegmentSelectionCallback,
-              (int, const std::string&));
+              (CallbackId, const std::string&));
   MOCK_METHOD(void, OnTrigger, (TriggerType, const TriggerContext&));
   MOCK_METHOD(void, EnableMetrics, (bool));
   MOCK_METHOD(void, GetServiceStatus, ());
diff --git a/chrome/browser/shared_highlighting/shared_highlighting_browsertest.cc b/chrome/browser/shared_highlighting/shared_highlighting_browsertest.cc
index 0aaa29c..61d62868 100644
--- a/chrome/browser/shared_highlighting/shared_highlighting_browsertest.cc
+++ b/chrome/browser/shared_highlighting/shared_highlighting_browsertest.cc
@@ -13,13 +13,17 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/feature_engagement/public/feature_constants.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
+#include "content/public/test/fenced_frame_test_util.h"
 #include "net/http/http_status_code.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
+#include "third_party/blink/public/mojom/link_to_text/link_to_text.mojom-test-utils.h"
+#include "third_party/blink/public/mojom/link_to_text/link_to_text.mojom.h"
 #include "ui/base/clipboard/clipboard.h"
 
 namespace shared_highlighting {
@@ -295,4 +299,91 @@
   EXPECT_EQ("This is a test page", GetFirstHighlightedText());
 }
 
+class MockTextFragmentReceiver
+    : public blink::mojom::TextFragmentReceiverInterceptorForTesting {
+ public:
+  MockTextFragmentReceiver() = default;
+  ~MockTextFragmentReceiver() override = default;
+
+  MockTextFragmentReceiver(const MockTextFragmentReceiver&) = delete;
+  MockTextFragmentReceiver& operator=(const MockTextFragmentReceiver&) = delete;
+
+  TextFragmentReceiver* GetForwardingInterface() override { return this; }
+
+  void Bind(mojo::ScopedMessagePipeHandle handle) {
+    bound_ = true;
+    receiver_.Bind(mojo::PendingReceiver<blink::mojom::TextFragmentReceiver>(
+        std::move(handle)));
+  }
+
+  bool bound() { return bound_; }
+
+  MOCK_METHOD1(GetExistingSelectors, void(GetExistingSelectorsCallback));
+
+ private:
+  mojo::Receiver<blink::mojom::TextFragmentReceiver> receiver_{this};
+  bool bound_ = false;
+};
+
+class SharedHighlightingFencedFrameBrowserTest
+    : public SharedHighlightingBrowserTest {
+ public:
+  SharedHighlightingFencedFrameBrowserTest() {
+    scoped_feature_list_.InitAndEnableFeature(
+        feature_engagement::kIPHDesktopSharedHighlightingFeature);
+  }
+  ~SharedHighlightingFencedFrameBrowserTest() override = default;
+
+  void SetUpOnMainThread() override {
+    InProcessBrowserTest::SetUpOnMainThread();
+    ASSERT_TRUE(embedded_test_server()->Start());
+  }
+
+  content::WebContents* web_contents() {
+    return browser()->tab_strip_model()->GetActiveWebContents();
+  }
+
+  content::test::FencedFrameTestHelper& fenced_frame_test_helper() {
+    return fenced_frame_helper_;
+  }
+
+ private:
+  content::test::FencedFrameTestHelper fenced_frame_helper_;
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(
+    SharedHighlightingFencedFrameBrowserTest,
+    EnsureTextFragmentReceiverMojoMethodIsNotCalledForFencedFrame) {
+  GURL initial_url(embedded_test_server()->GetURL("/empty.html"));
+  EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), initial_url));
+
+  GURL fenced_frame_url =
+      embedded_test_server()->GetURL("/fenced_frames/title1.html");
+  content::RenderFrameHost* fenced_frame_host =
+      fenced_frame_test_helper().CreateFencedFrame(
+          web_contents()->GetMainFrame(), fenced_frame_url);
+  ASSERT_TRUE(fenced_frame_host);
+
+  // Intercept TextFragmentReceiver Mojo connection.
+  MockTextFragmentReceiver text_fragment_receiver;
+  service_manager::InterfaceProvider::TestApi interface_overrider(
+      web_contents()->GetMainFrame()->GetRemoteInterfaces());
+  interface_overrider.SetBinderForName(
+      blink::mojom::TextFragmentReceiver::Name_,
+      base::BindRepeating(&MockTextFragmentReceiver::Bind,
+                          base::Unretained(&text_fragment_receiver)));
+
+  // GetExistingSelectors method should not be called by the navigation on a
+  // fenced frame.
+  EXPECT_CALL(text_fragment_receiver, GetExistingSelectors(testing::_))
+      .Times(0);
+
+  GURL text_fragment_url =
+      embedded_test_server()->GetURL("/fenced_frames/title2.html#:~:text=");
+  fenced_frame_test_helper().NavigateFrameInFencedFrameTree(fenced_frame_host,
+                                                            text_fragment_url);
+  EXPECT_FALSE(text_fragment_receiver.bound());
+}
+
 }  // namespace shared_highlighting
diff --git a/chrome/browser/sync/sync_service_factory_unittest.cc b/chrome/browser/sync/sync_service_factory_unittest.cc
index 0eadbeaa..c5ee7e8 100644
--- a/chrome/browser/sync/sync_service_factory_unittest.cc
+++ b/chrome/browser/sync/sync_service_factory_unittest.cc
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/task/thread_pool/thread_pool_instance.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
@@ -18,6 +19,7 @@
 #include "chrome/test/base/testing_profile.h"
 #include "components/browser_sync/browser_sync_switches.h"
 #include "components/sync/base/command_line_switches.h"
+#include "components/sync/base/features.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/driver/data_type_controller.h"
 #include "components/sync/driver/sync_service_impl.h"
@@ -137,7 +139,9 @@
     datatypes.Put(syncer::AUTOFILL_WALLET_OFFER);
     datatypes.Put(syncer::BOOKMARKS);
     datatypes.Put(syncer::DEVICE_INFO);
-    // TODO(crbug.com/1318028): Add HISTORY once it has a Controller.
+    if (base::FeatureList::IsEnabled(syncer::kSyncEnableHistoryDataType)) {
+      datatypes.Put(syncer::HISTORY);
+    }
     datatypes.Put(syncer::HISTORY_DELETE_DIRECTIVES);
     datatypes.Put(syncer::PREFERENCES);
     datatypes.Put(syncer::PRIORITY_PREFERENCES);
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 191b348..81fa8f8d 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1748,6 +1748,7 @@
       "//chrome/browser:theme_properties",
       "//chrome/browser/ash/system_web_apps/types:types",
       "//chrome/browser/autofill_assistant/password_change/proto:proto",
+      "//chrome/browser/autofill_assistant/password_change/vector_icons",
       "//chrome/browser/browsing_data:constants",
       "//chrome/browser/cart:mojo_bindings",
       "//chrome/browser/image_editor",
diff --git a/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_arc_tracker.cc b/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_arc_tracker.cc
index beaa738..d074862 100644
--- a/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_arc_tracker.cc
+++ b/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_arc_tracker.cc
@@ -460,6 +460,7 @@
   window->SetProperty(ash::kShelfIDKey, shelf_id.Serialize());
   window->SetProperty(ash::kArcPackageNameKey, info->package_name());
   window->SetProperty(ash::kAppIDKey, shelf_id.app_id);
+  window->SetProperty(aura::client::kSkipImeProcessing, true);
 
   if (info->launch_intent().empty())
     return;
diff --git a/chrome/browser/ui/ash/shelf/app_service/exo_app_type_resolver.cc b/chrome/browser/ui/ash/shelf/app_service/exo_app_type_resolver.cc
index 49ef60f..2c1e82b 100644
--- a/chrome/browser/ui/ash/shelf/app_service/exo_app_type_resolver.cc
+++ b/chrome/browser/ui/ash/shelf/app_service/exo_app_type_resolver.cc
@@ -111,6 +111,4 @@
     out_properties_container.SetProperty(
         app_restore::kParentToHiddenContainerKey, true);
   }
-
-  out_properties_container.SetProperty(aura::client::kSkipImeProcessing, true);
 }
diff --git a/chrome/browser/ui/autofill_assistant/password_change/apc_utils.cc b/chrome/browser/ui/autofill_assistant/password_change/apc_utils.cc
index 32d3d7e1..97dfbaf 100644
--- a/chrome/browser/ui/autofill_assistant/password_change/apc_utils.cc
+++ b/chrome/browser/ui/autofill_assistant/password_change/apc_utils.cc
@@ -6,6 +6,8 @@
 
 #include "build/branding_buildflags.h"
 #include "chrome/app/vector_icons/vector_icons.h"
+#include "chrome/browser/autofill_assistant/password_change/proto/extensions.pb.h"
+#include "chrome/browser/autofill_assistant/password_change/vector_icons/vector_icons.h"
 
 const gfx::VectorIcon& GetAssistantIconOrFallback() {
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
@@ -15,3 +17,33 @@
   return kProductIcon;
 #endif
 }
+
+const gfx::VectorIcon& GetApcTopIconFromEnum(
+    autofill_assistant::password_change::TopIcon icon) {
+  switch (icon) {
+    case autofill_assistant::password_change::TopIcon::TOP_ICON_UNSPECIFIED:
+      return autofill_assistant::password_change::kUnspecifiedStateIcon;
+    case autofill_assistant::password_change::TopIcon::
+        TOP_ICON_OPEN_SITE_SETTINGS:
+      return autofill_assistant::password_change::kOpenSiteSettingsIcon;
+    case autofill_assistant::password_change::TopIcon::
+        TOP_ICON_ENTER_OLD_PASSWORD:
+      return autofill_assistant::password_change::kEnterOldPasswordIcon;
+    case autofill_assistant::password_change::TopIcon::
+        TOP_ICON_CHOOSE_NEW_PASSWORD:
+      return autofill_assistant::password_change::kChooseNewPasswordIcon;
+    case autofill_assistant::password_change::TopIcon::
+        TOP_ICON_SAVE_NEW_PASSWORD:
+      return autofill_assistant::password_change::kSaveNewPasswordIcon;
+    case autofill_assistant::password_change::TOP_ICON_CHANGED_PASSWORD:
+      return autofill_assistant::password_change::kChangedPasswordIcon;
+    case autofill_assistant::password_change::TOP_ICON_BAD_NEW_PASSWORD:
+      return autofill_assistant::password_change::kBadNewPasswordIcon;
+    case autofill_assistant::password_change::TOP_ICON_ERROR_OCCURRED:
+      return autofill_assistant::password_change::kErrorOccurredIcon;
+    case autofill_assistant::password_change::TOP_ICON_USER_ACTION_REQUIRED:
+      return autofill_assistant::password_change::kUserActionRequiredIcon;
+  }
+
+  return autofill_assistant::password_change::kUnspecifiedStateIcon;
+}
diff --git a/chrome/browser/ui/autofill_assistant/password_change/apc_utils.h b/chrome/browser/ui/autofill_assistant/password_change/apc_utils.h
index 9e51d59..9cac75e 100644
--- a/chrome/browser/ui/autofill_assistant/password_change/apc_utils.h
+++ b/chrome/browser/ui/autofill_assistant/password_change/apc_utils.h
@@ -6,9 +6,15 @@
 #define CHROME_BROWSER_UI_AUTOFILL_ASSISTANT_PASSWORD_CHANGE_APC_UTILS_H_
 
 #include "chrome/app/vector_icons/vector_icons.h"
+#include "chrome/browser/autofill_assistant/password_change/proto/extensions.pb.h"
 
 // Returns the icon for Google Assistant on Google-branded builds and a
 // Chromium icon as a placeholder on non-branded builds.
 const gfx::VectorIcon& GetAssistantIconOrFallback();
 
+// Convert the protobuf enum that specifies a top icon for an Automate Password
+// Change flow to its correct `gfx::VectorIcon` counterpart.
+const gfx::VectorIcon& GetApcTopIconFromEnum(
+    autofill_assistant::password_change::TopIcon icon);
+
 #endif  // CHROME_BROWSER_UI_AUTOFILL_ASSISTANT_PASSWORD_CHANGE_APC_UTILS_H_
diff --git a/chrome/browser/ui/hid/hid_chooser_controller.cc b/chrome/browser/ui/hid/hid_chooser_controller.cc
index 8d812cd..2e0d77e0 100644
--- a/chrome/browser/ui/hid/hid_chooser_controller.cc
+++ b/chrome/browser/ui/hid/hid_chooser_controller.cc
@@ -20,7 +20,6 @@
 #include "chrome/grit/generated_resources.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/web_contents.h"
-#include "services/device/public/cpp/hid/hid_blocklist.h"
 #include "services/device/public/cpp/hid/hid_switches.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -312,27 +311,15 @@
     return false;
   }
 
-  if (device::HidBlocklist::IsDeviceExcluded(device)) {
+  if (device.is_excluded_by_blocklist) {
     AddMessageToConsole(
         blink::mojom::ConsoleMessageLevel::kInfo,
         base::StringPrintf(
-            "Chooser dialog is not displaying a device blocked by "
+            "Chooser dialog is not displaying a device excluded by "
             "the HID blocklist: vendorId=%d, "
-            "productId=%d, name='%s', serial='%s', numberOfCollections=%zu, "
-            "numberOfProtectedInputReports=%zu, "
-            "numberOfProtectedOutputReports=%zu, "
-            "numberOfProtectedFeatureReports=%zu",
+            "productId=%d, name='%s', serial='%s'",
             device.vendor_id, device.product_id, device.product_name.c_str(),
-            device.serial_number.c_str(), device.collections.size(),
-            device.protected_input_report_ids
-                ? device.protected_input_report_ids->size()
-                : 0,
-            device.protected_output_report_ids
-                ? device.protected_output_report_ids->size()
-                : 0,
-            device.protected_feature_report_ids
-                ? device.protected_feature_report_ids->size()
-                : 0));
+            device.serial_number.c_str()));
     return false;
   }
 
diff --git a/chrome/browser/ui/shared_highlighting/shared_highlighting_promo.cc b/chrome/browser/ui/shared_highlighting/shared_highlighting_promo.cc
index be86f3a..1a0eecd 100644
--- a/chrome/browser/ui/shared_highlighting/shared_highlighting_promo.cc
+++ b/chrome/browser/ui/shared_highlighting/shared_highlighting_promo.cc
@@ -41,7 +41,8 @@
     content::RenderFrameHost* render_frame_host,
     const GURL& validated_url) {
   if (!base::FeatureList::IsEnabled(
-          feature_engagement::kIPHDesktopSharedHighlightingFeature)) {
+          feature_engagement::kIPHDesktopSharedHighlightingFeature) ||
+      !render_frame_host->GetOutermostMainFrame()) {
     return;
   }
 
@@ -51,8 +52,9 @@
 
 void SharedHighlightingPromo::CheckExistingSelectors(
     content::RenderFrameHost* render_frame_host) {
+  DCHECK(render_frame_host->GetOutermostMainFrame());
   if (!remote_.is_bound()) {
-    render_frame_host->GetMainFrame()->GetRemoteInterfaces()->GetInterface(
+    render_frame_host->GetRemoteInterfaces()->GetInterface(
         remote_.BindNewPipeAndPassReceiver());
   }
 
diff --git a/chrome/browser/ui/views/autofill_assistant/password_change/password_change_run_view.cc b/chrome/browser/ui/views/autofill_assistant/password_change/password_change_run_view.cc
index 80cd2d7..b72cf13b 100644
--- a/chrome/browser/ui/views/autofill_assistant/password_change/password_change_run_view.cc
+++ b/chrome/browser/ui/views/autofill_assistant/password_change/password_change_run_view.cc
@@ -9,16 +9,25 @@
 
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
-#include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/autofill_assistant/password_change/proto/extensions.pb.h"
+#include "chrome/browser/ui/autofill_assistant/password_change/apc_utils.h"
 #include "chrome/browser/ui/autofill_assistant/password_change/password_change_run_controller.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
-#include "ui/views/background.h"
+#include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/layout_provider.h"
 #include "ui/views/view.h"
 
+namespace {
+
+// TODO(crbug.com/1322419): Where possible, replace these constants by values
+// obtained from the global layout provider.
+constexpr int kTopIconSize = 96;
+
+}  // namespace
+
 PasswordChangeRunView::PasswordChangeRunView(
     base::WeakPtr<PasswordChangeRunController> controller,
     raw_ptr<AssistantDisplayDelegate> display_delegate)
@@ -36,32 +45,39 @@
 }
 
 void PasswordChangeRunView::CreateView() {
+  // TODO(crbug.com/1322419): Add IDs to elements.
   DCHECK(controller_);
-  // TODO(crbug.com/1322419): Add proper icons, sizes, style etc.
-  SetLayoutManager(std::make_unique<views::BoxLayout>(
-      views::BoxLayout::Orientation::kVertical, gfx::Insets()));
-  SetBackground(views::CreateSolidBackground(SK_ColorWHITE));
+  views::BoxLayout* layout =
+      SetLayoutManager(std::make_unique<views::BoxLayout>(
+          views::BoxLayout::Orientation::kVertical));
+  layout->set_inside_border_insets(
+      views::LayoutProvider::Get()->GetInsetsMetric(views::INSETS_DIALOG));
+  layout->set_between_child_spacing(
+      views::LayoutProvider::Get()->GetDistanceMetric(
+          views::DISTANCE_UNRELATED_CONTROL_VERTICAL));
 
-  // Set up top container.
-  std::unique_ptr<views::View> top_container = std::make_unique<views::View>();
-  top_container->SetLayoutManager(std::make_unique<views::BoxLayout>(
-      views::BoxLayout::Orientation::kHorizontal, gfx::Insets()));
+  top_icon_ = AddChildView(views::Builder<views::ImageView>().Build());
 
-  top_icon_ = top_container->AddChildView(std::make_unique<views::ImageView>());
-  top_icon_->SetImage(
-      ui::ImageModel::FromVectorIcon(kKeyIcon, ui::kColorIcon, 64));
-  top_icon_->SetHorizontalAlignment(views::ImageView::Alignment::kLeading);
-  // TODO(brunobraga): Initialise progress bar.
+  // TODO(crbug.com/1322419): Adjust style (multiline, font style, etc.)
   title_ = AddChildView(std::make_unique<views::Label>());
-  description_ = AddChildView(std::make_unique<views::Label>());
-  body_ = AddChildView(std::make_unique<views::View>());
 
-  AddChildView(std::move(top_container));
+  // TODO(crbug.com/1322419): Add and initialize progress bar.
+
+  // TODO(crbug.com/1322419): Adjust style (multiline, font style, etc.)
+  description_ = AddChildView(std::make_unique<views::Label>());
+
+  // TODO(crbug.com/1322419): Add appropriate layout manager.
+  body_ = AddChildView(std::make_unique<views::View>());
+}
+
+void PasswordChangeRunView::SetTopIcon(
+    autofill_assistant::password_change::TopIcon top_icon) {
+  DCHECK(top_icon_);
+  top_icon_->SetImage(gfx::CreateVectorIcon(
+      GetApcTopIconFromEnum(top_icon), kTopIconSize, gfx::kPlaceholderColor));
 }
 
 // TODO(crbug.com/1322419): Implement set methods.
-void PasswordChangeRunView::SetTopIcon(
-    autofill_assistant::password_change::TopIcon top_icon) {}
 void PasswordChangeRunView::SetTitle(std::u16string body_title) {}
 void PasswordChangeRunView::SetDescription(
     std::u16string progress_description) {}
diff --git a/chrome/browser/ui/views/location_bar/permission_request_chip_browsertest.cc b/chrome/browser/ui/views/location_bar/permission_request_chip_browsertest.cc
index 73b2732..d72398c 100644
--- a/chrome/browser/ui/views/location_bar/permission_request_chip_browsertest.cc
+++ b/chrome/browser/ui/views/location_bar/permission_request_chip_browsertest.cc
@@ -21,6 +21,7 @@
 #include "components/omnibox/browser/omnibox_edit_model.h"
 #include "components/omnibox/browser/omnibox_view.h"
 #include "components/permissions/features.h"
+#include "components/permissions/test/permission_request_observer.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test.h"
 #include "ui/gfx/animation/animation_test_api.h"
@@ -29,12 +30,15 @@
 
 void RequestPermission(Browser* browser) {
   test::PermissionRequestManagerTestApi test_api(browser);
+  permissions::PermissionRequestObserver observer(
+      browser->tab_strip_model()->GetActiveWebContents());
+
   EXPECT_NE(nullptr, test_api.manager());
   test_api.AddSimpleRequest(
       browser->tab_strip_model()->GetActiveWebContents()->GetMainFrame(),
       permissions::RequestType::kGeolocation);
 
-  base::RunLoop().RunUntilIdle();
+  observer.Wait();
 }
 
 LocationBarView* GetLocationBarView(Browser* browser) {
@@ -111,6 +115,83 @@
   EXPECT_FALSE(lbv->chip());
 }
 
+// This is an end-to-end test that verifies that a permission prompt bubble will
+// not be shown because of the empty address bar. Under the normal conditions
+// such a test should be placed in PermissionsSecurityModelInteractiveUITest but
+// due to dependency issues (see crbug.com/1112591) `//chrome/browser` is not
+// allowed to have dependencies on `//chrome/browser/ui/views/*`.
+IN_PROC_BROWSER_TEST_F(PermissionRequestChipBrowserTest,
+                       PermissionRequestIsAutoIgnored) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  content::WebContents* embedder_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  ASSERT_TRUE(embedder_contents);
+  const GURL url(embedded_test_server()->GetURL("/empty.html"));
+  content::RenderFrameHost* main_rfh =
+      ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(browser(), url,
+                                                                1);
+  content::WebContents::FromRenderFrameHost(main_rfh)->Focus();
+
+  ASSERT_TRUE(main_rfh);
+
+  constexpr char kCheckMicrophone[] = R"(
+    new Promise(async resolve => {
+      const PermissionStatus =
+        await navigator.permissions.query({name: 'microphone'});
+      resolve(PermissionStatus.state === 'granted');
+    })
+    )";
+
+  constexpr char kRequestMicrophone[] = R"(
+    new Promise(async resolve => {
+      var constraints = { audio: true };
+      window.focus();
+      try {
+        const stream = await navigator.mediaDevices.getUserMedia(constraints);
+        resolve('granted');
+      } catch(error) {
+        resolve('denied')
+      }
+    })
+    )";
+
+  EXPECT_FALSE(content::EvalJs(main_rfh, kCheckMicrophone,
+                               content::EXECUTE_SCRIPT_DEFAULT_OPTIONS, 1)
+                   .value.GetBool());
+
+  LocationBarView* location_bar =
+      BrowserView::GetBrowserViewForBrowser(browser())
+          ->toolbar()
+          ->location_bar();
+
+  // Type something in the omnibox.
+  OmniboxView* omnibox_view = location_bar->GetOmniboxView();
+  omnibox_view->SetUserText(u"search query");
+  omnibox_view->model()->SetInputInProgress(true);
+
+  auto* manager =
+      permissions::PermissionRequestManager::FromWebContents(embedder_contents);
+  permissions::PermissionRequestObserver observer(embedder_contents);
+
+  EXPECT_FALSE(manager->IsRequestInProgress());
+
+  EXPECT_TRUE(content::ExecJs(
+      main_rfh, kRequestMicrophone,
+      content::EvalJsOptions::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES));
+
+  // Wait until a permission request is shown or finalized.
+  observer.Wait();
+
+  // Permission request was finalized without showing a prompt bubble.
+  EXPECT_FALSE(manager->IsRequestInProgress());
+  EXPECT_FALSE(observer.request_shown());
+
+  EXPECT_FALSE(content::EvalJs(main_rfh, kCheckMicrophone,
+                               content::EXECUTE_SCRIPT_DEFAULT_OPTIONS, 1)
+                   .value.GetBool());
+}
+
 class PermissionRequestChipDialogBrowserTest : public UiBrowserTest {
  public:
   PermissionRequestChipDialogBrowserTest() {
diff --git a/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc b/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc
index 0117d9f..70e37336 100644
--- a/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc
+++ b/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/ui/views/location_bar/permission_chip.h"
 #include "chrome/browser/ui/views/permission_bubble/permission_prompt_bubble_view.h"
 #include "chrome/browser/ui/web_applications/app_browser_controller.h"
+#include "chrome/common/webui_url_constants.h"
 #include "components/permissions/features.h"
 #include "components/permissions/permission_request.h"
 #include "components/permissions/permission_request_manager.h"
@@ -43,9 +44,20 @@
   return !location_bar || !location_bar->IsDrawn();
 }
 
-bool IsLocationBarEditingOrEmpty(Browser* browser) {
+// A permission request should be auto-ignored if a user interacts with the
+// LocationBar. The only exception is the NTP page where the user needs to press
+// on a microphone icon to get a permission request.
+bool ShouldIgnorePermissionRequest(content::WebContents* web_contents,
+                                   Browser* browser) {
+  DCHECK(web_contents);
   DCHECK(browser);
 
+  // In case of the NTP, `WebContents::GetVisibleURL()` is equal to
+  // `chrome://newtab/`, but the `LocationBarView` will be empty.
+  if (web_contents->GetVisibleURL() == GURL(chrome::kChromeUINewTabURL)) {
+    return false;
+  }
+
   BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
   if (!browser_view)
     return false;
@@ -106,7 +118,7 @@
   }
 
   // Auto-ignore the permission request if a user is typing into location bar.
-  if (IsLocationBarEditingOrEmpty(browser)) {
+  if (ShouldIgnorePermissionRequest(web_contents, browser)) {
     return nullptr;
   }
 
diff --git a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.cc b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.cc
index c165a51..2d0e153 100644
--- a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.cc
+++ b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.cc
@@ -8,7 +8,10 @@
 
 #include "ash/components/arc/arc_prefs.h"
 #include "ash/components/audio/cras_audio_handler.h"
+#include "ash/constants/ash_features.h"
+#include "base/containers/contains.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/notreached.h"
 #include "chrome/browser/consent_auditor/consent_auditor_factory.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/grit/browser_resources.h"
@@ -28,6 +31,37 @@
 
 namespace chromeos {
 
+namespace {
+
+// Possible native assistant icons
+// Must be in sync with the corresponding javascript enum.
+enum class AssistantNativeIconType {
+  kNone = 0,
+
+  // Web & App Activity.
+  kWAA = 1,
+
+  // Device Applications Information.
+  kDA = 2,
+
+  kInfo = 3,
+};
+
+AssistantNativeIconType SettingIdToIconType(
+    assistant::SettingSetId setting_set_id) {
+  switch (setting_set_id) {
+    case assistant::SettingSetId::WAA:
+      return AssistantNativeIconType::kWAA;
+    case assistant::SettingSetId::DA:
+      return AssistantNativeIconType::kDA;
+    case assistant::SettingSetId::UNKNOWN_SETTING_SET_ID:
+      NOTREACHED();
+      return AssistantNativeIconType::kNone;
+  }
+}
+
+}  // namespace
+
 void RecordAssistantOptInStatus(AssistantOptInFlowStatus status) {
   UMA_HISTOGRAM_ENUMERATION("Assistant.OptInFlowStatus", status, kMaxValue + 1);
 }
@@ -104,6 +138,11 @@
                   base::Value(setting_zippy.additional_info_paragraph(0)));
     }
     data.SetKey("iconUri", base::Value(setting_zippy.icon_uri()));
+    data.SetKey("nativeIconType",
+                base::Value(static_cast<int>(
+                    SettingIdToIconType(setting_zippy.setting_set_id()))));
+    data.SetKey("useNativeIcons",
+                base::Value(ash::features::IsAssistantNativeIconsEnabled()));
     data.SetKey("popupLink", base::Value(l10n_util::GetStringUTF16(
                                  IDS_ASSISTANT_ACTIVITY_CONTROL_POPUP_LINK)));
     if (is_minor_mode) {
diff --git a/chrome/browser/ui/webui/chromeos/login/debug/debug_overlay_handler.cc b/chrome/browser/ui/webui/chromeos/login/debug/debug_overlay_handler.cc
index db19aa93..45dd2b8c 100644
--- a/chrome/browser/ui/webui/chromeos/login/debug/debug_overlay_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/debug/debug_overlay_handler.cc
@@ -134,6 +134,10 @@
     if (add_resolution_to_filename_)
       filename.append("_" + rect.size().ToString());
 
+    if (ash::ColorProvider::Get()->IsDarkModeEnabled()) {
+      filename.append("_dark");
+    }
+
     filename.append(".png");
     ui::GrabWindowSnapshotAsyncPNG(
         root_window, rect,
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn
index fe5dfb0..fa49d24 100644
--- a/chrome/browser/web_applications/BUILD.gn
+++ b/chrome/browser/web_applications/BUILD.gn
@@ -172,6 +172,7 @@
     "web_app_tab_helper.h",
     "web_app_translation_manager.cc",
     "web_app_translation_manager.h",
+    "web_app_ui_manager.cc",
     "web_app_ui_manager.h",
     "web_app_uninstall_job.cc",
     "web_app_uninstall_job.h",
diff --git a/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_unittest.cc b/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_unittest.cc
index bf24a0d..f7b63c5 100644
--- a/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_unittest.cc
+++ b/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_unittest.cc
@@ -117,6 +117,47 @@
   base::RunLoop run_loop_;
 };
 
+class TestUiManagerObserver : public WebAppUiManagerObserver {
+ public:
+  explicit TestUiManagerObserver(WebAppUiManager* ui_manager) {
+    ui_manager_observation_.Observe(ui_manager);
+  }
+
+  using ReadyToCommitNavigationCallback = base::RepeatingCallback<
+      void(const AppId& app_id, content::NavigationHandle* navigation_handle)>;
+
+  void SetReadyToCommitNavigationCallback(
+      ReadyToCommitNavigationCallback callback) {
+    ready_to_commit_navigation_callback_ = std::move(callback);
+  }
+
+  void OnReadyToCommitNavigation(
+      const AppId& app_id,
+      content::NavigationHandle* navigation_handle) override {
+    if (ready_to_commit_navigation_callback_)
+      ready_to_commit_navigation_callback_.Run(app_id, navigation_handle);
+  }
+
+  using UiManagerDestroyedCallback = base::RepeatingCallback<void()>;
+
+  void SetUiManagerDestroyedCallback(UiManagerDestroyedCallback callback) {
+    ui_manager_destroyed_callback_ = std::move(callback);
+  }
+
+  void OnWebAppUiManagerDestroyed() override {
+    if (ui_manager_destroyed_callback_)
+      ui_manager_destroyed_callback_.Run();
+    ui_manager_observation_.Reset();
+  }
+
+ private:
+  ReadyToCommitNavigationCallback ready_to_commit_navigation_callback_;
+  UiManagerDestroyedCallback ui_manager_destroyed_callback_;
+
+  base::ScopedObservation<WebAppUiManager, WebAppUiManagerObserver>
+      ui_manager_observation_{this};
+};
+
 }  // namespace
 
 class SystemWebAppManagerTest : public WebAppTest {
@@ -202,6 +243,8 @@
     fake_registry_controller_.reset();
   }
 
+  void DestroyUiManager() { test_ui_manager_.reset(); }
+
  protected:
   FakeWebAppRegistryController& controller() {
     return *fake_registry_controller_;
@@ -1480,4 +1523,17 @@
   EXPECT_FALSE(unsynced_system_web_app_manager->IsSystemWebApp(*opt_app_id));
 }
 
+TEST_F(SystemWebAppManagerTest, DestroyUiManager) {
+  InitEmptyRegistrar();
+  StartAndWaitForAppsToSynchronize();
+
+  base::RunLoop run_loop;
+  TestUiManagerObserver observer{&ui_manager()};
+  observer.SetUiManagerDestroyedCallback(run_loop.QuitClosure());
+
+  // Should not crash.
+  DestroyUiManager();
+  run_loop.Run();
+}
+
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_tab_helper.cc b/chrome/browser/web_applications/web_app_tab_helper.cc
index 3bee865c..e4e653a 100644
--- a/chrome/browser/web_applications/web_app_tab_helper.cc
+++ b/chrome/browser/web_applications/web_app_tab_helper.cc
@@ -8,7 +8,6 @@
 #include <string>
 
 #include "base/unguessable_token.h"
-#include "chrome/browser/ash/system_web_apps/system_web_app_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/manifest_update_manager.h"
 #include "chrome/browser/web_applications/os_integration/os_integration_manager.h"
@@ -86,16 +85,12 @@
     SetAppId(FindAppWithUrlInScope(url));
   }
 
-  // If navigating to a System Web App (including navigation in sub frames), let
-  // ash::SystemWebAppManager perform tab-secific setup for navigations in
-  // System Web Apps.
-  Profile* profile =
-      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
-  auto* swa_manager =
-      ash::SystemWebAppManager::GetForLocalAppsUnchecked(profile);
-  if (app_id_.has_value() && swa_manager &&
-      swa_manager->IsSystemWebApp(app_id_.value())) {
-    swa_manager->OnReadyToCommitNavigation(app_id_.value(), navigation_handle);
+  // If navigating to a Web App (including navigation in sub frames), let
+  // `WebAppUiManager` observers perform tab-secific setup for navigations in
+  // Web Apps.
+  if (app_id_.has_value()) {
+    provider_->ui_manager().NotifyReadyToCommitNavigation(app_id_.value(),
+                                                          navigation_handle);
   }
 }
 
diff --git a/chrome/browser/web_applications/web_app_ui_manager.cc b/chrome/browser/web_applications/web_app_ui_manager.cc
new file mode 100644
index 0000000..0c79b95
--- /dev/null
+++ b/chrome/browser/web_applications/web_app_ui_manager.cc
@@ -0,0 +1,31 @@
+// 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.
+
+#include "chrome/browser/web_applications/web_app_ui_manager.h"
+
+namespace web_app {
+
+WebAppUiManager::WebAppUiManager() = default;
+
+WebAppUiManager::~WebAppUiManager() {
+  for (WebAppUiManagerObserver& observer : observers_)
+    observer.OnWebAppUiManagerDestroyed();
+}
+
+void WebAppUiManager::AddObserver(WebAppUiManagerObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void WebAppUiManager::RemoveObserver(WebAppUiManagerObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+void WebAppUiManager::NotifyReadyToCommitNavigation(
+    const AppId& app_id,
+    content::NavigationHandle* navigation_handle) {
+  for (WebAppUiManagerObserver& observer : observers_)
+    observer.OnReadyToCommitNavigation(app_id, navigation_handle);
+}
+
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_ui_manager.h b/chrome/browser/web_applications/web_app_ui_manager.h
index ced29ca..b16bffd 100644
--- a/chrome/browser/web_applications/web_app_ui_manager.h
+++ b/chrome/browser/web_applications/web_app_ui_manager.h
@@ -9,6 +9,8 @@
 #include <vector>
 
 #include "base/callback_forward.h"
+#include "base/observer_list.h"
+#include "base/observer_list_types.h"
 #include "chrome/browser/web_applications/os_integration/os_integration_manager.h"
 #include "chrome/browser/web_applications/os_integration/web_app_shortcut.h"
 #include "chrome/browser/web_applications/web_app_callback_app_identity.h"
@@ -18,6 +20,7 @@
 
 namespace content {
 class WebContents;
+class NavigationHandle;
 }
 
 namespace web_app {
@@ -26,13 +29,28 @@
 // WebAppUiManagerImpl can be used only in UI code.
 class WebAppUiManagerImpl;
 
-// Pure virtual interface used to perform Web App UI operations or listen to Web
-// App UI events.
+class WebAppUiManagerObserver : public base::CheckedObserver {
+ public:
+  // Notifies on `content::WebContentsObserver::ReadyToCommitNavigation` when a
+  // navigation is about to commit in a web app identified by `app_id`
+  // (including navigations in sub frames).
+  virtual void OnReadyToCommitNavigation(
+      const AppId& app_id,
+      content::NavigationHandle* navigation_handle) {}
+
+  // Called when the WebAppUiManager is about to be destroyed.
+  virtual void OnWebAppUiManagerDestroyed() {}
+};
+
+// A chrome/browser/ representation of the chrome/browser/ui/ UI manager to
+// perform Web App UI operations or listen to Web App UI events, including
+// events from WebAppTabHelpers.
 class WebAppUiManager {
  public:
   static std::unique_ptr<WebAppUiManager> Create(Profile* profile);
 
-  virtual ~WebAppUiManager() = default;
+  WebAppUiManager();
+  virtual ~WebAppUiManager();
 
   virtual void SetSubsystems(WebAppSyncBridge* sync_bridge,
                              OsIntegrationManager* os_integration_manager) = 0;
@@ -47,6 +65,12 @@
   virtual void NotifyOnAllAppWindowsClosed(const AppId& app_id,
                                            base::OnceClosure callback) = 0;
 
+  void AddObserver(WebAppUiManagerObserver* observer);
+  void RemoveObserver(WebAppUiManagerObserver* observer);
+  void NotifyReadyToCommitNavigation(
+      const AppId& app_id,
+      content::NavigationHandle* navigation_handle);
+
   // Uninstalls the the apps in |from_apps| and migrates an |to_app|'s OS
   // attributes (e.g pin position, app list folder/position, shortcuts) to the
   // first |from_app| found. |shortcut_locations| will be populated with the
@@ -83,6 +107,9 @@
       const SkBitmap& new_icon,
       content::WebContents* web_contents,
       web_app::AppIdentityDialogCallback callback) = 0;
+
+ private:
+  base::ObserverList<WebAppUiManagerObserver> observers_;
 };
 
 }  // namespace web_app
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 4b2c9ad..aecb0c9 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1654041570-5af5e342011ee50b3d65f76c3f829366019fc010.profdata
+chrome-linux-main-1654062874-4152fbd196e97db399ecd5e55faca78b8293291b.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 7889f26..fc1074b 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1654019812-0f0a0aefa982db3247e0b33aeebc738048a67f5c.profdata
+chrome-mac-main-1654062874-e5300f14cff8b390992f7247339845baa9949738.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 185d727..c308159 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1654030723-ddd5c8c3c0d770038e8afd577c4834342a7c22d5.profdata
+chrome-win32-main-1654062874-288a90e75e2530c80a4c3ddd4dee17ec1d8c2414.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index f100c25..f18c6f1 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1654030723-b348f5c33f2b995ec8ace4068a158aabb1500cce.profdata
+chrome-win64-main-1654062874-cbaa03a3d99d60fa8d5ad3e8377fba541e0c97cf.profdata
diff --git a/chrome/common/chromeos/extensions/api/telemetry.idl b/chrome/common/chromeos/extensions/api/telemetry.idl
index e6e6428..3d99a3a8 100644
--- a/chrome/common/chromeos/extensions/api/telemetry.idl
+++ b/chrome/common/chromeos/extensions/api/telemetry.idl
@@ -5,37 +5,24 @@
 // Use the <code>chrome.os.telemetry</code> API to get telemetry data.
 [implemented_in = "chrome/browser/chromeos/extensions/telemetry/api/telemetry_api.h"]
 namespace os.telemetry {
-  dictionary VpdInfo {
-    // Device activate date. Format: YYYY-WW.
-    DOMString? activateDate;
-
-    // Device model name.
-    DOMString? modelName;
-
-    // Device serial number.
+  dictionary BatteryInfo {
+    double? cycleCount;
+    double? voltageNow;
+    DOMString? vendor;
     DOMString? serialNumber;
-
-    // Device SKU number, a.k.a. model number.
-    DOMString? skuNumber;
+    double? chargeFullDesign;
+    double? chargeFull;
+    double? voltageMinDesign;
+    DOMString? modelName;
+    double? chargeNow;
+    double? currentNow;
+    DOMString? technology;
+    DOMString? status;
+    DOMString? manufactureDate;
+    double? temperature;
   };
 
-  callback VpdInfoCallback = void (VpdInfo vpdInfo);
-
-  dictionary OemData {
-    // OEM data. This field used to store battery serial number by some OEMs.
-    DOMString? oemData;
-  };
-
-  callback OemDataCallback = void (OemData oemData);
-
-  dictionary MemoryInfo {
-    long? totalMemoryKiB;
-    long? freeMemoryKiB;
-    long? availableMemoryKiB;
-    double? pageFaultsSinceLastBoot;
-  };
-
-  callback MemoryInfoCallback = void (MemoryInfo cpuInfo);
+  callback BatteryInfoCallback = void (BatteryInfo batteryInfo);
 
   enum CpuArchitectureEnum {
     unknown,
@@ -77,37 +64,50 @@
 
   callback CpuInfoCallback = void (CpuInfo cpuInfo);
 
-  dictionary BatteryInfo {
-    double? cycleCount;
-    double? voltageNow;
-    DOMString? vendor;
-    DOMString? serialNumber;
-    double? chargeFullDesign;
-    double? chargeFull;
-    double? voltageMinDesign;
-    DOMString? modelName;
-    double? chargeNow;
-    double? currentNow;
-    DOMString? technology;
-    DOMString? status;
-    DOMString? manufactureDate;
-    double? temperature;
+  dictionary MemoryInfo {
+    long? totalMemoryKiB;
+    long? freeMemoryKiB;
+    long? availableMemoryKiB;
+    double? pageFaultsSinceLastBoot;
   };
 
-  callback BatteryInfoCallback = void (BatteryInfo batteryInfo);
+  callback MemoryInfoCallback = void (MemoryInfo cpuInfo);
+
+  dictionary OemData {
+    // OEM data. This field used to store battery serial number by some OEMs.
+    DOMString? oemData;
+  };
+
+  callback OemDataCallback = void (OemData oemData);
+
+  dictionary VpdInfo {
+    // Device activate date. Format: YYYY-WW.
+    DOMString? activateDate;
+
+    // Device model name.
+    DOMString? modelName;
+
+    // Device serial number.
+    DOMString? serialNumber;
+
+    // Device SKU number, a.k.a. model number.
+    DOMString? skuNumber;
+  };
+
+  callback VpdInfoCallback = void (VpdInfo vpdInfo);
 
   interface Functions {
-    // Retrieves VPD info.
-    [supportsPromises] static void getVpdInfo(VpdInfoCallback callback);
+    // Retrieves battery info.
+    [supportsPromises] static void getBatteryInfo(BatteryInfoCallback callback);
+
+    [supportsPromises] static void getCpuInfo(CpuInfoCallback callback);
+
+    [supportsPromises] static void getMemoryInfo(MemoryInfoCallback callback);
 
     // Retrieves OEM data.
     [supportsPromises] static void getOemData(OemDataCallback callback);
 
-    [supportsPromises] static void getMemoryInfo(MemoryInfoCallback callback);
-
-    [supportsPromises] static void getCpuInfo(CpuInfoCallback callback);
-
-    // Retrieves battery info.
-    [supportsPromises] static void getBatteryInfo(BatteryInfoCallback callback);
+    // Retrieves VPD info.
+    [supportsPromises] static void getVpdInfo(VpdInfoCallback callback);
   };
 };
diff --git a/chrome/common/extensions/api/autotest_private.idl b/chrome/common/extensions/api/autotest_private.idl
index 215c026..4043dfa1 100644
--- a/chrome/common/extensions/api/autotest_private.idl
+++ b/chrome/common/extensions/api/autotest_private.idl
@@ -352,9 +352,22 @@
     boolean? showInSearch;
   };
 
-  dictionary SystemApp {
+  dictionary SystemWebApp {
+    // App's internal name. This isn't user-visible and should only be used
+    // for logging.
     DOMString internalName;
+
+    // App's install URL. This is a placeholder for installation pipeline,
+    // not used for anything else.
     DOMString url;
+
+    // App's visible name. This is defined in the Web App manifest, and shown
+    // in Shelf and Launcher. This matches App's name attribute (see above).
+    DOMString name;
+
+    // App's default start_url. This is the default URL that the App will be
+    // launched to.
+    DOMString startUrl;
   };
 
   callback GetAllInstalledAppsCallback = void (App[] apps);
@@ -617,7 +630,7 @@
   // Callback invoked to report the number of system web apps that should be
   // installed.
   callback GetRegisteredSystemWebAppsCallback = void
-      (SystemApp[] systemApps);
+      (SystemWebApp[] systemWebApps);
 
   callback IsSystemWebAppOpenCallback = void (boolean isOpen);
 
diff --git a/chrome/test/chromedriver/chrome/chrome_android_impl.cc b/chrome/test/chromedriver/chrome/chrome_android_impl.cc
index 691615f..49666b7 100644
--- a/chrome/test/chromedriver/chrome/chrome_android_impl.cc
+++ b/chrome/test/chromedriver/chrome/chrome_android_impl.cc
@@ -8,6 +8,7 @@
 
 #include "base/strings/string_split.h"
 #include "chrome/test/chromedriver/chrome/device_manager.h"
+#include "chrome/test/chromedriver/chrome/device_metrics.h"
 #include "chrome/test/chromedriver/chrome/devtools_client.h"
 #include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
 #include "chrome/test/chromedriver/chrome/devtools_http_client.h"
@@ -19,11 +20,15 @@
     std::unique_ptr<DevToolsClient> websocket_client,
     std::vector<std::unique_ptr<DevToolsEventListener>>
         devtools_event_listeners,
+    std::unique_ptr<DeviceMetrics> device_metrics,
+    SyncWebSocketFactory socket_factory,
     std::string page_load_strategy,
     std::unique_ptr<Device> device)
     : ChromeImpl(std::move(http_client),
                  std::move(websocket_client),
                  std::move(devtools_event_listeners),
+                 std::move(device_metrics),
+                 std::move(socket_factory),
                  page_load_strategy),
       device_(std::move(device)) {}
 
diff --git a/chrome/test/chromedriver/chrome/chrome_android_impl.h b/chrome/test/chromedriver/chrome/chrome_android_impl.h
index 3621af23..871dd1a 100644
--- a/chrome/test/chromedriver/chrome/chrome_android_impl.h
+++ b/chrome/test/chromedriver/chrome/chrome_android_impl.h
@@ -12,6 +12,7 @@
 #include "chrome/test/chromedriver/chrome/chrome_impl.h"
 
 class Device;
+struct DeviceMetrics;
 class DevToolsClient;
 class DevToolsHttpClient;
 
@@ -21,6 +22,8 @@
                     std::unique_ptr<DevToolsClient> websocket_client,
                     std::vector<std::unique_ptr<DevToolsEventListener>>
                         devtools_event_listeners,
+                    std::unique_ptr<DeviceMetrics> device_metrics,
+                    SyncWebSocketFactory socket_factory,
                     std::string page_load_strategy,
                     std::unique_ptr<Device> device);
   ~ChromeAndroidImpl() override;
diff --git a/chrome/test/chromedriver/chrome/chrome_desktop_impl.cc b/chrome/test/chromedriver/chrome/chrome_desktop_impl.cc
index a0dba51..c623f36 100644
--- a/chrome/test/chromedriver/chrome/chrome_desktop_impl.cc
+++ b/chrome/test/chromedriver/chrome/chrome_desktop_impl.cc
@@ -17,6 +17,7 @@
 #include "base/threading/platform_thread.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
+#include "chrome/test/chromedriver/chrome/device_metrics.h"
 #include "chrome/test/chromedriver/chrome/devtools_client.h"
 #include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
 #include "chrome/test/chromedriver/chrome/devtools_http_client.h"
@@ -75,6 +76,8 @@
     std::unique_ptr<DevToolsClient> websocket_client,
     std::vector<std::unique_ptr<DevToolsEventListener>>
         devtools_event_listeners,
+    std::unique_ptr<DeviceMetrics> device_metrics,
+    SyncWebSocketFactory socket_factory,
     std::string page_load_strategy,
     base::Process process,
     const base::CommandLine& command,
@@ -84,6 +87,8 @@
     : ChromeImpl(std::move(http_client),
                  std::move(websocket_client),
                  std::move(devtools_event_listeners),
+                 std::move(device_metrics),
+                 std::move(socket_factory),
                  page_load_strategy),
       process_(std::move(process)),
       command_(command),
@@ -141,7 +146,7 @@
   if (id.empty())
     return Status(kUnknownError, "page could not be found: " + url);
 
-  const DeviceMetrics* device_metrics = devtools_http_client_->device_metrics();
+  const DeviceMetrics* device_metrics = device_metrics_.get();
   if (type == WebViewInfo::Type::kApp ||
       type == WebViewInfo::Type::kBackgroundPage) {
     // Apps and extensions don't work on Android, so it doesn't make sense to
@@ -152,8 +157,7 @@
   }
   std::unique_ptr<WebView> web_view_tmp(new WebViewImpl(
       id, w3c_compliant, nullptr, devtools_http_client_->browser_info(),
-      devtools_http_client_->CreateClient(id), device_metrics,
-      page_load_strategy()));
+      CreateClient(id), device_metrics, page_load_strategy()));
   Status status = web_view_tmp->ConnectIfNecessary();
   if (status.IsError())
     return status;
@@ -175,7 +179,7 @@
 }
 
 bool ChromeDesktopImpl::IsMobileEmulationEnabled() const {
-  return devtools_http_client_->device_metrics() != NULL;
+  return static_cast<bool>(device_metrics_);
 }
 
 bool ChromeDesktopImpl::HasTouchScreen() const {
diff --git a/chrome/test/chromedriver/chrome/chrome_desktop_impl.h b/chrome/test/chromedriver/chrome/chrome_desktop_impl.h
index e03f2070..1fc4c14 100644
--- a/chrome/test/chromedriver/chrome/chrome_desktop_impl.h
+++ b/chrome/test/chromedriver/chrome/chrome_desktop_impl.h
@@ -13,6 +13,7 @@
 #include "base/process/process.h"
 #include "chrome/test/chromedriver/chrome/chrome_impl.h"
 #include "chrome/test/chromedriver/chrome/scoped_temp_dir_with_retry.h"
+#include "chrome/test/chromedriver/net/sync_websocket_factory.h"
 
 namespace base {
 class TimeDelta;
@@ -22,6 +23,7 @@
 class DevToolsHttpClient;
 class Status;
 class WebView;
+struct DeviceMetrics;
 
 class ChromeDesktopImpl : public ChromeImpl {
  public:
@@ -29,6 +31,8 @@
                     std::unique_ptr<DevToolsClient> websocket_client,
                     std::vector<std::unique_ptr<DevToolsEventListener>>
                         devtools_event_listeners,
+                    std::unique_ptr<DeviceMetrics> device_metrics,
+                    SyncWebSocketFactory socket_factory,
                     std::string page_load_strategy,
                     base::Process process,
                     const base::CommandLine& command,
diff --git a/chrome/test/chromedriver/chrome/chrome_impl.cc b/chrome/test/chromedriver/chrome/chrome_impl.cc
index 7c0ef44..47bf735b 100644
--- a/chrome/test/chromedriver/chrome/chrome_impl.cc
+++ b/chrome/test/chromedriver/chrome/chrome_impl.cc
@@ -5,13 +5,19 @@
 #include "chrome/test/chromedriver/chrome/chrome_impl.h"
 
 #include <stddef.h>
+#include <algorithm>
 #include <utility>
 
+#include "base/bind.h"
+#include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/threading/platform_thread.h"
 #include "base/time/time.h"
 #include "base/values.h"
+#include "chrome/test/chromedriver/chrome/chrome.h"
+#include "chrome/test/chromedriver/chrome/device_metrics.h"
 #include "chrome/test/chromedriver/chrome/devtools_client.h"
+#include "chrome/test/chromedriver/chrome/devtools_client_impl.h"
 #include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
 #include "chrome/test/chromedriver/chrome/devtools_http_client.h"
 #include "chrome/test/chromedriver/chrome/page_load_strategy.h"
@@ -105,8 +111,7 @@
         }
       }
       if (!found) {
-        std::unique_ptr<DevToolsClient> client(
-            devtools_http_client_->CreateClient(view.id));
+        std::unique_ptr<DevToolsClient> client = CreateClient(view.id);
         for (const auto& listener : devtools_event_listeners_)
           client->AddListener(listener.get());
         // OnConnected will fire when DevToolsClient connects later.
@@ -119,7 +124,7 @@
           web_views_.push_back(std::make_unique<WebViewImpl>(
               view.id, w3c_compliant, nullptr,
               devtools_http_client_->browser_info(), std::move(client),
-              devtools_http_client_->device_metrics(), page_load_strategy_));
+              device_metrics_.get(), page_load_strategy_));
         }
       }
     }
@@ -166,6 +171,89 @@
   return Status(kOk);
 }
 
+std::unique_ptr<DevToolsClient> ChromeImpl::CreateClient(
+    const std::string& id) {
+  auto result = std::make_unique<DevToolsClientImpl>(
+      id, "", devtools_http_client_->endpoint().GetDebuggerUrl(id),
+      socket_factory_);
+  result->SetFrontendCloserFunc(base::BindRepeating(
+      &ChromeImpl::CloseFrontends, base::Unretained(this), id));
+  return result;
+}
+
+Status ChromeImpl::CloseFrontends(const std::string& for_client_id) {
+  WebViewsInfo views_info;
+  Status status = devtools_http_client_->GetWebViewsInfo(&views_info);
+  if (status.IsError())
+    return status;
+
+  // Close frontends. Usually frontends are docked in the same page, although
+  // some may be in tabs (undocked, chrome://inspect, the DevTools
+  // discovery page, etc.). Tabs can be closed via the DevTools HTTP close
+  // URL, but docked frontends can only be closed, by design, by connecting
+  // to them and clicking the close button. Close the tab frontends first
+  // in case one of them is debugging a docked frontend, which would prevent
+  // the code from being able to connect to the docked one.
+  std::list<std::string> tab_frontend_ids;
+  std::list<std::string> docked_frontend_ids;
+  for (size_t i = 0; i < views_info.GetSize(); ++i) {
+    const WebViewInfo& view_info = views_info.Get(i);
+    if (view_info.IsFrontend()) {
+      if (view_info.type == WebViewInfo::kPage)
+        tab_frontend_ids.push_back(view_info.id);
+      else if (view_info.type == WebViewInfo::kOther)
+        docked_frontend_ids.push_back(view_info.id);
+      else
+        return Status(kUnknownError, "unknown type of DevTools frontend");
+    }
+  }
+
+  for (std::list<std::string>::const_iterator it = tab_frontend_ids.begin();
+       it != tab_frontend_ids.end(); ++it) {
+    status = CloseWebView(*it);
+    if (status.IsError())
+      return status;
+  }
+
+  for (std::list<std::string>::const_iterator it = docked_frontend_ids.begin();
+       it != docked_frontend_ids.end(); ++it) {
+    std::unique_ptr<DevToolsClient> client(new DevToolsClientImpl(
+        *it, "", devtools_http_client_->endpoint().GetDebuggerUrl(*it),
+        socket_factory_));
+    std::unique_ptr<WebViewImpl> web_view(new WebViewImpl(
+        *it, false, nullptr, devtools_http_client_->browser_info(),
+        std::move(client), nullptr, page_load_strategy_));
+
+    status = web_view->ConnectIfNecessary();
+    // Ignore disconnected error, because the debugger might have closed when
+    // its container page was closed above.
+    if (status.IsError() && status.code() != kDisconnected)
+      return status;
+
+    status = CloseWebView(*it);
+    // Ignore disconnected error, because it may be closed already.
+    if (status.IsError() && status.code() != kDisconnected)
+      return status;
+  }
+
+  // Wait until DevTools UI disconnects from the given web view.
+  base::TimeTicks deadline = base::TimeTicks::Now() + base::Seconds(20);
+  while (base::TimeTicks::Now() < deadline) {
+    status = devtools_http_client_->GetWebViewsInfo(&views_info);
+    if (status.IsError())
+      return status;
+
+    const WebViewInfo* view_info = views_info.GetForId(for_client_id);
+    if (!view_info)
+      return Status(kNoSuchWindow, "window was already closed");
+    if (view_info->debugger_url.size())
+      return Status(kOk);
+
+    base::PlatformThread::Sleep(base::Milliseconds(50));
+  }
+  return Status(kUnknownError, "failed to close UI debuggers");
+}
+
 Status ChromeImpl::GetWindow(const std::string& target_id, Window* window) {
   Status status = devtools_websocket_client_->ConnectIfNecessary();
   if (status.IsError())
@@ -470,15 +558,26 @@
 }
 
 Status ChromeImpl::CloseWebView(const std::string& id) {
-  Status status = devtools_http_client_->CloseWebView(id);
+  Status status = devtools_websocket_client_->ConnectIfNecessary();
+  if (status.IsError()) {
+    return status;
+  }
+
+  base::Value params{base::Value::Type::DICT};
+  params.GetDict().Set("targetId", id);
+  status = devtools_websocket_client_->SendCommand(
+      "Target.closeTarget", base::Value::AsDictionaryValue(params));
+
   if (status.IsError())
     return status;
-  for (auto iter = web_views_.begin(); iter != web_views_.end(); ++iter) {
-    if ((*iter)->GetId() == id) {
-      web_views_.erase(iter);
-      break;
-    }
+
+  auto it =
+      std::find_if(web_views_.begin(), web_views_.end(),
+                   [&id](const auto& view) { return view->GetId() == id; });
+  if (it != web_views_.end()) {
+    web_views_.erase(it);
   }
+
   return Status(kOk);
 }
 
@@ -487,7 +586,17 @@
   GetWebViewById(id, &webview);
   if (webview && webview->IsServiceWorker())
     return Status(kOk);
-  return devtools_http_client_->ActivateWebView(id);
+
+  Status status = devtools_websocket_client_->ConnectIfNecessary();
+  if (status.IsError()) {
+    return status;
+  }
+
+  base::Value params{base::Value::Type::DICT};
+  params.GetDict().Set("targetId", id);
+  status = devtools_websocket_client_->SendCommand(
+      "Target.activateTarget", base::Value::AsDictionaryValue(params));
+  return status;
 }
 
 Status ChromeImpl::SetAcceptInsecureCerts() {
@@ -557,8 +666,11 @@
                        std::unique_ptr<DevToolsClient> websocket_client,
                        std::vector<std::unique_ptr<DevToolsEventListener>>
                            devtools_event_listeners,
+                       std::unique_ptr<DeviceMetrics> device_metrics,
+                       SyncWebSocketFactory socket_factory,
                        std::string page_load_strategy)
-    : quit_(false),
+    : device_metrics_(std::move(device_metrics)),
+      socket_factory_(std::move(socket_factory)),
       devtools_http_client_(std::move(http_client)),
       devtools_websocket_client_(std::move(websocket_client)),
       devtools_event_listeners_(std::move(devtools_event_listeners)),
diff --git a/chrome/test/chromedriver/chrome/chrome_impl.h b/chrome/test/chromedriver/chrome/chrome_impl.h
index 834d3255..1aa4957a 100644
--- a/chrome/test/chromedriver/chrome/chrome_impl.h
+++ b/chrome/test/chromedriver/chrome/chrome_impl.h
@@ -12,8 +12,8 @@
 
 #include "base/values.h"
 #include "chrome/test/chromedriver/chrome/chrome.h"
+#include "chrome/test/chromedriver/net/sync_websocket_factory.h"
 
-struct BrowserInfo;
 class DevToolsClient;
 class DevToolsEventListener;
 class DevToolsHttpClient;
@@ -21,6 +21,8 @@
 class WebView;
 class WebViewImpl;
 class WebViewsInfo;
+struct BrowserInfo;
+struct DeviceMetrics;
 
 class ChromeImpl : public Chrome {
  public:
@@ -61,10 +63,15 @@
              std::unique_ptr<DevToolsClient> websocket_client,
              std::vector<std::unique_ptr<DevToolsEventListener>>
                  devtools_event_listeners,
+             std::unique_ptr<DeviceMetrics> device_metrics,
+             SyncWebSocketFactory socket_factory,
              std::string page_load_strategy);
 
   virtual Status QuitImpl() = 0;
 
+  std::unique_ptr<DevToolsClient> CreateClient(const std::string& id);
+  Status CloseFrontends(const std::string& for_client_id);
+
   struct Window {
     int id;
     std::string state;
@@ -81,7 +88,9 @@
                          const std::string& target_id,
                          std::unique_ptr<base::DictionaryValue> bounds);
 
-  bool quit_;
+  bool quit_ = false;
+  std::unique_ptr<DeviceMetrics> device_metrics_;
+  SyncWebSocketFactory socket_factory_;
   std::unique_ptr<DevToolsHttpClient> devtools_http_client_;
   std::unique_ptr<DevToolsClient> devtools_websocket_client_;
 
diff --git a/chrome/test/chromedriver/chrome/chrome_remote_impl.cc b/chrome/test/chromedriver/chrome/chrome_remote_impl.cc
index 9c4547b..4154d9e 100644
--- a/chrome/test/chromedriver/chrome/chrome_remote_impl.cc
+++ b/chrome/test/chromedriver/chrome/chrome_remote_impl.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "chrome/test/chromedriver/chrome/device_metrics.h"
 #include "chrome/test/chromedriver/chrome/devtools_client.h"
 #include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
 #include "chrome/test/chromedriver/chrome/devtools_http_client.h"
@@ -16,10 +17,14 @@
     std::unique_ptr<DevToolsClient> websocket_client,
     std::vector<std::unique_ptr<DevToolsEventListener>>
         devtools_event_listeners,
+    std::unique_ptr<DeviceMetrics> device_metrics,
+    SyncWebSocketFactory socket_factory,
     std::string page_load_strategy)
     : ChromeImpl(std::move(http_client),
                  std::move(websocket_client),
                  std::move(devtools_event_listeners),
+                 std::move(device_metrics),
+                 std::move(socket_factory),
                  page_load_strategy) {}
 
 ChromeRemoteImpl::~ChromeRemoteImpl() {}
diff --git a/chrome/test/chromedriver/chrome/chrome_remote_impl.h b/chrome/test/chromedriver/chrome/chrome_remote_impl.h
index 5abbe9d..1c081a0 100644
--- a/chrome/test/chromedriver/chrome/chrome_remote_impl.h
+++ b/chrome/test/chromedriver/chrome/chrome_remote_impl.h
@@ -9,9 +9,11 @@
 #include <string>
 
 #include "chrome/test/chromedriver/chrome/chrome_impl.h"
+#include "chrome/test/chromedriver/net/sync_websocket_factory.h"
 
 class DevToolsClient;
 class DevToolsHttpClient;
+struct DeviceMetrics;
 
 class ChromeRemoteImpl : public ChromeImpl {
  public:
@@ -19,6 +21,8 @@
                    std::unique_ptr<DevToolsClient> websocket_client,
                    std::vector<std::unique_ptr<DevToolsEventListener>>
                        devtools_event_listeners,
+                   std::unique_ptr<DeviceMetrics> device_metrics,
+                   SyncWebSocketFactory socket_factory,
                    std::string page_load_strategy);
   ~ChromeRemoteImpl() override;
 
diff --git a/chrome/test/chromedriver/chrome/devtools_endpoint.cc b/chrome/test/chromedriver/chrome/devtools_endpoint.cc
index 9bba6b5..85de9db 100644
--- a/chrome/test/chromedriver/chrome/devtools_endpoint.cc
+++ b/chrome/test/chromedriver/chrome/devtools_endpoint.cc
@@ -52,7 +52,3 @@
 std::string DevToolsEndpoint::GetCloseUrl(const std::string& id) const {
   return server_url_.Resolve("json/close/" + id).spec();
 }
-
-std::string DevToolsEndpoint::GetActivateUrl(const std::string& id) const {
-  return server_url_.Resolve("json/activate/" + id).spec();
-}
diff --git a/chrome/test/chromedriver/chrome/devtools_endpoint.h b/chrome/test/chromedriver/chrome/devtools_endpoint.h
index 702447b7..a446abd 100644
--- a/chrome/test/chromedriver/chrome/devtools_endpoint.h
+++ b/chrome/test/chromedriver/chrome/devtools_endpoint.h
@@ -26,7 +26,6 @@
   std::string GetVersionUrl() const;
   std::string GetListUrl() const;
   std::string GetCloseUrl(const std::string& id) const;
-  std::string GetActivateUrl(const std::string& id) const;
 
  private:
   GURL server_url_;
diff --git a/chrome/test/chromedriver/chrome/devtools_endpoint_unittest.cc b/chrome/test/chromedriver/chrome/devtools_endpoint_unittest.cc
index b138095..93d366b 100644
--- a/chrome/test/chromedriver/chrome/devtools_endpoint_unittest.cc
+++ b/chrome/test/chromedriver/chrome/devtools_endpoint_unittest.cc
@@ -24,8 +24,6 @@
   ASSERT_EQ(endpoint.GetListUrl(), "http://localhost:9999/json/list");
   ASSERT_EQ(endpoint.GetCloseUrl("xyz"),
             "http://localhost:9999/json/close/xyz");
-  ASSERT_EQ(endpoint.GetActivateUrl("xyz"),
-            "http://localhost:9999/json/activate/xyz");
 }
 
 TEST(DevToolsEndpoint, FromNetAddress) {
@@ -40,8 +38,6 @@
   ASSERT_EQ(endpoint.GetListUrl(), "http://localhost:9222/json/list");
   ASSERT_EQ(endpoint.GetCloseUrl("xyz"),
             "http://localhost:9222/json/close/xyz");
-  ASSERT_EQ(endpoint.GetActivateUrl("xyz"),
-            "http://localhost:9222/json/activate/xyz");
 }
 
 TEST(DevToolsEndpoint, FromHttpUrl) {
@@ -58,8 +54,6 @@
   ASSERT_EQ(endpoint.GetListUrl(), "http://remote:9223/custom/path/json/list");
   ASSERT_EQ(endpoint.GetCloseUrl("xyz"),
             "http://remote:9223/custom/path/json/close/xyz");
-  ASSERT_EQ(endpoint.GetActivateUrl("xyz"),
-            "http://remote:9223/custom/path/json/activate/xyz");
 }
 
 TEST(DevToolsEndpoint, FromHttpsUrl) {
@@ -76,6 +70,4 @@
   ASSERT_EQ(endpoint.GetListUrl(), "https://secure:9224/custom/path/json/list");
   ASSERT_EQ(endpoint.GetCloseUrl("xyz"),
             "https://secure:9224/custom/path/json/close/xyz");
-  ASSERT_EQ(endpoint.GetActivateUrl("xyz"),
-            "https://secure:9224/custom/path/json/activate/xyz");
 }
diff --git a/chrome/test/chromedriver/chrome/devtools_http_client.cc b/chrome/test/chromedriver/chrome/devtools_http_client.cc
index 45e5a95..439425b 100644
--- a/chrome/test/chromedriver/chrome/devtools_http_client.cc
+++ b/chrome/test/chromedriver/chrome/devtools_http_client.cc
@@ -15,11 +15,9 @@
 #include "base/threading/platform_thread.h"
 #include "base/time/time.h"
 #include "base/values.h"
-#include "chrome/test/chromedriver/chrome/device_metrics.h"
 #include "chrome/test/chromedriver/chrome/devtools_client_impl.h"
 #include "chrome/test/chromedriver/chrome/log.h"
 #include "chrome/test/chromedriver/chrome/status.h"
-#include "chrome/test/chromedriver/chrome/web_view_impl.h"
 #include "chrome/test/chromedriver/net/net_util.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
 
@@ -67,16 +65,10 @@
 DevToolsHttpClient::DevToolsHttpClient(
     const DevToolsEndpoint& endpoint,
     network::mojom::URLLoaderFactory* factory,
-    const SyncWebSocketFactory& socket_factory,
-    std::unique_ptr<DeviceMetrics> device_metrics,
-    std::unique_ptr<std::set<WebViewInfo::Type>> window_types,
-    std::string page_load_strategy)
+    std::unique_ptr<std::set<WebViewInfo::Type>> window_types)
     : url_loader_factory_(factory),
-      socket_factory_(socket_factory),
       endpoint_(endpoint),
-      device_metrics_(std::move(device_metrics)),
-      window_types_(std::move(window_types)),
-      page_load_strategy_(page_load_strategy) {
+      window_types_(std::move(window_types)) {
   window_types_->insert(WebViewInfo::kPage);
   window_types_->insert(WebViewInfo::kApp);
 }
@@ -111,127 +103,17 @@
   return internal::ParseWebViewsInfo(data, views_info);
 }
 
-std::unique_ptr<DevToolsClient> DevToolsHttpClient::CreateClient(
-    const std::string& id) {
-  auto result = std::make_unique<DevToolsClientImpl>(
-      id, "", endpoint_.GetDebuggerUrl(id), socket_factory_);
-  result->SetFrontendCloserFunc(base::BindRepeating(
-      &DevToolsHttpClient::CloseFrontends, base::Unretained(this), id));
-  return result;
-}
-
-Status DevToolsHttpClient::CloseWebView(const std::string& id) {
-  std::string data;
-  if (!FetchUrlAndLog(endpoint_.GetCloseUrl(id), &data)) {
-    return Status(kOk);  // Closing the last web view leads chrome to quit.
-  }
-
-  // Wait for the target window to be completely closed.
-  base::TimeTicks deadline = base::TimeTicks::Now() + base::Seconds(20);
-  while (base::TimeTicks::Now() < deadline) {
-    WebViewsInfo views_info;
-    Status status = GetWebViewsInfo(&views_info);
-    if (status.code() == kChromeNotReachable)
-      return Status(kOk);
-    if (status.IsError())
-      return status;
-    if (!views_info.GetForId(id))
-      return Status(kOk);
-    base::PlatformThread::Sleep(base::Milliseconds(50));
-  }
-  return Status(kUnknownError, "failed to close window in 20 seconds");
-}
-
-Status DevToolsHttpClient::ActivateWebView(const std::string& id) {
-  std::string data;
-  if (!FetchUrlAndLog(endpoint_.GetActivateUrl(id), &data))
-    return Status(kUnknownError, "cannot activate web view");
-  return Status(kOk);
-}
-
 const BrowserInfo* DevToolsHttpClient::browser_info() {
   return &browser_info_;
 }
 
-const DeviceMetrics* DevToolsHttpClient::device_metrics() {
-  return device_metrics_.get();
-}
-
 bool DevToolsHttpClient::IsBrowserWindow(const WebViewInfo& view) const {
   return base::Contains(*window_types_, view.type) ||
          (view.type == WebViewInfo::kOther && view.url == "chrome://print/");
 }
 
-Status DevToolsHttpClient::CloseFrontends(const std::string& for_client_id) {
-  WebViewsInfo views_info;
-  Status status = GetWebViewsInfo(&views_info);
-  if (status.IsError())
-    return status;
-
-  // Close frontends. Usually frontends are docked in the same page, although
-  // some may be in tabs (undocked, chrome://inspect, the DevTools
-  // discovery page, etc.). Tabs can be closed via the DevTools HTTP close
-  // URL, but docked frontends can only be closed, by design, by connecting
-  // to them and clicking the close button. Close the tab frontends first
-  // in case one of them is debugging a docked frontend, which would prevent
-  // the code from being able to connect to the docked one.
-  std::list<std::string> tab_frontend_ids;
-  std::list<std::string> docked_frontend_ids;
-  for (size_t i = 0; i < views_info.GetSize(); ++i) {
-    const WebViewInfo& view_info = views_info.Get(i);
-    if (view_info.IsFrontend()) {
-      if (view_info.type == WebViewInfo::kPage)
-        tab_frontend_ids.push_back(view_info.id);
-      else if (view_info.type == WebViewInfo::kOther)
-        docked_frontend_ids.push_back(view_info.id);
-      else
-        return Status(kUnknownError, "unknown type of DevTools frontend");
-    }
-  }
-
-  for (std::list<std::string>::const_iterator it = tab_frontend_ids.begin();
-       it != tab_frontend_ids.end(); ++it) {
-    status = CloseWebView(*it);
-    if (status.IsError())
-      return status;
-  }
-
-  for (std::list<std::string>::const_iterator it = docked_frontend_ids.begin();
-       it != docked_frontend_ids.end(); ++it) {
-    std::unique_ptr<DevToolsClient> client(new DevToolsClientImpl(
-        *it, "", endpoint_.GetDebuggerUrl(*it), socket_factory_));
-    std::unique_ptr<WebViewImpl> web_view(
-        new WebViewImpl(*it, false, nullptr, &browser_info_, std::move(client),
-                        nullptr, page_load_strategy_));
-
-    status = web_view->ConnectIfNecessary();
-    // Ignore disconnected error, because the debugger might have closed when
-    // its container page was closed above.
-    if (status.IsError() && status.code() != kDisconnected)
-      return status;
-
-    status = CloseWebView(*it);
-    // Ignore disconnected error, because it may be closed already.
-    if (status.IsError() && status.code() != kDisconnected)
-      return status;
-  }
-
-  // Wait until DevTools UI disconnects from the given web view.
-  base::TimeTicks deadline = base::TimeTicks::Now() + base::Seconds(20);
-  while (base::TimeTicks::Now() < deadline) {
-    status = GetWebViewsInfo(&views_info);
-    if (status.IsError())
-      return status;
-
-    const WebViewInfo* view_info = views_info.GetForId(for_client_id);
-    if (!view_info)
-      return Status(kNoSuchWindow, "window was already closed");
-    if (view_info->debugger_url.size())
-      return Status(kOk);
-
-    base::PlatformThread::Sleep(base::Milliseconds(50));
-  }
-  return Status(kUnknownError, "failed to close UI debuggers");
+const DevToolsEndpoint& DevToolsHttpClient::endpoint() const {
+  return endpoint_;
 }
 
 bool DevToolsHttpClient::FetchUrlAndLog(const std::string& url,
diff --git a/chrome/test/chromedriver/chrome/devtools_http_client.h b/chrome/test/chromedriver/chrome/devtools_http_client.h
index 7b74380..11515d3 100644
--- a/chrome/test/chromedriver/chrome/devtools_http_client.h
+++ b/chrome/test/chromedriver/chrome/devtools_http_client.h
@@ -16,7 +16,6 @@
 #include "base/memory/ref_counted.h"
 #include "chrome/test/chromedriver/chrome/browser_info.h"
 #include "chrome/test/chromedriver/chrome/devtools_endpoint.h"
-#include "chrome/test/chromedriver/net/sync_websocket_factory.h"
 
 namespace base {
 class TimeDelta;
@@ -28,8 +27,6 @@
 }
 }  // namespace network
 
-struct DeviceMetrics;
-class DevToolsClient;
 class Status;
 
 struct WebViewInfo {
@@ -81,10 +78,7 @@
  public:
   DevToolsHttpClient(const DevToolsEndpoint& endpoint,
                      network::mojom::URLLoaderFactory* factory,
-                     const SyncWebSocketFactory& socket_factory,
-                     std::unique_ptr<DeviceMetrics> device_metrics,
-                     std::unique_ptr<std::set<WebViewInfo::Type>> window_types,
-                     std::string page_load_strategy);
+                     std::unique_ptr<std::set<WebViewInfo::Type>> window_types);
 
   DevToolsHttpClient(const DevToolsHttpClient&) = delete;
   DevToolsHttpClient& operator=(const DevToolsHttpClient&) = delete;
@@ -95,27 +89,17 @@
 
   Status GetWebViewsInfo(WebViewsInfo* views_info);
 
-  std::unique_ptr<DevToolsClient> CreateClient(const std::string& id);
-
-  Status CloseWebView(const std::string& id);
-
-  Status ActivateWebView(const std::string& id);
-
   const BrowserInfo* browser_info();
-  const DeviceMetrics* device_metrics();
   bool IsBrowserWindow(const WebViewInfo& view) const;
+  const DevToolsEndpoint& endpoint() const;
 
  private:
-  Status CloseFrontends(const std::string& for_client_id);
   virtual bool FetchUrlAndLog(const std::string& url, std::string* response);
 
   raw_ptr<network::mojom::URLLoaderFactory> url_loader_factory_;
-  SyncWebSocketFactory socket_factory_;
   DevToolsEndpoint endpoint_;
   BrowserInfo browser_info_;
-  std::unique_ptr<DeviceMetrics> device_metrics_;
   std::unique_ptr<std::set<WebViewInfo::Type>> window_types_;
-  std::string page_load_strategy_;
 };
 
 Status ParseType(const std::string& data, WebViewInfo::Type* type);
diff --git a/chrome/test/chromedriver/chrome_launcher.cc b/chrome/test/chromedriver/chrome_launcher.cc
index 756410a..d29a628 100644
--- a/chrome/test/chromedriver/chrome_launcher.cc
+++ b/chrome/test/chromedriver/chrome_launcher.cc
@@ -234,19 +234,12 @@
 Status WaitForDevToolsAndCheckVersion(
     const DevToolsEndpoint& endpoint,
     network::mojom::URLLoaderFactory* factory,
-    const SyncWebSocketFactory& socket_factory,
     const Capabilities* capabilities,
     int wait_time,
     std::unique_ptr<DevToolsHttpClient>* user_client,
     bool* retry,
     ChromeType ct,
     std::string fp = "") {
-  std::unique_ptr<DeviceMetrics> device_metrics;
-  if (capabilities && capabilities->device_metrics) {
-    device_metrics =
-        std::make_unique<DeviceMetrics>(*capabilities->device_metrics);
-  }
-
   std::unique_ptr<std::set<WebViewInfo::Type>> window_types;
   if (capabilities && !capabilities->window_types.empty()) {
     window_types = std::make_unique<std::set<WebViewInfo::Type>>(
@@ -262,13 +255,10 @@
         cmd_line->GetSwitchValueNative("devtools-replay");
     base::FilePath log_file_path(log_path);
     client = std::make_unique<ReplayHttpClient>(
-        endpoint, factory, socket_factory, std::move(device_metrics),
-        std::move(window_types), capabilities->page_load_strategy,
-        log_file_path);
+        endpoint, factory, std::move(window_types), log_file_path);
   } else {
-    client = std::make_unique<DevToolsHttpClient>(
-        endpoint, factory, socket_factory, std::move(device_metrics),
-        std::move(window_types), capabilities->page_load_strategy);
+    client = std::make_unique<DevToolsHttpClient>(endpoint, factory,
+                                                  std::move(window_types));
   }
 
   const base::TimeTicks initial = base::TimeTicks::Now();
@@ -387,8 +377,8 @@
   std::unique_ptr<DevToolsHttpClient> devtools_http_client;
   bool retry = true;
   status = WaitForDevToolsAndCheckVersion(
-      DevToolsEndpoint(capabilities.debugger_address), factory, socket_factory,
-      &capabilities, 60, &devtools_http_client, &retry, ChromeType::Remote);
+      DevToolsEndpoint(capabilities.debugger_address), factory, &capabilities,
+      60, &devtools_http_client, &retry, ChromeType::Remote);
   if (status.IsError()) {
     return Status(
         kUnknownError,
@@ -409,9 +399,16 @@
                  << status.message();
   }
 
+  std::unique_ptr<DeviceMetrics> device_metrics;
+  if (capabilities.device_metrics) {
+    device_metrics =
+        std::make_unique<DeviceMetrics>(*capabilities.device_metrics);
+  }
+
   *chrome = std::make_unique<ChromeRemoteImpl>(
       std::move(devtools_http_client), std::move(devtools_websocket_client),
-      std::move(devtools_event_listeners), capabilities.page_load_strategy);
+      std::move(devtools_event_listeners), std::move(device_metrics),
+      socket_factory, capabilities.page_load_strategy);
   return Status(kOk);
 }
 
@@ -592,9 +589,8 @@
       std::ostringstream oss;
       oss << command.GetProgram();
       status = WaitForDevToolsAndCheckVersion(
-          DevToolsEndpoint(devtools_port), factory, socket_factory,
-          &capabilities, 1, &devtools_http_client, &retry, ChromeType::Desktop,
-          oss.str());
+          DevToolsEndpoint(devtools_port), factory, &capabilities, 1,
+          &devtools_http_client, &retry, ChromeType::Desktop, oss.str());
       if (!retry) {
         break;
       }
@@ -668,11 +664,18 @@
                  << status.message();
   }
 
+  std::unique_ptr<DeviceMetrics> device_metrics;
+  if (capabilities.device_metrics) {
+    device_metrics =
+        std::make_unique<DeviceMetrics>(*capabilities.device_metrics);
+  }
+
   std::unique_ptr<ChromeDesktopImpl> chrome_desktop =
       std::make_unique<ChromeDesktopImpl>(
           std::move(devtools_http_client), std::move(devtools_websocket_client),
-          std::move(devtools_event_listeners), capabilities.page_load_strategy,
-          std::move(process), command, &user_data_dir_temp_dir, &extension_dir,
+          std::move(devtools_event_listeners), std::move(device_metrics),
+          socket_factory, capabilities.page_load_strategy, std::move(process),
+          command, &user_data_dir_temp_dir, &extension_dir,
           capabilities.network_emulation_enabled);
   if (!capabilities.extension_load_timeout.is_zero()) {
     for (size_t i = 0; i < extension_bg_pages.size(); ++i) {
@@ -737,8 +740,8 @@
   std::unique_ptr<DevToolsHttpClient> devtools_http_client;
   bool retry = true;
   status = WaitForDevToolsAndCheckVersion(
-      DevToolsEndpoint(devtools_port), factory, socket_factory, &capabilities,
-      60, &devtools_http_client, &retry, ChromeType::Android);
+      DevToolsEndpoint(devtools_port), factory, &capabilities, 60,
+      &devtools_http_client, &retry, ChromeType::Android);
   if (status.IsError()) {
     device->TearDown();
     return status;
@@ -755,10 +758,16 @@
                  << status.message();
   }
 
+  std::unique_ptr<DeviceMetrics> device_metrics;
+  if (capabilities.device_metrics) {
+    device_metrics =
+        std::make_unique<DeviceMetrics>(*capabilities.device_metrics);
+  }
+
   *chrome = std::make_unique<ChromeAndroidImpl>(
       std::move(devtools_http_client), std::move(devtools_websocket_client),
-      std::move(devtools_event_listeners), capabilities.page_load_strategy,
-      std::move(device));
+      std::move(devtools_event_listeners), std::move(device_metrics),
+      socket_factory, capabilities.page_load_strategy, std::move(device));
   return Status(kOk);
 }
 
@@ -792,8 +801,8 @@
   std::unique_ptr<DevToolsHttpClient> devtools_http_client;
   bool retry = true;
   status = WaitForDevToolsAndCheckVersion(
-      DevToolsEndpoint(0), factory, socket_factory, &capabilities, 1,
-      &devtools_http_client, &retry, ChromeType::Replay);
+      DevToolsEndpoint(0), factory, &capabilities, 1, &devtools_http_client,
+      &retry, ChromeType::Replay);
   if (status.IsError())
     return status;
   std::unique_ptr<DevToolsClient> devtools_websocket_client;
@@ -806,11 +815,19 @@
     LOG(WARNING) << "Browser-wide DevTools client failed to connect: "
                  << status.message();
   }
+
+  std::unique_ptr<DeviceMetrics> device_metrics;
+  if (capabilities.device_metrics) {
+    device_metrics =
+        std::make_unique<DeviceMetrics>(*capabilities.device_metrics);
+  }
+
   base::Process dummy_process;
   std::unique_ptr<ChromeDesktopImpl> chrome_impl =
       std::make_unique<ChromeReplayImpl>(
           std::move(devtools_http_client), std::move(devtools_websocket_client),
-          std::move(devtools_event_listeners), capabilities.page_load_strategy,
+          std::move(devtools_event_listeners), std::move(device_metrics),
+          socket_factory, capabilities.page_load_strategy,
           std::move(dummy_process), command, &user_data_dir_temp_dir,
           &extension_dir, capabilities.network_emulation_enabled);
 
diff --git a/chrome/test/chromedriver/log_replay/chrome_replay_impl.cc b/chrome/test/chromedriver/log_replay/chrome_replay_impl.cc
index 009ae6c..2d59b28d 100644
--- a/chrome/test/chromedriver/log_replay/chrome_replay_impl.cc
+++ b/chrome/test/chromedriver/log_replay/chrome_replay_impl.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 #include "chrome/test/chromedriver/log_replay/chrome_replay_impl.h"
 
+#include "chrome/test/chromedriver/chrome/device_metrics.h"
 #include "chrome/test/chromedriver/chrome/devtools_client.h"
 #include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
 #include "chrome/test/chromedriver/chrome/devtools_http_client.h"
@@ -13,6 +14,8 @@
     std::unique_ptr<DevToolsClient> websocket_client,
     std::vector<std::unique_ptr<DevToolsEventListener>>
         devtools_event_listeners,
+    std::unique_ptr<DeviceMetrics> device_metrics,
+    SyncWebSocketFactory socket_factory,
     std::string page_load_strategy,
     base::Process process,
     const base::CommandLine& command,
@@ -22,6 +25,8 @@
     : ChromeDesktopImpl(std::move(http_client),
                         std::move(websocket_client),
                         std::move(devtools_event_listeners),
+                        std::move(device_metrics),
+                        std::move(socket_factory),
                         page_load_strategy,
                         std::move(process),
                         command,
diff --git a/chrome/test/chromedriver/log_replay/chrome_replay_impl.h b/chrome/test/chromedriver/log_replay/chrome_replay_impl.h
index ab7e5cb0..087b4578 100644
--- a/chrome/test/chromedriver/log_replay/chrome_replay_impl.h
+++ b/chrome/test/chromedriver/log_replay/chrome_replay_impl.h
@@ -4,11 +4,14 @@
 #ifndef CHROME_TEST_CHROMEDRIVER_LOG_REPLAY_CHROME_REPLAY_IMPL_H_
 #define CHROME_TEST_CHROMEDRIVER_LOG_REPLAY_CHROME_REPLAY_IMPL_H_
 
+#include <memory>
 #include "chrome/test/chromedriver/chrome/chrome_desktop_impl.h"
+#include "chrome/test/chromedriver/chrome/device_metrics.h"
 
 class DevToolsClient;
 class DevToolsHttpClient;
 class Status;
+struct DeviceMetrics;
 
 // Same as ChromeDesktopImpl except that it completely ignores the existence
 // of the |process| passed into the constructor. This allows running Chrome
@@ -20,6 +23,8 @@
                    std::unique_ptr<DevToolsClient> websocket_client,
                    std::vector<std::unique_ptr<DevToolsEventListener>>
                        devtools_event_listeners,
+                   std::unique_ptr<DeviceMetrics> device_metrics,
+                   SyncWebSocketFactory socket_factory,
                    std::string page_load_strategy,
                    base::Process process,
                    const base::CommandLine& command,
diff --git a/chrome/test/chromedriver/log_replay/replay_http_client.cc b/chrome/test/chromedriver/log_replay/replay_http_client.cc
index 46718fc..3437c48 100644
--- a/chrome/test/chromedriver/log_replay/replay_http_client.cc
+++ b/chrome/test/chromedriver/log_replay/replay_http_client.cc
@@ -5,7 +5,6 @@
 
 #include <utility>
 
-#include "chrome/test/chromedriver/chrome/device_metrics.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
 #include "url/gurl.h"
 
@@ -22,17 +21,9 @@
 ReplayHttpClient::ReplayHttpClient(
     const DevToolsEndpoint& endpoint,
     network::mojom::URLLoaderFactory* factory,
-    const SyncWebSocketFactory& socket_factory,
-    std::unique_ptr<DeviceMetrics> device_metrics,
     std::unique_ptr<std::set<WebViewInfo::Type>> window_types,
-    std::string page_load_strategy,
     const base::FilePath& log_path)
-    : DevToolsHttpClient(endpoint,
-                         factory,
-                         socket_factory,
-                         std::move(device_metrics),
-                         std::move(window_types),
-                         page_load_strategy),
+    : DevToolsHttpClient(endpoint, factory, std::move(window_types)),
       log_reader_(log_path) {}
 ReplayHttpClient::~ReplayHttpClient() {}
 
diff --git a/chrome/test/chromedriver/log_replay/replay_http_client.h b/chrome/test/chromedriver/log_replay/replay_http_client.h
index b714f7d9..9f114acc 100644
--- a/chrome/test/chromedriver/log_replay/replay_http_client.h
+++ b/chrome/test/chromedriver/log_replay/replay_http_client.h
@@ -29,10 +29,7 @@
   // Initializes a DevToolsLogReader with the given log file.
   ReplayHttpClient(const DevToolsEndpoint& endpoint,
                    network::mojom::URLLoaderFactory* factory,
-                   const SyncWebSocketFactory& socket_factory,
-                   std::unique_ptr<DeviceMetrics> device_metrics,
                    std::unique_ptr<std::set<WebViewInfo::Type>> window_types,
-                   std::string page_load_strategy,
                    const base::FilePath& log_file);
   ~ReplayHttpClient() override;
 
diff --git a/chrome/test/data/extensions/api_test/autotest_private/test.js b/chrome/test/data/extensions/api_test/autotest_private/test.js
index 3178dfbf..b1d7ecb4 100644
--- a/chrome/test/data/extensions/api_test/autotest_private/test.js
+++ b/chrome/test/data/extensions/api_test/autotest_private/test.js
@@ -1527,6 +1527,9 @@
         chrome.test.assertEq(1, apps.length)
         chrome.test.assertEq('OSSettings', apps[0].internalName);
         chrome.test.assertEq('chrome://test-system-app/', apps[0].url);
+        chrome.test.assertEq('chrome://test-system-app/pwa.html',
+            apps[0].startUrl);
+        chrome.test.assertEq('Test System App', apps[0].name);
       })
     );
   },
diff --git a/chrome/test/data/webui/settings/chromeos/internet_detail_page_tests.js b/chrome/test/data/webui/settings/chromeos/internet_detail_page_tests.js
index 79e8998..2986d511 100644
--- a/chrome/test/data/webui/settings/chromeos/internet_detail_page_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/internet_detail_page_tests.js
@@ -139,7 +139,6 @@
   setup(function() {
     loadTimeData.overrideValues({
       esimPolicyEnabled: true,
-      extendedOpenVpnSettingsEnabled: true,
       internetAddConnection: 'internetAddConnection',
       internetAddConnectionExpandA11yLabel:
           'internetAddConnectionExpandA11yLabel',
diff --git a/chromeos/components/mojo_service_manager/connection.cc b/chromeos/components/mojo_service_manager/connection.cc
index 914d57d2..7aa844b 100644
--- a/chromeos/components/mojo_service_manager/connection.cc
+++ b/chromeos/components/mojo_service_manager/connection.cc
@@ -9,11 +9,19 @@
 #include <sys/un.h>
 
 #include <cstdlib>
+#include <string>
 #include <utility>
 
+#include "base/bind.h"
 #include "base/check_op.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/no_destructor.h"
 #include "base/posix/eintr_wrapper.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "base/timer/elapsed_timer.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/platform/platform_channel.h"
 #include "mojo/public/cpp/system/invitation.h"
@@ -22,10 +30,24 @@
 namespace {
 
 // The socket path to connect to the service manager.
-constexpr char kServiceManagerSocketPath[] = "/run/mojo/service_manager";
+constexpr char kServiceManagerSocketPath[] = "/run/mojo/service_manager.sock";
 // The default mojo pipe name for bootstrap the mojo.
 constexpr int kDefaultMojoInvitationPipeName = 0;
 
+// The connection may fail if the socket is not exist or the permission is not
+// set to the right permission. This could happen if the ChromeOS mojo service
+// manager is starting. We may need to wait for a while and retry.
+//
+// TODO(b/234318452): Clean up this retry logic after we collect enough UMA
+// data.
+//
+// The retry interval of connecting to the service manager. It is expected that
+// normally the first retry should be able to perform the bootstrap on all
+// devices.
+constexpr base::TimeDelta kRetryInterval = base::Milliseconds(1);
+// The retry timeout of connecting to the service manager.
+constexpr base::TimeDelta kRetryTimeout = base::Seconds(5);
+
 base::ScopedFD ConnectToServiceManagerUnixSocket() {
   base::ScopedFD sock{socket(AF_UNIX, SOCK_STREAM, 0)};
   if (!sock.is_valid()) {
@@ -67,27 +89,61 @@
   return *instance;
 }
 
+// Sends the histogram to record the retry times of bootstrap.
+void SendBootsrapRetryTimesHistogram(int retry_times) {
+  // Note that sample will be 0 if didn't retry, and it will be in the underflow
+  // bucket.
+  base::UmaHistogramCustomCounts("Ash.MojoServiceManager.BootstrapRetryTimes",
+                                 retry_times, 1, 5000, 50);
+}
+
+// Sends the histogram to record whether the connection is lost during ash
+// running.
+void SendIsConnectionLostHistogram(bool is_connection_lost) {
+  base::UmaHistogramBoolean("Ash.MojoServiceManager.IsConnectionLost",
+                            is_connection_lost);
+}
+
+void OnDisconnect(uint32_t reason, const std::string& message) {
+  SendIsConnectionLostHistogram(true);
+  LOG(FATAL) << "Disconnecting from ChromeOS mojo service manager is "
+                "unexpected. Reason: "
+             << reason << ", message: " << message;
+}
+
 }  // namespace
 
 bool BootstrapServiceManagerConnection() {
   CHECK(!GetRemote().is_bound()) << "remote_ has already bound.";
-  mojo::PendingRemote<mojom::ServiceManager> remote =
-      ConnectToMojoServiceManager();
-  if (!remote.is_valid())
-    return false;
-  GetRemote().Bind(std::move(remote));
-  GetRemote().reset_on_disconnect();
-  return true;
+
+  // We block and sleep here because we assume that it doesn't need to retry at
+  // all.
+  int retry_times = 0;
+  for (base::ElapsedTimer timer; timer.Elapsed() < kRetryTimeout;
+       base::PlatformThread::Sleep(kRetryInterval), ++retry_times) {
+    mojo::PendingRemote<mojom::ServiceManager> remote =
+        ConnectToMojoServiceManager();
+    if (!remote.is_valid())
+      continue;
+    SendBootsrapRetryTimesHistogram(retry_times);
+    GetRemote().Bind(std::move(remote));
+    GetRemote().set_disconnect_with_reason_handler(
+        base::BindOnce(&OnDisconnect));
+    return true;
+  }
+  SendBootsrapRetryTimesHistogram(retry_times);
+  return false;
 }
 
 bool IsServiceManagerConnected() {
-  // Because reset_on_disconnect() is set, is_bound() will be the same as
-  // is_connected().
+  // is_bound() will be the same as is_connected() because we crash on
+  // disconnecting.
   DCHECK_EQ(GetRemote().is_bound(), GetRemote().is_connected());
   return GetRemote().is_bound();
 }
 
 void ResetServiceManagerConnection() {
+  SendIsConnectionLostHistogram(false);
   GetRemote().reset();
 }
 
@@ -99,7 +155,7 @@
     mojo::PendingRemote<mojom::ServiceManager> remote) {
   CHECK(remote.is_valid());
   GetRemote().Bind(std::move(remote));
-  GetRemote().reset_on_disconnect();
+  GetRemote().set_disconnect_with_reason_handler(base::BindOnce(&OnDisconnect));
 }
 
 }  // namespace chromeos::mojo_service_manager
diff --git a/chromeos/components/mojo_service_manager/connection.h b/chromeos/components/mojo_service_manager/connection.h
index 2cad8ec8..574a092 100644
--- a/chromeos/components/mojo_service_manager/connection.h
+++ b/chromeos/components/mojo_service_manager/connection.h
@@ -12,7 +12,10 @@
 namespace chromeos::mojo_service_manager {
 
 // Connects to the mojo service manager. Returns false if cannot connect.
-// This will will block until finishes.
+// This will will block until connects to the socket of service manager.
+// Note that the service manager also acts as the mojo broker process. Will
+// raise a |CHECK(false)| if the service manager disconnected unexpectedly,
+// because the mojo cannot work without a broker.
 COMPONENT_EXPORT(CHROMEOS_MOJO_SERVICE_MANAGER)
 bool BootstrapServiceManagerConnection();
 
diff --git a/chromeos/services/cros_healthd/private/cpp/data_collector.cc b/chromeos/services/cros_healthd/private/cpp/data_collector.cc
index 6af1068..f70a4367 100644
--- a/chromeos/services/cros_healthd/private/cpp/data_collector.cc
+++ b/chromeos/services/cros_healthd/private/cpp/data_collector.cc
@@ -14,7 +14,6 @@
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
-#include "mojo/public/cpp/bindings/receiver_set.h"
 #include "ui/events/devices/device_data_manager.h"
 #include "ui/events/ozone/evdev/event_device_info.h"
 
@@ -82,39 +81,6 @@
   return delegate.get();
 }
 
-class DataCollectorImpl : public DataCollector,
-                          public mojom::ChromiumDataCollector {
- public:
-  explicit DataCollectorImpl(Delegate* delegate);
-  DataCollectorImpl(const DataCollectorImpl&) = delete;
-  DataCollectorImpl& operator=(const DataCollectorImpl&) = delete;
-  ~DataCollectorImpl() override;
-
-  // DataCollector overrides.
-  void BindReceiver(
-      mojo::PendingReceiver<mojom::ChromiumDataCollector> receiver) override;
-
- private:
-  // mojom::ChromiumDataCollector overrides.
-  void GetTouchscreenDevices(GetTouchscreenDevicesCallback callback) override;
-  void GetTouchpadLibraryName(GetTouchpadLibraryNameCallback callback) override;
-
-  // Pointer to the delegate.
-  Delegate* const delegate_;
-  // The receiver set to keep the mojo receivers.
-  mojo::ReceiverSet<mojom::ChromiumDataCollector> receiver_set_;
-};
-
-DataCollectorImpl::DataCollectorImpl(Delegate* delegate)
-    : delegate_(delegate) {}
-
-DataCollectorImpl::~DataCollectorImpl() = default;
-
-void DataCollectorImpl::BindReceiver(
-    mojo::PendingReceiver<mojom::ChromiumDataCollector> receiver) {
-  receiver_set_.Add(this, std::move(receiver));
-}
-
 mojom::InputDevice::ConnectionType GetInputDeviceConnectionType(
     ui::InputDeviceType type) {
   switch (type) {
@@ -131,7 +97,7 @@
 
 void GetTouchscreenDevicesOnUIThread(
     scoped_refptr<base::SequencedTaskRunner> task_runner,
-    DataCollectorImpl::GetTouchscreenDevicesCallback callback) {
+    DataCollector::GetTouchscreenDevicesCallback callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   const std::vector<ui::TouchscreenDevice>& devices =
@@ -156,7 +122,20 @@
       FROM_HERE, base::BindOnce(std::move(callback), std::move(results)));
 }
 
-void DataCollectorImpl::GetTouchscreenDevices(
+};  // namespace
+
+DataCollector::DataCollector() : DataCollector(GetDataCollectorDelegate()) {}
+
+DataCollector::DataCollector(Delegate* delegate) : delegate_(delegate) {}
+
+DataCollector::~DataCollector() = default;
+
+mojo::PendingRemote<mojom::ChromiumDataCollector>
+DataCollector::BindNewPipeAndPassRemote() {
+  return receiver_.BindNewPipeAndPassRemote();
+}
+
+void DataCollector::GetTouchscreenDevices(
     GetTouchscreenDevicesCallback callback) {
   content::GetUIThreadTaskRunner({})->PostTask(
       FROM_HERE, base::BindOnce(&GetTouchscreenDevicesOnUIThread,
@@ -164,47 +143,11 @@
                                 std::move(callback)));
 }
 
-void DataCollectorImpl::GetTouchpadLibraryName(
+void DataCollector::GetTouchpadLibraryName(
     GetTouchpadLibraryNameCallback callback) {
   std::move(callback).Run(delegate_->GetTouchpadLibraryName());
 }
 
-// The pointer to the global instance.
-DataCollector* g_instance = nullptr;
-
-};  // namespace
-
-DataCollector::DataCollector() {
-  CHECK(!g_instance) << "Can have only one instance";
-  g_instance = this;
-}
-
-DataCollector::~DataCollector() {
-  CHECK_EQ(g_instance, this);
-  g_instance = nullptr;
-}
-
-// static
-void DataCollector::Initialize() {
-  new DataCollectorImpl(GetDataCollectorDelegate());
-}
-
-// static
-void DataCollector::InitializeWithDelegateForTesting(Delegate* delegate) {
-  new DataCollectorImpl(delegate);
-}
-
-// static
-void DataCollector::Shutdown() {
-  delete g_instance;
-}
-
-// static
-DataCollector* DataCollector::Get() {
-  CHECK(g_instance) << "Not initialized.";
-  return g_instance;
-}
-
 }  // namespace internal
 }  // namespace cros_healthd
 }  // namespace chromeos
diff --git a/chromeos/services/cros_healthd/private/cpp/data_collector.h b/chromeos/services/cros_healthd/private/cpp/data_collector.h
index 752939c..13cd8bc4 100644
--- a/chromeos/services/cros_healthd/private/cpp/data_collector.h
+++ b/chromeos/services/cros_healthd/private/cpp/data_collector.h
@@ -6,13 +6,13 @@
 #define CHROMEOS_SERVICES_CROS_HEALTHD_PRIVATE_CPP_DATA_COLLECTOR_H_
 
 #include "chromeos/services/cros_healthd/private/mojom/cros_healthd_internal.mojom.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 
 namespace chromeos {
 namespace cros_healthd {
 namespace internal {
 
-class DataCollector {
+class DataCollector : public mojom::ChromiumDataCollector {
  public:
   // Delegate class to be replaced for testing.
   class Delegate {
@@ -24,28 +24,24 @@
     virtual std::string GetTouchpadLibraryName() = 0;
   };
 
+  DataCollector();
+  DataCollector(Delegate* delegate);
   DataCollector(const DataCollector&) = delete;
   DataCollector& operator=(const DataCollector&) = delete;
+  ~DataCollector() override;
 
-  // Initialize a global instance.
-  static void Initialize();
+  // Binds new pipe and returns the mojo remote.
+  mojo::PendingRemote<mojom::ChromiumDataCollector> BindNewPipeAndPassRemote();
 
-  // Initialize a global instance with delegate for testing.
-  static void InitializeWithDelegateForTesting(Delegate* delegate);
+ private:
+  // mojom::ChromiumDataCollector overrides.
+  void GetTouchscreenDevices(GetTouchscreenDevicesCallback callback) override;
+  void GetTouchpadLibraryName(GetTouchpadLibraryNameCallback callback) override;
 
-  // Shutdown the global instance.
-  static void Shutdown();
-
-  // Returns the global instance. Check failed if this is not initialized.
-  static DataCollector* Get();
-
-  // Binds a mojo receiver to this.
-  virtual void BindReceiver(
-      mojo::PendingReceiver<mojom::ChromiumDataCollector> receiver) = 0;
-
- protected:
-  DataCollector();
-  virtual ~DataCollector();
+  // Pointer to the delegate.
+  Delegate* const delegate_;
+  // The mojo receiver.
+  mojo::Receiver<mojom::ChromiumDataCollector> receiver_{this};
 };
 
 }  // namespace internal
diff --git a/chromeos/services/cros_healthd/private/cpp/data_collector_unittest.cc b/chromeos/services/cros_healthd/private/cpp/data_collector_unittest.cc
index 912dd3b3..a6d5beb 100644
--- a/chromeos/services/cros_healthd/private/cpp/data_collector_unittest.cc
+++ b/chromeos/services/cros_healthd/private/cpp/data_collector_unittest.cc
@@ -33,15 +33,10 @@
  protected:
   void SetUp() override {
     ui::DeviceDataManager::CreateInstance();
-    DataCollector::InitializeWithDelegateForTesting(&delegate_);
-    DataCollector::Get()->BindReceiver(remote_.BindNewPipeAndPassReceiver());
+    remote_.Bind(data_collector_.BindNewPipeAndPassRemote());
   }
 
-  void TearDown() override {
-    remote_.reset();
-    DataCollector::Shutdown();
-    ui::DeviceDataManager::DeleteInstance();
-  }
+  void TearDown() override { ui::DeviceDataManager::DeleteInstance(); }
 
   // The test environment.
   content::BrowserTaskEnvironment env_;
@@ -49,6 +44,8 @@
   mojo::Remote<mojom::ChromiumDataCollector> remote_;
   // The fake delegate for DataCollector.
   FakeDataCollectorDelegate delegate_;
+  // The DataCollector.
+  DataCollector data_collector_{&delegate_};
 };
 
 TEST_F(DataCollectorTest, GetTouchscreenDevices) {
diff --git a/chromeos/services/cros_healthd/public/cpp/service_connection.cc b/chromeos/services/cros_healthd/public/cpp/service_connection.cc
index 3141b0d4f..7ec6d19 100644
--- a/chromeos/services/cros_healthd/public/cpp/service_connection.cc
+++ b/chromeos/services/cros_healthd/public/cpp/service_connection.cc
@@ -191,6 +191,10 @@
       BindNetworkHealthServiceCallback callback) override;
   void SetBindNetworkDiagnosticsRoutinesCallback(
       BindNetworkDiagnosticsRoutinesCallback callback) override;
+  void SendChromiumDataCollector(
+      mojo::PendingRemote<
+          chromeos::cros_healthd::internal::mojom::ChromiumDataCollector>
+          remote) override;
   std::string FetchTouchpadLibraryName() override;
   void FlushForTesting() override;
 
@@ -660,6 +664,15 @@
   BindAndSendNetworkDiagnosticsRoutines();
 }
 
+void ServiceConnectionImpl::SendChromiumDataCollector(
+    mojo::PendingRemote<
+        chromeos::cros_healthd::internal::mojom::ChromiumDataCollector>
+        remote) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  EnsureCrosHealthdServiceFactoryIsBound();
+  cros_healthd_service_factory_->SendChromiumDataCollector(std::move(remote));
+}
+
 // This is a short-term solution for ChromeOS Flex. We should remove this work
 // around after cros_healthd team develop a healthier input telemetry approach.
 std::string ServiceConnectionImpl::FetchTouchpadLibraryName() {
diff --git a/chromeos/services/cros_healthd/public/cpp/service_connection.h b/chromeos/services/cros_healthd/public/cpp/service_connection.h
index 17ef90f2..4bdb101 100644
--- a/chromeos/services/cros_healthd/public/cpp/service_connection.h
+++ b/chromeos/services/cros_healthd/public/cpp/service_connection.h
@@ -12,6 +12,7 @@
 
 #include "base/callback_forward.h"
 #include "base/time/time.h"
+#include "chromeos/services/cros_healthd/private/mojom/cros_healthd_internal.mojom.h"
 #include "chromeos/services/cros_healthd/public/mojom/cros_healthd.mojom.h"
 #include "chromeos/services/cros_healthd/public/mojom/cros_healthd_events.mojom.h"
 #include "chromeos/services/network_health/public/mojom/network_diagnostics.mojom.h"
@@ -370,6 +371,12 @@
   virtual void SetBindNetworkDiagnosticsRoutinesCallback(
       BindNetworkDiagnosticsRoutinesCallback callback) = 0;
 
+  // Sends the ChromiumDataCollector interface to cros_healthd.
+  virtual void SendChromiumDataCollector(
+      mojo::PendingRemote<
+          chromeos::cros_healthd::internal::mojom::ChromiumDataCollector>
+          remote) = 0;
+
   // Fetch touchpad stack driver library name.
   virtual std::string FetchTouchpadLibraryName() = 0;
 
diff --git a/chromeos/tast_control.gni b/chromeos/tast_control.gni
index 0fc65a3..574e01b 100644
--- a/chromeos/tast_control.gni
+++ b/chromeos/tast_control.gni
@@ -240,13 +240,6 @@
   "inputs.PhysicalKeyboardEmojiSuggestion",
   "inputs.PhysicalKeyboardEmojiSuggestion.guest",
   "inputs.PhysicalKeyboardEmojiSuggestion.incognito",
-
-  # crbug.com/1330605
-  "arc.StandardizedKeyboardTyping",
-  "arc.StandardizedKeyboardTyping.tablet_mode",
-
-  # https://crbug.com/1330519
-  "arc.PhysicalKeyboard",
 ]
 
 # To create filters to be used on specific builders add them like this:
diff --git a/components/browser_sync/sync_api_component_factory_impl.cc b/components/browser_sync/sync_api_component_factory_impl.cc
index 4083301..928e19cb 100644
--- a/components/browser_sync/sync_api_component_factory_impl.cc
+++ b/components/browser_sync/sync_api_component_factory_impl.cc
@@ -32,6 +32,7 @@
 #include "components/send_tab_to_self/features.h"
 #include "components/send_tab_to_self/send_tab_to_self_model_type_controller.h"
 #include "components/send_tab_to_self/send_tab_to_self_sync_service.h"
+#include "components/sync/base/features.h"
 #include "components/sync/base/legacy_directory_deletion.h"
 #include "components/sync/base/report_unrecoverable_error.h"
 #include "components/sync/base/sync_prefs.h"
@@ -254,7 +255,15 @@
     // provided by HistoryService.
     controllers.push_back(
         std::make_unique<history::TypedURLModelTypeController>(
-            sync_service, sync_client_->GetHistoryService(),
+            syncer::TYPED_URLS, sync_service, sync_client_->GetHistoryService(),
+            sync_client_->GetPrefService()));
+  }
+
+  if (!disabled_types.Has(syncer::HISTORY) &&
+      base::FeatureList::IsEnabled(syncer::kSyncEnableHistoryDataType)) {
+    controllers.push_back(
+        std::make_unique<history::TypedURLModelTypeController>(
+            syncer::HISTORY, sync_service, sync_client_->GetHistoryService(),
             sync_client_->GetPrefService()));
   }
 
diff --git a/components/exo/test/exo_test_suite_aura.cc b/components/exo/test/exo_test_suite_aura.cc
index e00ed4c..a3aa9d9 100644
--- a/components/exo/test/exo_test_suite_aura.cc
+++ b/components/exo/test/exo_test_suite_aura.cc
@@ -16,11 +16,11 @@
 
 void ExoTestSuiteAura::Initialize() {
   base::TestSuite::Initialize();
-  display_ = gl::GLSurfaceTestSupport::InitializeOneOff();
+  gl::GLSurfaceTestSupport::InitializeOneOff();
 }
 
 void ExoTestSuiteAura::Shutdown() {
-  gl::GLSurfaceTestSupport::ShutdownGL(display_);
+  gl::GLSurfaceTestSupport::ShutdownGL();
   base::TestSuite::Shutdown();
 }
 
diff --git a/components/exo/test/exo_test_suite_aura.h b/components/exo/test/exo_test_suite_aura.h
index 37cbbd7..8217346 100644
--- a/components/exo/test/exo_test_suite_aura.h
+++ b/components/exo/test/exo_test_suite_aura.h
@@ -6,7 +6,6 @@
 #define COMPONENTS_EXO_TEST_EXO_TEST_SUITE_AURA_H_
 
 #include "base/test/test_suite.h"
-#include "ui/gl/gl_display.h"
 
 namespace exo {
 namespace test {
@@ -28,9 +27,6 @@
   // base::TestSuite:
   void Initialize() override;
   void Shutdown() override;
-
- private:
-  gl::GLDisplay* display_ = nullptr;
 };
 
 }  // namespace test
diff --git a/components/history/core/browser/BUILD.gn b/components/history/core/browser/BUILD.gn
index 44df8d93..deab0cf 100644
--- a/components/history/core/browser/BUILD.gn
+++ b/components/history/core/browser/BUILD.gn
@@ -58,6 +58,8 @@
     "sync/history_delete_directives_model_type_controller.h",
     "sync/history_model_type_controller_helper.cc",
     "sync/history_model_type_controller_helper.h",
+    "sync/history_sync_bridge.cc",
+    "sync/history_sync_bridge.h",
     "sync/history_sync_metadata_database.cc",
     "sync/history_sync_metadata_database.h",
     "sync/typed_url_model_type_controller.cc",
diff --git a/components/history/core/browser/history_backend.cc b/components/history/core/browser/history_backend.cc
index 7864061..d3337b4 100644
--- a/components/history/core/browser/history_backend.cc
+++ b/components/history/core/browser/history_backend.cc
@@ -18,6 +18,7 @@
 #include "base/callback_helpers.h"
 #include "base/compiler_specific.h"
 #include "base/containers/flat_set.h"
+#include "base/feature_list.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -50,8 +51,10 @@
 #include "components/history/core/browser/in_memory_history_backend.h"
 #include "components/history/core/browser/keyword_search_term.h"
 #include "components/history/core/browser/page_usage_data.h"
+#include "components/history/core/browser/sync/history_sync_bridge.h"
 #include "components/history/core/browser/sync/typed_url_sync_bridge.h"
 #include "components/history/core/browser/url_utils.h"
+#include "components/sync/base/features.h"
 #include "components/sync/model/client_tag_based_model_type_processor.h"
 #include "components/url_formatter/url_formatter.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
@@ -319,6 +322,15 @@
           syncer::TYPED_URLS, /*dump_stack=*/base::RepeatingClosure()));
   typed_url_sync_bridge_->Init();
 
+  if (base::FeatureList::IsEnabled(syncer::kSyncEnableHistoryDataType)) {
+    // TODO(crbug.com/1318028): Plumb in syncer::ReportUnrecoverableError as the
+    // dump_stack callback.
+    history_sync_bridge_ = std::make_unique<HistorySyncBridge>(
+        this, db_ ? db_->GetHistoryMetadataDB() : nullptr,
+        std::make_unique<ClientTagBasedModelTypeProcessor>(
+            syncer::HISTORY, /*dump_stack=*/base::RepeatingClosure()));
+  }
+
   memory_pressure_listener_ = std::make_unique<base::MemoryPressureListener>(
       FROM_HERE, base::BindRepeating(&HistoryBackend::OnMemoryPressure,
                                      base::Unretained(this)));
@@ -1355,6 +1367,12 @@
   return typed_url_sync_bridge_->change_processor()->GetControllerDelegate();
 }
 
+base::WeakPtr<syncer::ModelTypeControllerDelegate>
+HistoryBackend::GetHistorySyncControllerDelegate() {
+  DCHECK(history_sync_bridge_);
+  return history_sync_bridge_->change_processor()->GetControllerDelegate();
+}
+
 // Statistics ------------------------------------------------------------------
 
 HistoryCountResult HistoryBackend::GetHistoryCount(const Time& begin_time,
@@ -2538,10 +2556,12 @@
   if (!db_)
     return;
 
-  // Notify SyncBridge about storage error. It will report failure to sync
-  // engine and stop accepting remote updates.
+  // Notify the sync bridges about storage error. They'll report failures to the
+  // sync engine and stop accepting remote updates.
   if (typed_url_sync_bridge_)
     typed_url_sync_bridge_->OnDatabaseError();
+  if (history_sync_bridge_)
+    history_sync_bridge_->OnDatabaseError();
 
   // Rollback transaction because Raze() cannot be called from within a
   // transaction.
diff --git a/components/history/core/browser/history_backend.h b/components/history/core/browser/history_backend.h
index b16adcf9..fe2ce69 100644
--- a/components/history/core/browser/history_backend.h
+++ b/components/history/core/browser/history_backend.h
@@ -65,6 +65,7 @@
 class HistoryDatabase;
 struct HistoryDatabaseParams;
 class HistoryDBTask;
+class HistorySyncBridge;
 class InMemoryHistoryBackend;
 class TypedURLSyncBridge;
 class URLDatabase;
@@ -539,6 +540,11 @@
   base::WeakPtr<syncer::ModelTypeControllerDelegate>
   GetTypedURLSyncControllerDelegate();
 
+  // Returns the sync controller delegate for syncing history. The returned
+  // delegate is owned by `this` object.
+  base::WeakPtr<syncer::ModelTypeControllerDelegate>
+  GetHistorySyncControllerDelegate();
+
   // Deleting ------------------------------------------------------------------
 
   void DeleteURLs(const std::vector<GURL>& urls);
@@ -866,9 +872,14 @@
   base::ObserverList<HistoryBackendObserver>::Unchecked observers_;
 
   // Used to manage syncing of the typed urls datatype. It will be null before
-  // HistoryBackend::Init is called. Defined after observers_ because
+  // HistoryBackend::Init() is called. Defined after `observers_` because
   // it unregisters itself as observer during destruction.
   std::unique_ptr<TypedURLSyncBridge> typed_url_sync_bridge_;
+
+  // Used to manage syncing of the history datatype. It will be null before
+  // HistoryBackend::Init() is called. Defined after `observers_` because
+  // it unregisters itself as observer during destruction.
+  std::unique_ptr<HistorySyncBridge> history_sync_bridge_;
 };
 
 }  // namespace history
diff --git a/components/history/core/browser/history_database.cc b/components/history/core/browser/history_database.cc
index 5cf6b84..5eb4b0f3 100644
--- a/components/history/core/browser/history_database.cc
+++ b/components/history/core/browser/history_database.cc
@@ -22,6 +22,7 @@
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
+#include "components/sync/base/features.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "sql/meta_table.h"
 #include "sql/statement.h"
@@ -93,7 +94,8 @@
            // value, tells us how much memory the cache will use maximum.
            // 1000 * 4kB = 4MB
            .cache_size = 1000}),
-      typed_url_metadata_db_(&db_, &meta_table_) {}
+      typed_url_metadata_db_(&db_, &meta_table_),
+      history_metadata_db_(&db_, &meta_table_) {}
 
 HistoryDatabase::~HistoryDatabase() = default;
 
@@ -127,6 +129,10 @@
       !InitVisitAnnotationsTables()) {
     return LogInitFailure(InitStep::CREATE_TABLES);
   }
+  if (base::FeatureList::IsEnabled(syncer::kSyncEnableHistoryDataType) &&
+      !history_metadata_db_.Init()) {
+    return LogInitFailure(InitStep::CREATE_TABLES);
+  }
   CreateMainURLIndex();
 
   // TODO(benjhayden) Remove at some point.
@@ -379,6 +385,10 @@
   return &typed_url_metadata_db_;
 }
 
+HistorySyncMetadataDatabase* HistoryDatabase::GetHistoryMetadataDB() {
+  return &history_metadata_db_;
+}
+
 sql::Database& HistoryDatabase::GetDB() {
   return db_;
 }
diff --git a/components/history/core/browser/history_database.h b/components/history/core/browser/history_database.h
index fd168499..f7a4340 100644
--- a/components/history/core/browser/history_database.h
+++ b/components/history/core/browser/history_database.h
@@ -12,6 +12,7 @@
 #include "build/build_config.h"
 #include "components/history/core/browser/download_database.h"
 #include "components/history/core/browser/history_types.h"
+#include "components/history/core/browser/sync/history_sync_metadata_database.h"
 #include "components/history/core/browser/sync/typed_url_sync_metadata_database.h"
 #include "components/history/core/browser/url_database.h"
 #include "components/history/core/browser/visit_annotations_database.h"
@@ -161,6 +162,9 @@
   // Returns the sub-database used for storing Sync metadata for Typed URLs.
   TypedURLSyncMetadataDatabase* GetTypedURLMetadataDB();
 
+  // Returns the sub-database used for storing Sync metadata for History.
+  HistorySyncMetadataDatabase* GetHistoryMetadataDB();
+
  private:
 #if BUILDFLAG(IS_ANDROID)
   // AndroidProviderBackend uses the `db_`.
@@ -197,8 +201,9 @@
   // Most of the sub-DBs (URLDatabase etc.) are integrated into HistoryDatabase
   // via inheritance. However, that can lead to "diamond inheritance" issues
   // when multiple of these base classes define the same methods. Therefore the
-  // Sync metadata DB is integrated via composition instead.
+  // Sync metadata DBs are integrated via composition instead.
   TypedURLSyncMetadataDatabase typed_url_metadata_db_;
+  HistorySyncMetadataDatabase history_metadata_db_;
 
   base::Time cached_early_expiration_threshold_;
 };
diff --git a/components/history/core/browser/history_service.cc b/components/history/core/browser/history_service.cc
index a9977e4..ce9cdaf 100644
--- a/components/history/core/browser/history_service.cc
+++ b/components/history/core/browser/history_service.cc
@@ -1184,6 +1184,18 @@
                           base::Unretained(history_backend_.get())));
 }
 
+std::unique_ptr<syncer::ModelTypeControllerDelegate>
+HistoryService::GetHistorySyncControllerDelegate() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // Note that a callback is bound for GetHistorySyncControllerDelegate()
+  // because this getter itself must also run in the backend sequence, and the
+  // proxy object below will take care of that.
+  return std::make_unique<syncer::ProxyModelTypeControllerDelegate>(
+      backend_task_runner_,
+      base::BindRepeating(&HistoryBackend::GetHistorySyncControllerDelegate,
+                          base::Unretained(history_backend_.get())));
+}
+
 void HistoryService::ProcessLocalDeleteDirective(
     const sync_pb::HistoryDeleteDirectiveSpecifics& delete_directive) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/components/history/core/browser/history_service.h b/components/history/core/browser/history_service.h
index 001d61c..ff791aa 100644
--- a/components/history/core/browser/history_service.h
+++ b/components/history/core/browser/history_service.h
@@ -650,6 +650,11 @@
   std::unique_ptr<syncer::ModelTypeControllerDelegate>
   GetTypedURLSyncControllerDelegate();
 
+  // For sync codebase only: instantiates a controller delegate to interact with
+  // HistorySyncBridge. Must be called from the UI thread.
+  std::unique_ptr<syncer::ModelTypeControllerDelegate>
+  GetHistorySyncControllerDelegate();
+
   // Override `backend_task_runner_` for testing; needs to be called before
   // Init.
   void set_backend_task_runner_for_testing(
diff --git a/components/history/core/browser/sync/history_sync_bridge.cc b/components/history/core/browser/sync/history_sync_bridge.cc
new file mode 100644
index 0000000..f46d520c
--- /dev/null
+++ b/components/history/core/browser/sync/history_sync_bridge.cc
@@ -0,0 +1,87 @@
+// 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.
+
+#include "components/history/core/browser/sync/history_sync_bridge.h"
+
+#include "components/sync/model/metadata_change_list.h"
+
+namespace history {
+
+HistorySyncBridge::HistorySyncBridge(
+    HistoryBackend* history_backend,
+    HistorySyncMetadataDatabase* sync_metadata_database,
+    std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor)
+    : ModelTypeSyncBridge(std::move(change_processor)) {
+  NOTIMPLEMENTED();
+}
+
+HistorySyncBridge::~HistorySyncBridge() = default;
+
+std::unique_ptr<syncer::MetadataChangeList>
+HistorySyncBridge::CreateMetadataChangeList() {
+  NOTIMPLEMENTED();
+  return {};
+}
+
+absl::optional<syncer::ModelError> HistorySyncBridge::MergeSyncData(
+    std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
+    syncer::EntityChangeList entity_data) {
+  NOTIMPLEMENTED();
+  return {};
+}
+
+absl::optional<syncer::ModelError> HistorySyncBridge::ApplySyncChanges(
+    std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
+    syncer::EntityChangeList entity_changes) {
+  NOTIMPLEMENTED();
+  return {};
+}
+
+void HistorySyncBridge::GetData(StorageKeyList storage_keys,
+                                DataCallback callback) {
+  NOTIMPLEMENTED();
+}
+
+void HistorySyncBridge::GetAllDataForDebugging(DataCallback callback) {
+  NOTIMPLEMENTED();
+}
+
+std::string HistorySyncBridge::GetClientTag(
+    const syncer::EntityData& entity_data) {
+  NOTIMPLEMENTED();
+  return {};
+}
+
+std::string HistorySyncBridge::GetStorageKey(
+    const syncer::EntityData& entity_data) {
+  NOTIMPLEMENTED();
+  return {};
+}
+
+void HistorySyncBridge::OnURLVisited(HistoryBackend* history_backend,
+                                     ui::PageTransition transition,
+                                     const URLRow& row,
+                                     base::Time visit_time) {
+  NOTIMPLEMENTED();
+}
+
+void HistorySyncBridge::OnURLsModified(HistoryBackend* history_backend,
+                                       const URLRows& changed_urls,
+                                       bool is_from_expiration) {
+  NOTIMPLEMENTED();
+}
+
+void HistorySyncBridge::OnURLsDeleted(HistoryBackend* history_backend,
+                                      bool all_history,
+                                      bool expired,
+                                      const URLRows& deleted_rows,
+                                      const std::set<GURL>& favicon_urls) {
+  NOTIMPLEMENTED();
+}
+
+void HistorySyncBridge::OnDatabaseError() {
+  NOTIMPLEMENTED();
+}
+
+}  // namespace history
diff --git a/components/history/core/browser/sync/history_sync_bridge.h b/components/history/core/browser/sync/history_sync_bridge.h
new file mode 100644
index 0000000..b59898d
--- /dev/null
+++ b/components/history/core/browser/sync/history_sync_bridge.h
@@ -0,0 +1,75 @@
+// 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.
+
+#ifndef COMPONENTS_HISTORY_CORE_BROWSER_SYNC_HISTORY_SYNC_BRIDGE_H_
+#define COMPONENTS_HISTORY_CORE_BROWSER_SYNC_HISTORY_SYNC_BRIDGE_H_
+
+#include <memory>
+#include <set>
+#include <string>
+
+#include "components/history/core/browser/history_backend.h"
+#include "components/history/core/browser/history_backend_observer.h"
+#include "components/sync/model/model_type_sync_bridge.h"
+
+namespace syncer {
+class MetadataChangeList;
+class ModelTypeChangeProcessor;
+}  // namespace syncer
+
+namespace history {
+
+class HistorySyncMetadataDatabase;
+
+class HistorySyncBridge : public syncer::ModelTypeSyncBridge,
+                          public HistoryBackendObserver {
+ public:
+  // `sync_metadata_store` is owned by `history_backend`, and must outlive
+  // HistorySyncBridge.
+  HistorySyncBridge(
+      HistoryBackend* history_backend,
+      HistorySyncMetadataDatabase* sync_metadata_store,
+      std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor);
+
+  HistorySyncBridge(const HistorySyncBridge&) = delete;
+  HistorySyncBridge& operator=(const HistorySyncBridge&) = delete;
+
+  ~HistorySyncBridge() override;
+
+  // syncer::ModelTypeSyncBridge implementation.
+  std::unique_ptr<syncer::MetadataChangeList> CreateMetadataChangeList()
+      override;
+  absl::optional<syncer::ModelError> MergeSyncData(
+      std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
+      syncer::EntityChangeList entity_data) override;
+  absl::optional<syncer::ModelError> ApplySyncChanges(
+      std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
+      syncer::EntityChangeList entity_changes) override;
+  void GetData(StorageKeyList storage_keys, DataCallback callback) override;
+  void GetAllDataForDebugging(DataCallback callback) override;
+  std::string GetClientTag(const syncer::EntityData& entity_data) override;
+  std::string GetStorageKey(const syncer::EntityData& entity_data) override;
+
+  // HistoryBackendObserver:
+  void OnURLVisited(HistoryBackend* history_backend,
+                    ui::PageTransition transition,
+                    const URLRow& row,
+                    base::Time visit_time) override;
+  void OnURLsModified(HistoryBackend* history_backend,
+                      const URLRows& changed_urls,
+                      bool is_from_expiration) override;
+  void OnURLsDeleted(HistoryBackend* history_backend,
+                     bool all_history,
+                     bool expired,
+                     const URLRows& deleted_rows,
+                     const std::set<GURL>& favicon_urls) override;
+
+  // Called by HistoryBackend when database error is reported through
+  // DatabaseErrorCallback.
+  void OnDatabaseError();
+};
+
+}  // namespace history
+
+#endif  // COMPONENTS_HISTORY_CORE_BROWSER_SYNC_HISTORY_SYNC_BRIDGE_H_
diff --git a/components/history/core/browser/sync/history_sync_metadata_database.cc b/components/history/core/browser/sync/history_sync_metadata_database.cc
index 8cfa42bf..1bc4f3b 100644
--- a/components/history/core/browser/sync/history_sync_metadata_database.cc
+++ b/components/history/core/browser/sync/history_sync_metadata_database.cc
@@ -34,9 +34,24 @@
 //   value            Serialized sync EntityMetadata, which tracks the sync
 //                    state of each history entity.
 
-HistorySyncMetadataDatabase::HistorySyncMetadataDatabase() = default;
+HistorySyncMetadataDatabase::HistorySyncMetadataDatabase(
+    sql::Database* db,
+    sql::MetaTable* meta_table)
+    : db_(db), meta_table_(meta_table) {}
+
 HistorySyncMetadataDatabase::~HistorySyncMetadataDatabase() = default;
 
+bool HistorySyncMetadataDatabase::Init() {
+  if (!db_->DoesTableExist("history_sync_metadata")) {
+    if (!db_->Execute(
+            "CREATE TABLE history_sync_metadata "
+            "(storage_key INTEGER PRIMARY KEY NOT NULL, value BLOB)")) {
+      return false;
+    }
+  }
+  return true;
+}
+
 bool HistorySyncMetadataDatabase::GetAllSyncMetadata(
     syncer::MetadataBatch* metadata_batch) {
   DCHECK(metadata_batch);
@@ -62,8 +77,8 @@
   DCHECK(!storage_key.empty());
 
   sql::Statement s(
-      GetDB().GetUniqueStatement("INSERT OR REPLACE INTO history_sync_metadata "
-                                 "(storage_key, value) VALUES(?, ?)"));
+      db_->GetUniqueStatement("INSERT OR REPLACE INTO history_sync_metadata "
+                              "(storage_key, value) VALUES(?, ?)"));
   s.BindInt64(0, StorageKeyToMicrosSinceWindowsEpoch(storage_key));
   s.BindString(1, metadata.SerializeAsString());
 
@@ -77,7 +92,7 @@
       << "Only the HISTORY model type is supported";
   DCHECK(!storage_key.empty());
 
-  sql::Statement s(GetDB().GetUniqueStatement(
+  sql::Statement s(db_->GetUniqueStatement(
       "DELETE FROM history_sync_metadata WHERE storage_key=?"));
   s.BindInt64(0, StorageKeyToMicrosSinceWindowsEpoch(storage_key));
 
@@ -89,18 +104,18 @@
     const sync_pb::ModelTypeState& model_type_state) {
   DCHECK_EQ(model_type, syncer::HISTORY)
       << "Only the HISTORY model type is supported";
-  DCHECK_GT(GetMetaTable().GetVersionNumber(), 0);
+  DCHECK_GT(meta_table_->GetVersionNumber(), 0);
 
   std::string serialized_state = model_type_state.SerializeAsString();
-  return GetMetaTable().SetValue(kHistoryModelTypeStateKey, serialized_state);
+  return meta_table_->SetValue(kHistoryModelTypeStateKey, serialized_state);
 }
 
 bool HistorySyncMetadataDatabase::ClearModelTypeState(
     syncer::ModelType model_type) {
   DCHECK_EQ(model_type, syncer::HISTORY)
       << "Only the HISTORY model type is supported";
-  DCHECK_GT(GetMetaTable().GetVersionNumber(), 0);
-  return GetMetaTable().DeleteKey(kHistoryModelTypeStateKey);
+  DCHECK_GT(meta_table_->GetVersionNumber(), 0);
+  return meta_table_->DeleteKey(kHistoryModelTypeStateKey);
 }
 
 // static
@@ -137,21 +152,10 @@
       visit_time.ToDeltaSinceWindowsEpoch().InMicroseconds());
 }
 
-bool HistorySyncMetadataDatabase::InitHistoryMetadataTable() {
-  if (!GetDB().DoesTableExist("history_sync_metadata")) {
-    if (!GetDB().Execute(
-            "CREATE TABLE history_sync_metadata "
-            "(storage_key INTEGER PRIMARY KEY NOT NULL, value BLOB)")) {
-      return false;
-    }
-  }
-  return true;
-}
-
 bool HistorySyncMetadataDatabase::GetAllEntityMetadata(
     syncer::MetadataBatch* metadata_batch) {
   DCHECK(metadata_batch);
-  sql::Statement s(GetDB().GetUniqueStatement(
+  sql::Statement s(db_->GetUniqueStatement(
       "SELECT storage_key, value FROM history_sync_metadata"));
 
   while (s.Step()) {
@@ -171,9 +175,9 @@
 
 bool HistorySyncMetadataDatabase::GetModelTypeState(
     sync_pb::ModelTypeState* state) {
-  DCHECK_GT(GetMetaTable().GetVersionNumber(), 0);
+  DCHECK_GT(meta_table_->GetVersionNumber(), 0);
   std::string serialized_state;
-  if (!GetMetaTable().GetValue(kHistoryModelTypeStateKey, &serialized_state)) {
+  if (!meta_table_->GetValue(kHistoryModelTypeStateKey, &serialized_state)) {
     *state = sync_pb::ModelTypeState();
     return true;
   }
diff --git a/components/history/core/browser/sync/history_sync_metadata_database.h b/components/history/core/browser/sync/history_sync_metadata_database.h
index 3c92537..02bb3b1 100644
--- a/components/history/core/browser/sync/history_sync_metadata_database.h
+++ b/components/history/core/browser/sync/history_sync_metadata_database.h
@@ -31,9 +31,9 @@
 // overall state of the history sync datatype.
 class HistorySyncMetadataDatabase : public syncer::SyncMetadataStore {
  public:
-  // After construction, subclasses must call InitHistoryMetadataTable() before
-  // doing anything else to make sure the database is initialized.
-  HistorySyncMetadataDatabase();
+  // After construction, Init() must be called before doing anything else to
+  // make sure the database is initialized.
+  HistorySyncMetadataDatabase(sql::Database* db, sql::MetaTable* meta_table);
 
   HistorySyncMetadataDatabase(const HistorySyncMetadataDatabase&) = delete;
   HistorySyncMetadataDatabase& operator=(const HistorySyncMetadataDatabase&) =
@@ -41,6 +41,10 @@
 
   ~HistorySyncMetadataDatabase() override;
 
+  // Makes sure the tables and indices are properly set up. Must be called
+  // before anything else.
+  bool Init();
+
   // Reads all stored metadata for History and fills `metadata_batch` with it.
   bool GetAllSyncMetadata(syncer::MetadataBatch* metadata_batch);
 
@@ -64,17 +68,6 @@
   static base::Time StorageKeyToVisitTime(const std::string& storage_key);
   static std::string StorageKeyFromVisitTime(base::Time visit_time);
 
- protected:
-  // Called by derived classes on initialization to make sure the tables and
-  // indices are properly set up. Must be called before anything else.
-  bool InitHistoryMetadataTable();
-
-  // Returns the underlying database to be used.
-  virtual sql::Database& GetDB() = 0;
-
-  // Returns the database's MetaTable, where the ModelTypeState will be stored.
-  virtual sql::MetaTable& GetMetaTable() = 0;
-
  private:
   // Reads all sync_pb::EntityMetadata for History and fills `metadata_batch`
   // with it.
@@ -82,6 +75,9 @@
 
   // Reads sync_pb::ModelTypeState for History and fills `state` with it.
   bool GetModelTypeState(sync_pb::ModelTypeState* state);
+
+  sql::Database* const db_;
+  sql::MetaTable* const meta_table_;
 };
 
 }  // namespace history
diff --git a/components/history/core/browser/sync/history_sync_metadata_database_unittest.cc b/components/history/core/browser/sync/history_sync_metadata_database_unittest.cc
index 9a129a2f3..527b86a 100644
--- a/components/history/core/browser/sync/history_sync_metadata_database_unittest.cc
+++ b/components/history/core/browser/sync/history_sync_metadata_database_unittest.cc
@@ -30,35 +30,9 @@
 constexpr base::Time kVisitTime2 = base::Time::FromDeltaSinceWindowsEpoch(
     base::Microseconds(13297523047664774ull));
 
-// Test implementation of HistorySyncMetadataDatabase that's backed by an
-// in-memory database.
-class TestHistorySyncMetadataDatabase : public HistorySyncMetadataDatabase {
- public:
-  TestHistorySyncMetadataDatabase() {
-    EXPECT_TRUE(db_.OpenInMemory());
-    EXPECT_TRUE(
-        meta_table_.Init(&db_, /*version=*/1, /*compatible_version=*/1));
-
-    InitHistoryMetadataTable();
-  }
-  ~TestHistorySyncMetadataDatabase() override { db_.Close(); }
-
-  TestHistorySyncMetadataDatabase(const TestHistorySyncMetadataDatabase&) =
-      delete;
-  TestHistorySyncMetadataDatabase& operator=(
-      const TestHistorySyncMetadataDatabase&) = delete;
-
-  sql::Database& GetDB() override { return db_; }
-  sql::MetaTable& GetMetaTable() override { return meta_table_; }
-
- private:
-  sql::Database db_;
-  sql::MetaTable meta_table_;
-};
-
 class HistorySyncMetadataDatabaseTest : public testing::Test {
  public:
-  HistorySyncMetadataDatabaseTest() = default;
+  HistorySyncMetadataDatabaseTest() : metadata_db_(&db_, &meta_table_) {}
 
   HistorySyncMetadataDatabaseTest(const HistorySyncMetadataDatabaseTest&) =
       delete;
@@ -67,10 +41,24 @@
 
   ~HistorySyncMetadataDatabaseTest() override = default;
 
-  TestHistorySyncMetadataDatabase* db() { return &metadata_db_; }
+  HistorySyncMetadataDatabase* metadata_db() { return &metadata_db_; }
+
+  sql::Database* sql_db() { return &db_; }
+  sql::MetaTable* sql_meta_table() { return &meta_table_; }
+
+ protected:
+  void SetUp() override {
+    EXPECT_TRUE(db_.OpenInMemory());
+    metadata_db_.Init();
+    meta_table_.Init(&db_, 1, 1);
+  }
+  void TearDown() override { db_.Close(); }
 
  private:
-  TestHistorySyncMetadataDatabase metadata_db_;
+  sql::Database db_;
+  sql::MetaTable meta_table_;
+
+  HistorySyncMetadataDatabase metadata_db_;
 };
 
 TEST_F(HistorySyncMetadataDatabaseTest,
@@ -102,7 +90,7 @@
 
 TEST_F(HistorySyncMetadataDatabaseTest, EmptyStateIsValid) {
   MetadataBatch metadata_batch;
-  EXPECT_TRUE(db()->GetAllSyncMetadata(&metadata_batch));
+  EXPECT_TRUE(metadata_db()->GetAllSyncMetadata(&metadata_batch));
   EXPECT_EQ(0u, metadata_batch.TakeAllMetadata().size());
   EXPECT_EQ(ModelTypeState().SerializeAsString(),
             metadata_batch.GetModelTypeState().SerializeAsString());
@@ -118,22 +106,23 @@
   EntityMetadata metadata1;
   metadata1.set_sequence_number(1);
   metadata1.set_client_tag_hash("client_hash1");
-  ASSERT_TRUE(
-      db()->UpdateSyncMetadata(syncer::HISTORY, storage_key1, metadata1));
+  ASSERT_TRUE(metadata_db()->UpdateSyncMetadata(syncer::HISTORY, storage_key1,
+                                                metadata1));
 
   ModelTypeState model_type_state;
   model_type_state.set_initial_sync_done(true);
-  ASSERT_TRUE(db()->UpdateModelTypeState(syncer::HISTORY, model_type_state));
+  ASSERT_TRUE(
+      metadata_db()->UpdateModelTypeState(syncer::HISTORY, model_type_state));
 
   EntityMetadata metadata2;
   metadata2.set_sequence_number(2);
   metadata2.set_client_tag_hash("client_hash2");
-  ASSERT_TRUE(
-      db()->UpdateSyncMetadata(syncer::HISTORY, storage_key2, metadata2));
+  ASSERT_TRUE(metadata_db()->UpdateSyncMetadata(syncer::HISTORY, storage_key2,
+                                                metadata2));
 
   // Read the metadata and make sure it matches what we wrote.
   MetadataBatch metadata_batch;
-  EXPECT_TRUE(db()->GetAllSyncMetadata(&metadata_batch));
+  EXPECT_TRUE(metadata_db()->GetAllSyncMetadata(&metadata_batch));
 
   EXPECT_TRUE(metadata_batch.GetModelTypeState().initial_sync_done());
 
@@ -147,13 +136,14 @@
   // Now check that an entity update and a model type state update replace the
   // old values.
   metadata1.set_sequence_number(2);
-  ASSERT_TRUE(
-      db()->UpdateSyncMetadata(syncer::HISTORY, storage_key1, metadata1));
+  ASSERT_TRUE(metadata_db()->UpdateSyncMetadata(syncer::HISTORY, storage_key1,
+                                                metadata1));
   model_type_state.set_initial_sync_done(false);
-  ASSERT_TRUE(db()->UpdateModelTypeState(syncer::HISTORY, model_type_state));
+  ASSERT_TRUE(
+      metadata_db()->UpdateModelTypeState(syncer::HISTORY, model_type_state));
 
   MetadataBatch metadata_batch2;
-  ASSERT_TRUE(db()->GetAllSyncMetadata(&metadata_batch2));
+  ASSERT_TRUE(metadata_db()->GetAllSyncMetadata(&metadata_batch2));
   EXPECT_FALSE(metadata_batch2.GetModelTypeState().initial_sync_done());
 
   EntityMetadataMap metadata_records2 = metadata_batch2.TakeAllMetadata();
@@ -168,46 +158,48 @@
   // Write some data into the store.
   ModelTypeState model_type_state;
   model_type_state.set_initial_sync_done(true);
-  ASSERT_TRUE(db()->UpdateModelTypeState(syncer::HISTORY, model_type_state));
+  ASSERT_TRUE(
+      metadata_db()->UpdateModelTypeState(syncer::HISTORY, model_type_state));
 
   EntityMetadata metadata;
   metadata.set_client_tag_hash("client_hash");
-  ASSERT_TRUE(db()->UpdateSyncMetadata(syncer::HISTORY, storage_key, metadata));
+  ASSERT_TRUE(metadata_db()->UpdateSyncMetadata(syncer::HISTORY, storage_key,
+                                                metadata));
 
   // Delete the data we just wrote.
-  ASSERT_TRUE(db()->ClearSyncMetadata(syncer::HISTORY, storage_key));
+  ASSERT_TRUE(metadata_db()->ClearSyncMetadata(syncer::HISTORY, storage_key));
 
   // It shouldn't be there anymore.
   MetadataBatch metadata_batch;
-  ASSERT_TRUE(db()->GetAllSyncMetadata(&metadata_batch));
+  ASSERT_TRUE(metadata_db()->GetAllSyncMetadata(&metadata_batch));
   EXPECT_EQ(metadata_batch.GetAllMetadata().size(), 0u);
 
   // Now delete the model type state and make sure it's gone.
   ASSERT_NE(ModelTypeState().SerializeAsString(),
             metadata_batch.GetModelTypeState().SerializeAsString());
-  ASSERT_TRUE(db()->ClearModelTypeState(syncer::HISTORY));
-  ASSERT_TRUE(db()->GetAllSyncMetadata(&metadata_batch));
+  ASSERT_TRUE(metadata_db()->ClearModelTypeState(syncer::HISTORY));
+  ASSERT_TRUE(metadata_db()->GetAllSyncMetadata(&metadata_batch));
   EXPECT_EQ(ModelTypeState().SerializeAsString(),
             metadata_batch.GetModelTypeState().SerializeAsString());
 }
 
 TEST_F(HistorySyncMetadataDatabaseTest, FailsToReadCorruptSyncMetadata) {
   // Manually insert some corrupt data into the underlying sql DB.
-  sql::Statement s(db()->GetDB().GetUniqueStatement(
+  sql::Statement s(sql_db()->GetUniqueStatement(
       "INSERT OR REPLACE INTO history_sync_metadata (storage_key, value) "
       "VALUES(1, 'unparseable')"));
   ASSERT_TRUE(s.Run());
 
   MetadataBatch metadata_batch;
-  EXPECT_FALSE(db()->GetAllSyncMetadata(&metadata_batch));
+  EXPECT_FALSE(metadata_db()->GetAllSyncMetadata(&metadata_batch));
 }
 
 TEST_F(HistorySyncMetadataDatabaseTest, FailsToReadCorruptModelTypeState) {
   // Insert some corrupt data into the meta table.
-  db()->GetMetaTable().SetValue("history_model_type_state", "unparseable");
+  sql_meta_table()->SetValue("history_model_type_state", "unparseable");
 
   MetadataBatch metadata_batch;
-  EXPECT_FALSE(db()->GetAllSyncMetadata(&metadata_batch));
+  EXPECT_FALSE(metadata_db()->GetAllSyncMetadata(&metadata_batch));
 }
 
 }  // namespace
diff --git a/components/history/core/browser/sync/typed_url_model_type_controller.cc b/components/history/core/browser/sync/typed_url_model_type_controller.cc
index 4e6e398a..3403594 100644
--- a/components/history/core/browser/sync/typed_url_model_type_controller.cc
+++ b/components/history/core/browser/sync/typed_url_model_type_controller.cc
@@ -8,33 +8,55 @@
 
 #include "base/bind.h"
 #include "components/history/core/browser/history_service.h"
+#include "components/sync/base/features.h"
 
 namespace history {
 
 namespace {
 
 std::unique_ptr<syncer::ModelTypeControllerDelegate>
-GetDelegateFromHistoryService(HistoryService* history_service) {
-  if (history_service) {
+GetDelegateFromHistoryService(syncer::ModelType model_type,
+                              HistoryService* history_service) {
+  if (!history_service) {
+    return nullptr;
+  }
+
+  if (model_type == syncer::TYPED_URLS) {
     return history_service->GetTypedURLSyncControllerDelegate();
   }
-  return nullptr;
+  DCHECK_EQ(model_type, syncer::HISTORY);
+  return history_service->GetHistorySyncControllerDelegate();
 }
 
 }  // namespace
 
 TypedURLModelTypeController::TypedURLModelTypeController(
+    syncer::ModelType model_type,
     syncer::SyncService* sync_service,
     HistoryService* history_service,
     PrefService* pref_service)
-    : ModelTypeController(syncer::TYPED_URLS,
-                          GetDelegateFromHistoryService(history_service)),
-      helper_(syncer::TYPED_URLS, sync_service, pref_service) {}
+    : ModelTypeController(
+          model_type,
+          GetDelegateFromHistoryService(model_type, history_service)),
+      helper_(model_type, sync_service, pref_service) {
+  DCHECK(model_type == syncer::TYPED_URLS || model_type == syncer::HISTORY);
+  DCHECK(model_type == syncer::TYPED_URLS ||
+         base::FeatureList::IsEnabled(syncer::kSyncEnableHistoryDataType));
+}
 
 TypedURLModelTypeController::~TypedURLModelTypeController() = default;
 
 syncer::DataTypeController::PreconditionState
 TypedURLModelTypeController::GetPreconditionState() const {
+  if (base::FeatureList::IsEnabled(syncer::kSyncEnableHistoryDataType)) {
+    // If the feature flag is enabled, syncer::HISTORY replaces
+    // syncer::TYPED_URLS.
+    // TODO(crbug.com/1318028): Consider whether this is the best way to go
+    // about things - maybe we'll want to keep the TypedURLs (meta)data for now?
+    if (type() == syncer::TYPED_URLS) {
+      return PreconditionState::kMustStopAndClearData;
+    }
+  }
   return helper_.GetPreconditionState();
 }
 
diff --git a/components/history/core/browser/sync/typed_url_model_type_controller.h b/components/history/core/browser/sync/typed_url_model_type_controller.h
index eb687f46..90fdcf5e 100644
--- a/components/history/core/browser/sync/typed_url_model_type_controller.h
+++ b/components/history/core/browser/sync/typed_url_model_type_controller.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_HISTORY_CORE_BROWSER_SYNC_TYPED_URL_MODEL_TYPE_CONTROLLER_H_
 
 #include "components/history/core/browser/sync/history_model_type_controller_helper.h"
+#include "components/sync/base/model_type.h"
 #include "components/sync/driver/model_type_controller.h"
 
 class PrefService;
@@ -18,9 +19,12 @@
 
 class HistoryService;
 
+// TODO(crbug.com/1318028): Rename to HistoryModelTypeController.
 class TypedURLModelTypeController : public syncer::ModelTypeController {
  public:
-  TypedURLModelTypeController(syncer::SyncService* sync_service,
+  // `model_type` must be either HISTORY or TYPED_URLS.
+  TypedURLModelTypeController(syncer::ModelType model_type,
+                              syncer::SyncService* sync_service,
                               HistoryService* history_service,
                               PrefService* pref_service);
 
diff --git a/components/permissions/test/permission_request_observer.cc b/components/permissions/test/permission_request_observer.cc
index ec4314e9..bec7ed8 100644
--- a/components/permissions/test/permission_request_observer.cc
+++ b/components/permissions/test/permission_request_observer.cc
@@ -22,4 +22,8 @@
   loop_.Quit();
 }
 
+void PermissionRequestObserver::OnRequestsFinalized() {
+  loop_.Quit();
+}
+
 }  // namespace permissions
diff --git a/components/permissions/test/permission_request_observer.h b/components/permissions/test/permission_request_observer.h
index aeb1afcf..bf123ce 100644
--- a/components/permissions/test/permission_request_observer.h
+++ b/components/permissions/test/permission_request_observer.h
@@ -28,6 +28,7 @@
 
   // PermissionRequestManager::Observer:
   void OnBubbleAdded() override;
+  void OnRequestsFinalized() override;
 
  private:
   base::ScopedObservation<PermissionRequestManager,
diff --git a/components/segmentation_platform/internal/android/segmentation_platform_service_android.cc b/components/segmentation_platform/internal/android/segmentation_platform_service_android.cc
index 24d1cf4..820d7ae 100644
--- a/components/segmentation_platform/internal/android/segmentation_platform_service_android.cc
+++ b/components/segmentation_platform/internal/android/segmentation_platform_service_android.cc
@@ -106,11 +106,12 @@
         const JavaParamRef<jobject>& jcaller,
         const JavaParamRef<jstring>& j_segmentation_key,
         const JavaParamRef<jobject>& jcallback) {
-  return segmentation_platform_service_
-      ->RegisterOnDemandSegmentSelectionCallback(
+  CallbackId callback_id =
+      segmentation_platform_service_->RegisterOnDemandSegmentSelectionCallback(
           ConvertJavaStringToUTF8(env, j_segmentation_key),
           base::BindRepeating(&RunOnDemandSegmentSelectionCallback,
                               ScopedJavaGlobalRef<jobject>(jcallback)));
+  return callback_id.value();
 }
 
 void SegmentationPlatformServiceAndroid::
@@ -120,7 +121,8 @@
         const JavaParamRef<jstring>& j_segmentation_key,
         jint j_callback_id) {
   segmentation_platform_service_->UnregisterOnDemandSegmentSelectionCallback(
-      (int)j_callback_id, ConvertJavaStringToUTF8(env, j_segmentation_key));
+      CallbackId::FromUnsafeValue(j_callback_id),
+      ConvertJavaStringToUTF8(env, j_segmentation_key));
 }
 
 ScopedJavaLocalRef<jobject>
diff --git a/components/segmentation_platform/internal/dummy_segmentation_platform_service.cc b/components/segmentation_platform/internal/dummy_segmentation_platform_service.cc
index 743b52c3..1ea3bcd 100644
--- a/components/segmentation_platform/internal/dummy_segmentation_platform_service.cc
+++ b/components/segmentation_platform/internal/dummy_segmentation_platform_service.cc
@@ -32,15 +32,16 @@
   return SegmentSelectionResult();
 }
 
-int DummySegmentationPlatformService::RegisterOnDemandSegmentSelectionCallback(
+CallbackId
+DummySegmentationPlatformService::RegisterOnDemandSegmentSelectionCallback(
     const std::string& segmentation_key,
     const OnDemandSegmentSelectionCallback& callback) {
-  return 0;
+  return CallbackId::FromUnsafeValue(0);
 }
 
 void DummySegmentationPlatformService::
     UnregisterOnDemandSegmentSelectionCallback(
-        int callback_id,
+        CallbackId callback_id,
         const std::string& segmentation_key) {}
 
 void DummySegmentationPlatformService::OnTrigger(
diff --git a/components/segmentation_platform/internal/dummy_segmentation_platform_service.h b/components/segmentation_platform/internal/dummy_segmentation_platform_service.h
index ac81913..8cf9fd80 100644
--- a/components/segmentation_platform/internal/dummy_segmentation_platform_service.h
+++ b/components/segmentation_platform/internal/dummy_segmentation_platform_service.h
@@ -29,11 +29,11 @@
                           SegmentSelectionCallback callback) override;
   SegmentSelectionResult GetCachedSegmentResult(
       const std::string& segmentation_key) override;
-  int RegisterOnDemandSegmentSelectionCallback(
+  CallbackId RegisterOnDemandSegmentSelectionCallback(
       const std::string& segmentation_key,
       const OnDemandSegmentSelectionCallback& callback) override;
   void UnregisterOnDemandSegmentSelectionCallback(
-      int callback_id,
+      CallbackId callback_id,
       const std::string& segmentation_key) override;
   void OnTrigger(TriggerType trigger,
                  const TriggerContext& trigger_context) override;
diff --git a/components/segmentation_platform/internal/segmentation_platform_service_impl.cc b/components/segmentation_platform/internal/segmentation_platform_service_impl.cc
index bc503964..2b6d6b9 100644
--- a/components/segmentation_platform/internal/segmentation_platform_service_impl.cc
+++ b/components/segmentation_platform/internal/segmentation_platform_service_impl.cc
@@ -101,6 +101,9 @@
             init_params->profile_prefs, config.get(),
             field_trial_register_.get(), init_params->clock, platform_options_,
             storage_service_->default_model_manager());
+    if (config->trigger != TriggerType::kNone) {
+      clients_for_trigger_[config->trigger].insert(config->segmentation_key);
+    }
   }
 
   proxy_ = std::make_unique<ServiceProxyImpl>(
@@ -136,20 +139,54 @@
   return selector->GetCachedSegmentResult();
 }
 
-int SegmentationPlatformServiceImpl::RegisterOnDemandSegmentSelectionCallback(
+CallbackId
+SegmentationPlatformServiceImpl::RegisterOnDemandSegmentSelectionCallback(
     const std::string& segmentation_key,
     const OnDemandSegmentSelectionCallback& callback) {
-  return 0;
+  static auto callback_id_generator = CallbackId::Generator();
+  const CallbackId callback_id = callback_id_generator.GenerateNextId();
+  callback_map_[callback_id] = callback;
+  segment_selection_callback_ids_[segmentation_key].insert(callback_id);
+  return callback_id;
 }
 
 void SegmentationPlatformServiceImpl::
     UnregisterOnDemandSegmentSelectionCallback(
-        int callback_id,
-        const std::string& segmentation_key) {}
+        CallbackId callback_id,
+        const std::string& segmentation_key) {
+  segment_selection_callback_ids_[segmentation_key].erase(callback_id);
+  if (segment_selection_callback_ids_[segmentation_key].empty()) {
+    segment_selection_callback_ids_.erase(segmentation_key);
+  }
+}
 
 void SegmentationPlatformServiceImpl::OnTrigger(
     TriggerType trigger,
-    const TriggerContext& trigger_context) {}
+    const TriggerContext& trigger_context) {
+  if (clients_for_trigger_.find(trigger) == clients_for_trigger_.end())
+    return;
+  scoped_refptr<InputContext> input_context;
+  for (const auto& segmentation_key : clients_for_trigger_[trigger]) {
+    CHECK(segment_selectors_.find(segmentation_key) !=
+          segment_selectors_.end());
+    auto& selector = segment_selectors_.at(segmentation_key);
+    selector->GetSelectedSegmentOnDemand(
+        input_context,
+        base::BindOnce(
+            &SegmentationPlatformServiceImpl::OnSegmentSelectionForTrigger,
+            weak_ptr_factory_.GetWeakPtr(), segmentation_key, trigger_context));
+  }
+}
+
+void SegmentationPlatformServiceImpl::OnSegmentSelectionForTrigger(
+    const std::string& segmentation_key,
+    const TriggerContext& trigger_context,
+    const SegmentSelectionResult& selected_segment) {
+  for (auto callback_id : segment_selection_callback_ids_[segmentation_key]) {
+    const auto& callback = callback_map_[callback_id];
+    callback.Run(selected_segment, trigger_context);
+  }
+}
 
 void SegmentationPlatformServiceImpl::EnableMetrics(
     bool signal_collection_allowed) {
diff --git a/components/segmentation_platform/internal/segmentation_platform_service_impl.h b/components/segmentation_platform/internal/segmentation_platform_service_impl.h
index 626fce5..afa49dc 100644
--- a/components/segmentation_platform/internal/segmentation_platform_service_impl.h
+++ b/components/segmentation_platform/internal/segmentation_platform_service_impl.h
@@ -92,11 +92,11 @@
                           SegmentSelectionCallback callback) override;
   SegmentSelectionResult GetCachedSegmentResult(
       const std::string& segmentation_key) override;
-  int RegisterOnDemandSegmentSelectionCallback(
+  CallbackId RegisterOnDemandSegmentSelectionCallback(
       const std::string& segmentation_key,
       const OnDemandSegmentSelectionCallback& callback) override;
   void UnregisterOnDemandSegmentSelectionCallback(
-      int callback_id,
+      CallbackId callback_id,
       const std::string& segmentation_key) override;
   void OnTrigger(TriggerType trigger,
                  const TriggerContext& trigger_context) override;
@@ -123,6 +123,12 @@
   // Task that runs every day or at startup to keep the platform data updated.
   void RunDailyTasks(bool is_startup);
 
+  // Callback to run after on-demand segment selection.
+  void OnSegmentSelectionForTrigger(
+      const std::string& segmentation_key,
+      const TriggerContext& trigger_context,
+      const SegmentSelectionResult& selected_segment);
+
   std::unique_ptr<ModelProviderFactory> model_provider_factory_;
 
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
@@ -146,6 +152,14 @@
   base::flat_map<std::string, std::unique_ptr<SegmentSelectorImpl>>
       segment_selectors_;
 
+  // On-demand segment selection.
+  base::flat_map<std::string, base::flat_set<CallbackId>>
+      segment_selection_callback_ids_;
+  base::flat_map<CallbackId, OnDemandSegmentSelectionCallback> callback_map_;
+
+  // Clients registered for trigger events.
+  base::flat_map<TriggerType, base::flat_set<std::string>> clients_for_trigger_;
+
   // Segment results.
   std::unique_ptr<SegmentScoreProvider> segment_score_provider_;
 
diff --git a/components/segmentation_platform/internal/segmentation_platform_service_impl_unittest.cc b/components/segmentation_platform/internal/segmentation_platform_service_impl_unittest.cc
index 92a66ef..46abac7f 100644
--- a/components/segmentation_platform/internal/segmentation_platform_service_impl_unittest.cc
+++ b/components/segmentation_platform/internal/segmentation_platform_service_impl_unittest.cc
@@ -99,6 +99,9 @@
     std::move(closure).Run();
   }
 
+  void OnOnDemandSegmentSelection(const SegmentSelectionResult& result,
+                                  const TriggerContext& trigger_context) {}
+
   void AssertSelectedSegment(
       const std::string& segmentation_key,
       bool is_ready,
@@ -265,6 +268,38 @@
   loop.Run();
 }
 
+TEST_F(SegmentationPlatformServiceImplTest, RegisterAndUnregisterCallback) {
+  CallbackId callback_id1 =
+      segmentation_platform_service_impl_
+          ->RegisterOnDemandSegmentSelectionCallback(
+              kTestSegmentationKey1,
+              base::BindRepeating(&SegmentationPlatformServiceImplTest::
+                                      OnOnDemandSegmentSelection,
+                                  base::Unretained(this)));
+  CallbackId callback_id2 =
+      segmentation_platform_service_impl_
+          ->RegisterOnDemandSegmentSelectionCallback(
+              kTestSegmentationKey1,
+              base::BindRepeating(&SegmentationPlatformServiceImplTest::
+                                      OnOnDemandSegmentSelection,
+                                  base::Unretained(this)));
+  ASSERT_EQ(callback_id2.value(), callback_id1.value() + 1);
+
+  segmentation_platform_service_impl_
+      ->UnregisterOnDemandSegmentSelectionCallback(callback_id1,
+                                                   kTestSegmentationKey1);
+  segmentation_platform_service_impl_
+      ->UnregisterOnDemandSegmentSelectionCallback(callback_id2,
+                                                   kTestSegmentationKey1);
+
+  // Calling unregister multiple times have no effect.
+  segmentation_platform_service_impl_
+      ->UnregisterOnDemandSegmentSelectionCallback(callback_id2,
+                                                   kTestSegmentationKey1);
+
+  // TODO(shaktisahu): Add test for OnTrigger that invokes the callback.
+}
+
 class SegmentationPlatformServiceImplEmptyConfigTest
     : public SegmentationPlatformServiceImplTest {
   std::vector<std::unique_ptr<Config>> CreateConfigs() override {
diff --git a/components/segmentation_platform/internal/selection/segment_selector_impl.cc b/components/segmentation_platform/internal/selection/segment_selector_impl.cc
index 074af992..eb5353f 100644
--- a/components/segmentation_platform/internal/selection/segment_selector_impl.cc
+++ b/components/segmentation_platform/internal/selection/segment_selector_impl.cc
@@ -249,7 +249,8 @@
     SegmentSelectionResult result;
     result.is_ready = true;
     result.segment = selected_segment;
-    std::move(callback).Run(result);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(std::move(callback), result));
   } else {
     DCHECK(callback.is_null());
     UpdateSelectedSegment(selected_segment);
diff --git a/components/segmentation_platform/public/segmentation_platform_service.h b/components/segmentation_platform/public/segmentation_platform_service.h
index 38ee2aa..dac91f3 100644
--- a/components/segmentation_platform/public/segmentation_platform_service.h
+++ b/components/segmentation_platform/public/segmentation_platform_service.h
@@ -10,6 +10,7 @@
 #include "base/callback.h"
 #include "base/observer_list_types.h"
 #include "base/supports_user_data.h"
+#include "base/types/id_type.h"
 #include "build/build_config.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/segmentation_platform/public/trigger.h"
@@ -25,6 +26,8 @@
 struct SegmentSelectionResult;
 struct TriggerContext;
 
+using CallbackId = base::IdType32<class OnDemandSegmentSelectionCallbackTag>;
+
 // The core class of segmentation platform that integrates all the required
 // pieces on the client side.
 class SegmentationPlatformService : public KeyedService,
@@ -71,13 +74,13 @@
   using OnDemandSegmentSelectionCallback =
       base::RepeatingCallback<void(const SegmentSelectionResult&,
                                    const TriggerContext&)>;
-  virtual int RegisterOnDemandSegmentSelectionCallback(
+  virtual CallbackId RegisterOnDemandSegmentSelectionCallback(
       const std::string& segmentation_key,
       const OnDemandSegmentSelectionCallback& callback) = 0;
 
   // Called to unregister the callback with the given callback_id.
   virtual void UnregisterOnDemandSegmentSelectionCallback(
-      int callback_id,
+      CallbackId callback_id,
       const std::string& segmentation_key) = 0;
 
   // Called when a trigger event happens.
diff --git a/components/services/app_service/app_service_mojom_impl.cc b/components/services/app_service/app_service_mojom_impl.cc
index c76a80f..c3362fa 100644
--- a/components/services/app_service/app_service_mojom_impl.cc
+++ b/components/services/app_service/app_service_mojom_impl.cc
@@ -283,7 +283,8 @@
     std::vector<apps::mojom::IntentFilterPtr> all_link_filters) {
   if (preferred_apps_impl_) {
     preferred_apps_impl_->SetSupportedLinksPreference(
-        app_type, app_id, std::move(all_link_filters));
+        ConvertMojomAppTypToAppType(app_type), app_id,
+        ConvertMojomIntentFiltersToIntentFilters(all_link_filters));
   }
 }
 
diff --git a/components/services/app_service/public/cpp/app_update.cc b/components/services/app_service/public/cpp/app_update.cc
index a286bf13..29cacae 100644
--- a/components/services/app_service/public/cpp/app_update.cc
+++ b/components/services/app_service/public/cpp/app_update.cc
@@ -39,16 +39,6 @@
   }
 }
 
-std::vector<apps::IntentFilterPtr> ConvertMojomIntentFiltersToIntentFilters(
-    const std::vector<apps::mojom::IntentFilterPtr>& mojom_intent_filters) {
-  std::vector<apps::IntentFilterPtr> intent_filters;
-  for (const auto& mojom_intent_filter : mojom_intent_filters) {
-    intent_filters.push_back(
-        apps::ConvertMojomIntentFilterToIntentFilter(mojom_intent_filter));
-  }
-  return intent_filters;
-}
-
 void CloneMojomIntentFilters(
     const std::vector<apps::mojom::IntentFilterPtr>& clone_from,
     std::vector<apps::mojom::IntentFilterPtr>* clone_to) {
@@ -885,10 +875,10 @@
   }
 
   if (mojom_delta_ && !mojom_delta_->intent_filters.empty()) {
-    return ::ConvertMojomIntentFiltersToIntentFilters(
+    return ConvertMojomIntentFiltersToIntentFilters(
         mojom_delta_->intent_filters);
   } else if (mojom_state_ && !mojom_state_->intent_filters.empty()) {
-    return ::ConvertMojomIntentFiltersToIntentFilters(
+    return ConvertMojomIntentFiltersToIntentFilters(
         mojom_state_->intent_filters);
   }
   return std::vector<IntentFilterPtr>{};
diff --git a/components/services/app_service/public/cpp/intent_filter.cc b/components/services/app_service/public/cpp/intent_filter.cc
index 96ed7fe5..907585e 100644
--- a/components/services/app_service/public/cpp/intent_filter.cc
+++ b/components/services/app_service/public/cpp/intent_filter.cc
@@ -538,4 +538,26 @@
   return mojom_intent_filter;
 }
 
+IntentFilters ConvertMojomIntentFiltersToIntentFilters(
+    const std::vector<apps::mojom::IntentFilterPtr>& mojom_intent_filters) {
+  IntentFilters intent_filters;
+  intent_filters.reserve(mojom_intent_filters.size());
+  for (const auto& mojom_intent_filter : mojom_intent_filters) {
+    intent_filters.push_back(
+        ConvertMojomIntentFilterToIntentFilter(mojom_intent_filter));
+  }
+  return intent_filters;
+}
+
+std::vector<apps::mojom::IntentFilterPtr>
+ConvertIntentFiltersToMojomIntentFilters(const IntentFilters& intent_filters) {
+  std::vector<apps::mojom::IntentFilterPtr> mojom_intent_filters;
+  mojom_intent_filters.reserve(intent_filters.size());
+  for (const auto& intent_filter : intent_filters) {
+    mojom_intent_filters.push_back(
+        ConvertIntentFilterToMojomIntentFilter(intent_filter));
+  }
+  return mojom_intent_filters;
+}
+
 }  // namespace apps
diff --git a/components/services/app_service/public/cpp/intent_filter.h b/components/services/app_service/public/cpp/intent_filter.h
index 7072e80..337650e 100644
--- a/components/services/app_service/public/cpp/intent_filter.h
+++ b/components/services/app_service/public/cpp/intent_filter.h
@@ -255,6 +255,14 @@
 apps::mojom::IntentFilterPtr ConvertIntentFilterToMojomIntentFilter(
     const IntentFilterPtr& intent_filter);
 
+COMPONENT_EXPORT(APP_TYPES)
+IntentFilters ConvertMojomIntentFiltersToIntentFilters(
+    const std::vector<apps::mojom::IntentFilterPtr>& mojom_intent_filters);
+
+COMPONENT_EXPORT(APP_TYPES)
+std::vector<apps::mojom::IntentFilterPtr>
+ConvertIntentFiltersToMojomIntentFilters(const IntentFilters& intent_filters);
+
 }  // namespace apps
 
 #endif  // COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_INTENT_FILTER_H_
diff --git a/components/services/app_service/public/cpp/preferred_apps_impl.cc b/components/services/app_service/public/cpp/preferred_apps_impl.cc
index be301ba..13eac3e 100644
--- a/components/services/app_service/public/cpp/preferred_apps_impl.cc
+++ b/components/services/app_service/public/cpp/preferred_apps_impl.cc
@@ -125,9 +125,9 @@
 }
 
 void PreferredAppsImpl::SetSupportedLinksPreference(
-    apps::mojom::AppType app_type,
+    AppType app_type,
     const std::string& app_id,
-    std::vector<apps::mojom::IntentFilterPtr> all_link_filters) {
+    IntentFilters all_link_filters) {
   RunAfterPreferredAppsReady(
       base::BindOnce(&PreferredAppsImpl::SetSupportedLinksPreferenceImpl,
                      weak_ptr_factory_.GetWeakPtr(), app_type, app_id,
@@ -325,15 +325,14 @@
 }
 
 void PreferredAppsImpl::SetSupportedLinksPreferenceImpl(
-    apps::mojom::AppType mojom_app_type,
+    AppType app_type,
     const std::string& app_id,
-    std::vector<apps::mojom::IntentFilterPtr> all_link_filters) {
+    IntentFilters all_link_filters) {
   auto changes = std::make_unique<PreferredAppChanges>();
   auto& added = changes->added_filters;
   auto& removed = changes->removed_filters;
 
-  for (auto& mojom_filter : all_link_filters) {
-    auto filter = ConvertMojomIntentFilterToIntentFilter(mojom_filter);
+  for (auto& filter : all_link_filters) {
     auto replaced_apps = preferred_apps_list_.AddPreferredApp(app_id, filter);
     added[app_id].push_back(std::move(filter));
 
@@ -375,7 +374,6 @@
 
   // Notify publishers: The new app has been set to open links, and all removed
   // apps no longer handle links.
-  AppType app_type = ConvertMojomAppTypToAppType(mojom_app_type);
   if (host_->HasPublisher(app_type)) {
     host_->OnSupportedLinksPreferenceChanged(app_type, app_id,
                                              /*open_in_app=*/true);
diff --git a/components/services/app_service/public/cpp/preferred_apps_impl.h b/components/services/app_service/public/cpp/preferred_apps_impl.h
index 546c41a..21cdc31 100644
--- a/components/services/app_service/public/cpp/preferred_apps_impl.h
+++ b/components/services/app_service/public/cpp/preferred_apps_impl.h
@@ -79,10 +79,9 @@
   void RemovePreferredAppForFilter(apps::mojom::AppType app_type,
                                    const std::string& app_id,
                                    apps::mojom::IntentFilterPtr intent_filter);
-  void SetSupportedLinksPreference(
-      apps::mojom::AppType app_type,
-      const std::string& app_id,
-      std::vector<apps::mojom::IntentFilterPtr> all_link_filters);
+  void SetSupportedLinksPreference(AppType app_type,
+                                   const std::string& app_id,
+                                   IntentFilters all_link_filters);
   void RemoveSupportedLinksPreference(AppType app_type,
                                       const std::string& app_id);
 
@@ -121,10 +120,9 @@
       apps::mojom::AppType app_type,
       const std::string& app_id,
       apps::mojom::IntentFilterPtr intent_filter);
-  void SetSupportedLinksPreferenceImpl(
-      apps::mojom::AppType app_type,
-      const std::string& app_id,
-      std::vector<apps::mojom::IntentFilterPtr> all_link_filters);
+  void SetSupportedLinksPreferenceImpl(AppType app_type,
+                                       const std::string& app_id,
+                                       IntentFilters all_link_filters);
   void RemoveSupportedLinksPreferenceImpl(AppType app_type,
                                           const std::string& app_id);
 
diff --git a/components/sync/base/features.h b/components/sync/base/features.h
index 70c59a2..c993295 100644
--- a/components/sync/base/features.h
+++ b/components/sync/base/features.h
@@ -145,6 +145,9 @@
 bool IsSyncTrustedVaultPassphraseiOSRPCEnabled();
 #endif  // BUILDFLAG(IS_IOS)
 
+inline constexpr base::Feature kSyncEnableHistoryDataType = {
+    "SyncEnableHistoryDataType", base::FEATURE_DISABLED_BY_DEFAULT};
+
 }  // namespace syncer
 
 #endif  // COMPONENTS_SYNC_BASE_FEATURES_H_
diff --git a/components/viz/common/resources/transferable_resource.h b/components/viz/common/resources/transferable_resource.h
index 0a360bc3..6d4d7ec 100644
--- a/components/viz/common/resources/transferable_resource.h
+++ b/components/viz/common/resources/transferable_resource.h
@@ -27,6 +27,19 @@
 struct ReturnedResource;
 
 struct VIZ_COMMON_EXPORT TransferableResource {
+  enum class SynchronizationType : uint8_t {
+    // Commands issued (SyncToken) - a resource can be reused as soon as display
+    // compositor issues the latest command on it and SyncToken will be signaled
+    // when this happens.
+    kSyncToken = 0,
+    // Commands completed (aka read lock fence) - If a gpu resource is backed by
+    // a GpuMemoryBuffer, then it will be accessed out-of-band, and a gpu fence
+    // needs to be waited on before the resource is returned and reused. In
+    // other words, the resource will be returned only when gpu commands are
+    // completed.
+    kGpuCommandsCompleted,
+  };
+
   TransferableResource();
   ~TransferableResource();
 
@@ -104,10 +117,10 @@
   // drawing it. Typically GL_LINEAR, or GL_NEAREST if no anti-aliasing
   // during scaling is desired.
   uint32_t filter = 0;
-  // If a gpu resource is backed by a GpuMemoryBuffer, then it will be accessed
-  // out-of-band, and a gpu fence needs to be waited on before the resource is
-  // returned and reused.
-  bool read_lock_fences_enabled = false;
+
+  // This defines when the display compositor returns resources. Clients may use
+  // different synchronization types based on their needs.
+  SynchronizationType synchronization_type = SynchronizationType::kSyncToken;
 
   // YCbCr info for resources backed by YCbCr Vulkan images.
   absl::optional<gpu::VulkanYCbCrInfo> ycbcr_info;
@@ -145,7 +158,7 @@
 #elif BUILDFLAG(IS_WIN)
            wants_promotion_hint == o.wants_promotion_hint &&
 #endif
-           read_lock_fences_enabled == o.read_lock_fences_enabled;
+           synchronization_type == o.synchronization_type;
   }
   bool operator!=(const TransferableResource& o) const { return !(*this == o); }
 };
diff --git a/components/viz/service/display/display_resource_provider.cc b/components/viz/service/display/display_resource_provider.cc
index eb87fff4..766002c 100644
--- a/components/viz/service/display/display_resource_provider.cc
+++ b/components/viz/service/display/display_resource_provider.cc
@@ -473,7 +473,8 @@
 bool DisplayResourceProvider::ScopedReadLockSharedImage::HasReadLockFence()
     const {
   DCHECK(resource_);
-  return resource_->transferable.read_lock_fences_enabled;
+  return resource_->transferable.synchronization_type ==
+         TransferableResource::SynchronizationType::kGpuCommandsCompleted;
 }
 
 void DisplayResourceProvider::ScopedReadLockSharedImage::Reset() {
diff --git a/components/viz/service/display/display_resource_provider_gl.cc b/components/viz/service/display/display_resource_provider_gl.cc
index 501cd71..6b8ed37 100644
--- a/components/viz/service/display/display_resource_provider_gl.cc
+++ b/components/viz/service/display/display_resource_provider_gl.cc
@@ -141,7 +141,8 @@
     resource->lock_for_overlay_count++;
   else
     resource->lock_for_read_count++;
-  if (resource->transferable.read_lock_fences_enabled) {
+  if (resource->transferable.synchronization_type ==
+      TransferableResource::SynchronizationType::kGpuCommandsCompleted) {
     if (current_read_lock_fence_.get())
       current_read_lock_fence_->Set();
     resource->read_lock_fence = current_read_lock_fence_;
@@ -396,7 +397,8 @@
 bool DisplayResourceProviderGL::ScopedOverlayLockGL::HasReadLockFence() const {
   auto* resource = resource_provider_->GetResource(resource_id_);
   DCHECK(resource);
-  return resource->transferable.read_lock_fences_enabled;
+  return resource->transferable.synchronization_type ==
+         TransferableResource::SynchronizationType::kGpuCommandsCompleted;
 }
 
 DisplayResourceProviderGL::SynchronousFence::SynchronousFence(
diff --git a/components/viz/service/display/display_resource_provider_gl_unittest.cc b/components/viz/service/display/display_resource_provider_gl_unittest.cc
index 1c2d058..a71ac8d9 100644
--- a/components/viz/service/display/display_resource_provider_gl_unittest.cc
+++ b/components/viz/service/display/display_resource_provider_gl_unittest.cc
@@ -233,7 +233,8 @@
 TEST_F(DisplayResourceProviderGLTest, ReadLockFenceStopsReturnToChildOrDelete) {
   MockReleaseCallback release;
   TransferableResource tran1 = CreateResource(RGBA_8888);
-  tran1.read_lock_fences_enabled = true;
+  tran1.synchronization_type =
+      TransferableResource::SynchronizationType::kGpuCommandsCompleted;
   ResourceId id1 = child_resource_provider_->ImportResource(
       tran1, base::BindOnce(&MockReleaseCallback::Released,
                             base::Unretained(&release)));
@@ -249,7 +250,8 @@
       static_cast<RasterContextProvider*>(child_context_provider_.get()));
   ASSERT_EQ(1u, list.size());
   EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
-  EXPECT_TRUE(list[0].read_lock_fences_enabled);
+  EXPECT_EQ(list[0].synchronization_type,
+            TransferableResource::SynchronizationType::kGpuCommandsCompleted);
 
   resource_provider_->ReceiveFromChild(child_id, list);
 
@@ -285,13 +287,15 @@
   MockReleaseCallback release;
 
   TransferableResource tran1 = CreateResource(RGBA_8888);
-  tran1.read_lock_fences_enabled = true;
+  tran1.synchronization_type =
+      TransferableResource::SynchronizationType::kGpuCommandsCompleted;
   ResourceId id1 = child_resource_provider_->ImportResource(
       tran1, base::BindOnce(&MockReleaseCallback::Released,
                             base::Unretained(&release)));
 
   TransferableResource tran2 = CreateResource(RGBA_8888);
-  tran2.read_lock_fences_enabled = false;
+  ASSERT_EQ(tran2.synchronization_type,
+            TransferableResource::SynchronizationType::kSyncToken);
   ResourceId id2 = child_resource_provider_->ImportResource(
       tran2, base::BindOnce(&MockReleaseCallback::Released,
                             base::Unretained(&release)));
diff --git a/components/viz/service/display/display_resource_provider_skia.cc b/components/viz/service/display/display_resource_provider_skia.cc
index 1a9aaa7..fcd0506f 100644
--- a/components/viz/service/display/display_resource_provider_skia.cc
+++ b/components/viz/service/display/display_resource_provider_skia.cc
@@ -167,7 +167,8 @@
     }
     resource.locked_for_external_use = true;
 
-    if (resource.transferable.read_lock_fences_enabled) {
+    if (resource.transferable.synchronization_type ==
+        TransferableResource::SynchronizationType::kGpuCommandsCompleted) {
       if (resource_provider_->current_read_lock_fence_.get())
         resource_provider_->current_read_lock_fence_->Set();
       resource.read_lock_fence = resource_provider_->current_read_lock_fence_;
diff --git a/components/viz/service/display/display_resource_provider_skia_unittest.cc b/components/viz/service/display/display_resource_provider_skia_unittest.cc
index 35ac8f1..6a1486cd 100644
--- a/components/viz/service/display/display_resource_provider_skia_unittest.cc
+++ b/components/viz/service/display/display_resource_provider_skia_unittest.cc
@@ -314,7 +314,8 @@
        ReadLockFenceStopsReturnToChildOrDelete) {
   MockReleaseCallback release;
   TransferableResource tran1 = CreateResource(RGBA_8888);
-  tran1.read_lock_fences_enabled = true;
+  tran1.synchronization_type =
+      TransferableResource::SynchronizationType::kGpuCommandsCompleted;
   ResourceId id1 = child_resource_provider_->ImportResource(
       tran1, base::BindOnce(&MockReleaseCallback::Released,
                             base::Unretained(&release)));
@@ -330,7 +331,8 @@
       static_cast<RasterContextProvider*>(child_context_provider_.get()));
   ASSERT_EQ(1u, list.size());
   EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
-  EXPECT_TRUE(list[0].read_lock_fences_enabled);
+  EXPECT_EQ(list[0].synchronization_type,
+            TransferableResource::SynchronizationType::kGpuCommandsCompleted);
 
   resource_provider_->ReceiveFromChild(child_id, list);
 
@@ -366,13 +368,15 @@
   MockReleaseCallback release;
 
   TransferableResource tran1 = CreateResource(RGBA_8888);
-  tran1.read_lock_fences_enabled = true;
+  tran1.synchronization_type =
+      TransferableResource::SynchronizationType::kGpuCommandsCompleted;
   ResourceId id1 = child_resource_provider_->ImportResource(
       tran1, base::BindOnce(&MockReleaseCallback::Released,
                             base::Unretained(&release)));
 
   TransferableResource tran2 = CreateResource(RGBA_8888);
-  tran2.read_lock_fences_enabled = false;
+  ASSERT_EQ(tran2.synchronization_type,
+            TransferableResource::SynchronizationType::kSyncToken);
   ResourceId id2 = child_resource_provider_->ImportResource(
       tran2, base::BindOnce(&MockReleaseCallback::Released,
                             base::Unretained(&release)));
diff --git a/content/BUILD.gn b/content/BUILD.gn
index 8e616f8..be01977 100644
--- a/content/BUILD.gn
+++ b/content/BUILD.gn
@@ -114,9 +114,9 @@
   deps = [
     "//content/browser/attribution_reporting:mojo_bindings_webui_js",
     "//content/browser/prerender:mojo_bindings_webui_js",
-    "//content/browser/process_internals:mojo_bindings_webui_js",
     "//content/browser/resources/attribution_reporting:build_ts",
     "//content/browser/resources/gpu:web_components",
+    "//content/browser/resources/process:build_ts",
     "//storage/browser/quota:mojo_bindings_webui_js",
   ]
 }
diff --git a/content/browser/attribution_reporting/attribution_interop_parser_unittest.cc b/content/browser/attribution_reporting/attribution_interop_parser_unittest.cc
index dfe463afb..d7c7a39 100644
--- a/content/browser/attribution_reporting/attribution_interop_parser_unittest.cc
+++ b/content/browser/attribution_reporting/attribution_interop_parser_unittest.cc
@@ -103,6 +103,7 @@
         "report_url": "https://r.example/path",
         "report": {
           "attribution_destination": "https://d.test",
+          "source_site": "https://s.test"
         },
         "test_info": {
           "histograms": [{
@@ -130,6 +131,7 @@
         "report_url": "https://r.example/path",
         "payload": {
           "attribution_destination": "https://d.test",
+          "source_site": "https://s.test",
           "histograms": [{
             "key": "key",
             "value": "0x159"
diff --git a/content/browser/attribution_reporting/attribution_report.cc b/content/browser/attribution_reporting/attribution_report.cc
index 7314e923..d81e437 100644
--- a/content/browser/attribution_reporting/attribution_report.cc
+++ b/content/browser/attribution_reporting/attribution_report.cc
@@ -201,6 +201,7 @@
       const CommonSourceInfo& common_info =
           report->attribution_info().source.common_info();
 
+      dict.Set("source_site", common_info.ImpressionSite().Serialize());
       dict.Set("attribution_destination",
                common_info.ConversionDestination().Serialize());
 
diff --git a/content/browser/buckets/bucket_manager_host.cc b/content/browser/buckets/bucket_manager_host.cc
index 94f9ad89..5dcdbf9 100644
--- a/content/browser/buckets/bucket_manager_host.cc
+++ b/content/browser/buckets/bucket_manager_host.cc
@@ -145,8 +145,9 @@
     storage::QuotaErrorOr<storage::BucketInfo> result) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  if (!result.ok()) {
-    // Getting a bucket can fail if there is a database error.
+  if (!result.ok() || !receivers_.HasReceiver(receiver_id)) {
+    // Getting a bucket can fail if there is a database error, and the receiver
+    // could have been disconnected by now.
     std::move(callback).Run(mojo::NullRemote());
     return;
   }
@@ -160,6 +161,7 @@
   }
 
   auto permission_it = permission_decider_map_.find(receiver_id);
+  CHECK(permission_it != permission_decider_map_.end());
   auto pending_remote =
       it->second->CreateStorageBucketBinding(permission_it->second);
   std::move(callback).Run(std::move(pending_remote));
diff --git a/content/browser/devtools/protocol/page_handler.cc b/content/browser/devtools/protocol/page_handler.cc
index fd4a966..5a0eb1e7 100644
--- a/content/browser/devtools/protocol/page_handler.cc
+++ b/content/browser/devtools/protocol/page_handler.cc
@@ -1279,9 +1279,11 @@
 }
 
 Response PageHandler::StopLoading() {
-  WebContentsImpl* web_contents = GetWebContents();
-  if (!web_contents)
-    return Response::InternalError();
+  Response response = AssureTopLevelActiveFrame(host_);
+  if (response.IsError())
+    return response;
+
+  WebContents* web_contents = WebContents::FromRenderFrameHost(host_);
   web_contents->Stop();
   return Response::Success();
 }
diff --git a/content/browser/file_system_access/file_system_access_directory_handle_impl_unittest.cc b/content/browser/file_system_access/file_system_access_directory_handle_impl_unittest.cc
index 0462cc6..7116ae7c 100644
--- a/content/browser/file_system_access/file_system_access_directory_handle_impl_unittest.cc
+++ b/content/browser/file_system_access/file_system_access_directory_handle_impl_unittest.cc
@@ -361,9 +361,8 @@
           EXPECT_FALSE(base::PathExists(file));
           // The write lock acquired during the operation should be released by
           // the time the callback runs.
-          auto write_lock =
-              manager_->TakeWriteLock(file_url, WriteLockType::kExclusive);
-          EXPECT_TRUE(write_lock.has_value());
+          EXPECT_TRUE(
+              manager_->TakeWriteLock(file_url, WriteLockType::kExclusive));
         }).Then(loop.QuitClosure()));
     loop.Run();
   }
@@ -377,7 +376,7 @@
               base::File::Error::FILE_OK);
     auto write_lock =
         manager_->TakeWriteLock(file_url, WriteLockType::kExclusive);
-    EXPECT_TRUE(write_lock.has_value());
+    EXPECT_TRUE(write_lock);
 
     base::RunLoop loop;
     handle->RemoveEntry(base_name,
@@ -401,8 +400,8 @@
     EXPECT_EQ(handle->GetChildURL(base_name, &file_url)->file_error,
               base::File::Error::FILE_OK);
     auto write_lock = manager_->TakeWriteLock(file_url, WriteLockType::kShared);
-    EXPECT_TRUE(write_lock.has_value());
-    EXPECT_TRUE(write_lock.value()->type() == WriteLockType::kShared);
+    ASSERT_TRUE(write_lock);
+    EXPECT_TRUE(write_lock->type() == WriteLockType::kShared);
 
     base::RunLoop loop;
     handle->RemoveEntry(
diff --git a/content/browser/file_system_access/file_system_access_file_handle_impl.cc b/content/browser/file_system_access/file_system_access_file_handle_impl.cc
index be077d4..505b993 100644
--- a/content/browser/file_system_access/file_system_access_file_handle_impl.cc
+++ b/content/browser/file_system_access/file_system_access_file_handle_impl.cc
@@ -218,7 +218,7 @@
   }
 
   auto lock = manager()->TakeWriteLock(url(), WriteLockType::kExclusive);
-  if (!lock.has_value()) {
+  if (!lock) {
     std::move(callback).Run(
         file_system_access_error::FromStatus(
             FileSystemAccessStatus::kNoModificationAllowedError,
@@ -232,9 +232,9 @@
   auto open_file_callback =
       file_system_context()->is_incognito()
           ? base::BindOnce(&FileSystemAccessFileHandleImpl::DoOpenIncognitoFile,
-                           weak_factory_.GetWeakPtr(), std::move(lock.value()))
+                           weak_factory_.GetWeakPtr(), std::move(lock))
           : base::BindOnce(&FileSystemAccessFileHandleImpl::DoOpenFile,
-                           weak_factory_.GetWeakPtr(), std::move(lock.value()));
+                           weak_factory_.GetWeakPtr(), std::move(lock));
   RunWithWritePermission(
       std::move(open_file_callback),
       base::BindOnce([](blink::mojom::FileSystemAccessErrorPtr result,
@@ -494,7 +494,7 @@
   }
 
   auto lock = manager()->TakeWriteLock(url(), WriteLockType::kShared);
-  if (!lock.has_value()) {
+  if (!lock) {
     std::move(callback).Run(
         file_system_access_error::FromStatus(
             FileSystemAccessStatus::kNoModificationAllowedError,
@@ -513,7 +513,7 @@
   // Writer creation request owns the file and eliminates possible race
   // conditions.
   CreateSwapFile(
-      /*count=*/0, keep_existing_data, auto_close, std::move(lock.value()),
+      /*count=*/0, keep_existing_data, auto_close, std::move(lock),
       std::move(callback));
 }
 
diff --git a/content/browser/file_system_access/file_system_access_file_writer_impl_unittest.cc b/content/browser/file_system_access/file_system_access_file_writer_impl_unittest.cc
index e34a9c3..9512d44 100644
--- a/content/browser/file_system_access/file_system_access_file_writer_impl_unittest.cc
+++ b/content/browser/file_system_access/file_system_access_file_writer_impl_unittest.cc
@@ -154,12 +154,12 @@
     auto lock = manager_->TakeWriteLock(
         test_file_url_,
         FileSystemAccessWriteLockManager::WriteLockType::kShared);
-    ASSERT_TRUE(lock.has_value());
+    ASSERT_TRUE(lock);
 
     handle_ = manager_->CreateFileWriter(
         FileSystemAccessManagerImpl::BindingContext(kTestStorageKey, kTestURL,
                                                     kFrameId),
-        test_file_url_, test_swap_url_, std::move(lock.value()),
+        test_file_url_, test_swap_url_, std::move(lock),
         FileSystemAccessManagerImpl::SharedHandleState(permission_grant_,
                                                        permission_grant_),
         remote_.InitWithNewPipeAndPassReceiver(),
@@ -614,13 +614,13 @@
 
   auto lock = manager_->TakeWriteLock(
       test_file_url_, FileSystemAccessWriteLockManager::WriteLockType::kShared);
-  ASSERT_TRUE(lock.has_value());
+  ASSERT_TRUE(lock);
 
   mojo::PendingRemote<blink::mojom::FileSystemAccessFileWriter> remote;
   handle_ = manager_->CreateFileWriter(
       FileSystemAccessManagerImpl::BindingContext(kTestStorageKey, kTestURL,
                                                   kFrameId),
-      test_file_url_, test_swap_url_, std::move(lock.value()),
+      test_file_url_, test_swap_url_, std::move(lock),
       FileSystemAccessManagerImpl::SharedHandleState(permission_grant_,
                                                      permission_grant_),
       remote.InitWithNewPipeAndPassReceiver(),
diff --git a/content/browser/file_system_access/file_system_access_handle_base.cc b/content/browser/file_system_access/file_system_access_handle_base.cc
index db0ad64..1ce8513 100644
--- a/content/browser/file_system_access/file_system_access_handle_base.cc
+++ b/content/browser/file_system_access/file_system_access_handle_base.cc
@@ -345,7 +345,7 @@
   std::vector<scoped_refptr<WriteLock>> locks;
   auto source_write_lock =
       manager()->TakeWriteLock(url(), WriteLockType::kExclusive);
-  if (!source_write_lock.has_value()) {
+  if (!source_write_lock) {
     std::move(callback).Run(file_system_access_error::FromStatus(
         blink::mojom::FileSystemAccessStatus::kNoModificationAllowedError,
         base::StrCat(
@@ -353,14 +353,14 @@
              ". A FileSystemHandle cannot be moved while it is locked."})));
     return;
   }
-  locks.emplace_back(std::move(source_write_lock.value()));
+  locks.emplace_back(std::move(source_write_lock));
 
   // Since we're using exclusive locks, we should only acquire the
   // lock of the destination URL if it is different from the source URL.
   if (url() != dest_url) {
     auto dest_write_lock =
         manager()->TakeWriteLock(dest_url, WriteLockType::kExclusive);
-    if (!dest_write_lock.has_value()) {
+    if (!dest_write_lock) {
       std::move(callback).Run(file_system_access_error::FromStatus(
           blink::mojom::FileSystemAccessStatus::kNoModificationAllowedError,
           base::StrCat({"Failed to move ", GetURLDisplayName(url()), " to ",
@@ -369,7 +369,7 @@
                         "which is locked."})));
       return;
     }
-    locks.emplace_back(std::move(dest_write_lock.value()));
+    locks.emplace_back(std::move(dest_write_lock));
   }
 
   auto safe_move_helper = std::make_unique<SafeMoveHelper>(
@@ -417,12 +417,12 @@
   // TODO(crbug.com/1252614): A directory should only be able to be removed if
   // none of the containing files are locked.
   auto write_lock = manager()->TakeWriteLock(url, lock_type);
-  if (!write_lock.has_value()) {
+  if (!write_lock) {
     std::move(callback).Run(file_system_access_error::FromStatus(
         blink::mojom::FileSystemAccessStatus::kNoModificationAllowedError));
     return;
   }
-  write_locks.push_back(std::move(write_lock.value()));
+  write_locks.push_back(std::move(write_lock));
 
   // Bind the `write_locks` to the Remove callback to guarantee the locks are
   // held until the operation completes.
diff --git a/content/browser/file_system_access/file_system_access_manager_impl.cc b/content/browser/file_system_access/file_system_access_manager_impl.cc
index 2722a75..a938af7b 100644
--- a/content/browser/file_system_access/file_system_access_manager_impl.cc
+++ b/content/browser/file_system_access/file_system_access_manager_impl.cc
@@ -949,7 +949,7 @@
       result.InitWithNewPipeAndPassReceiver());
   return result;
 }
-absl::optional<scoped_refptr<FileSystemAccessWriteLockManager::WriteLock>>
+scoped_refptr<FileSystemAccessWriteLockManager::WriteLock>
 FileSystemAccessManagerImpl::TakeWriteLock(
     const storage::FileSystemURL& url,
     FileSystemAccessWriteLockManager::WriteLockType lock_type) {
diff --git a/content/browser/file_system_access/file_system_access_manager_impl.h b/content/browser/file_system_access/file_system_access_manager_impl.h
index 5fa09888..4e6e23b 100644
--- a/content/browser/file_system_access/file_system_access_manager_impl.h
+++ b/content/browser/file_system_access/file_system_access_manager_impl.h
@@ -178,9 +178,9 @@
                         const SharedHandleState& handle_state);
   // Attempts to take a write lock on `url`. The lock is released when the
   // returned object is destroyed.
-  absl::optional<scoped_refptr<FileSystemAccessWriteLockManager::WriteLock>>
-  TakeWriteLock(const storage::FileSystemURL& url,
-                FileSystemAccessWriteLockManager::WriteLockType lock_type);
+  scoped_refptr<FileSystemAccessWriteLockManager::WriteLock> TakeWriteLock(
+      const storage::FileSystemURL& url,
+      FileSystemAccessWriteLockManager::WriteLockType lock_type);
 
   // Creates a new FileSystemAccessFileWriterImpl for a given target and
   // swap file URLs. Assumes the passed in URLs are valid and represent files.
diff --git a/content/browser/file_system_access/file_system_access_manager_impl_unittest.cc b/content/browser/file_system_access/file_system_access_manager_impl_unittest.cc
index 71e10ab..8b2caa7 100644
--- a/content/browser/file_system_access/file_system_access_manager_impl_unittest.cc
+++ b/content/browser/file_system_access/file_system_access_manager_impl_unittest.cc
@@ -587,11 +587,11 @@
 
   auto lock = manager_->TakeWriteLock(
       test_file_url, FileSystemAccessWriteLockManager::WriteLockType::kShared);
-  ASSERT_TRUE(lock.has_value());
+  ASSERT_TRUE(lock);
 
   mojo::Remote<blink::mojom::FileSystemAccessFileWriter> writer_remote(
       manager_->CreateFileWriter(kBindingContext, test_file_url, test_swap_url,
-                                 std::move(lock.value()),
+                                 std::move(lock),
                                  FileSystemAccessManagerImpl::SharedHandleState(
                                      allow_grant_, allow_grant_),
                                  /*auto_close=*/false));
@@ -625,11 +625,11 @@
 
   auto lock = manager_->TakeWriteLock(
       test_file_url, FileSystemAccessWriteLockManager::WriteLockType::kShared);
-  ASSERT_TRUE(lock.has_value());
+  ASSERT_TRUE(lock);
 
   mojo::Remote<blink::mojom::FileSystemAccessFileWriter> writer_remote(
       manager_->CreateFileWriter(kBindingContext, test_file_url, test_swap_url,
-                                 std::move(lock.value()),
+                                 std::move(lock),
                                  FileSystemAccessManagerImpl::SharedHandleState(
                                      allow_grant_, allow_grant_),
                                  /*auto_close=*/false));
@@ -674,11 +674,11 @@
 
   auto lock = manager_->TakeWriteLock(
       test_file_url, FileSystemAccessWriteLockManager::WriteLockType::kShared);
-  ASSERT_TRUE(lock.has_value());
+  ASSERT_TRUE(lock);
 
   mojo::Remote<blink::mojom::FileSystemAccessFileWriter> writer_remote(
       manager_->CreateFileWriter(kBindingContext, test_file_url, test_swap_url,
-                                 std::move(lock.value()),
+                                 std::move(lock),
                                  FileSystemAccessManagerImpl::SharedHandleState(
                                      allow_grant_, allow_grant_),
                                  /*auto_close=*/false));
@@ -712,11 +712,11 @@
 
   auto lock = manager_->TakeWriteLock(
       test_file_url, FileSystemAccessWriteLockManager::WriteLockType::kShared);
-  ASSERT_TRUE(lock.has_value());
+  ASSERT_TRUE(lock);
 
   mojo::Remote<blink::mojom::FileSystemAccessFileWriter> writer_remote(
       manager_->CreateFileWriter(kBindingContext, test_file_url, test_swap_url,
-                                 std::move(lock.value()),
+                                 std::move(lock),
                                  FileSystemAccessManagerImpl::SharedHandleState(
                                      allow_grant_, allow_grant_),
                                  /*auto_close=*/true));
diff --git a/content/browser/file_system_access/file_system_access_write_lock_manager.cc b/content/browser/file_system_access/file_system_access_write_lock_manager.cc
index 0b0a336e..f8d7533 100644
--- a/content/browser/file_system_access/file_system_access_write_lock_manager.cc
+++ b/content/browser/file_system_access/file_system_access_write_lock_manager.cc
@@ -97,17 +97,16 @@
 
 FileSystemAccessWriteLockManager::~FileSystemAccessWriteLockManager() = default;
 
-absl::optional<scoped_refptr<WriteLock>>
-FileSystemAccessWriteLockManager::TakeLock(const storage::FileSystemURL& url,
-                                           WriteLockType lock_type) {
+scoped_refptr<WriteLock> FileSystemAccessWriteLockManager::TakeLock(
+    const storage::FileSystemURL& url,
+    WriteLockType lock_type) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   EntryLocator entry_locator = EntryLocator::FromFileSystemURL(url);
   return TakeLockImpl(entry_locator, lock_type);
 }
 
-absl::optional<scoped_refptr<WriteLock>>
-FileSystemAccessWriteLockManager::TakeLockImpl(
+scoped_refptr<WriteLock> FileSystemAccessWriteLockManager::TakeLockImpl(
     const EntryLocator& entry_locator,
     WriteLockType lock_type) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -124,12 +123,9 @@
     if (parent_path != entry_locator.path) {
       EntryLocator parent_entry_locator{entry_locator.type, parent_path,
                                         entry_locator.bucket_locator};
-      auto maybe_parent_lock =
-          TakeLockImpl(parent_entry_locator, WriteLockType::kShared);
-      if (!maybe_parent_lock.has_value())
-        return absl::nullopt;
-
-      parent_lock = std::move(maybe_parent_lock.value());
+      parent_lock = TakeLockImpl(parent_entry_locator, WriteLockType::kShared);
+      if (!parent_lock)
+        return nullptr;
     }
 
     // There are no locks on the file, we can take any type of lock.
@@ -153,7 +149,7 @@
       existing_lock->type() == WriteLockType::kExclusive) {
     // There is an existing lock, and either it or the requested lock is
     // exclusive. Therefore it is not possible to take a new lock.
-    return absl::nullopt;
+    return nullptr;
   }
 
   // There is an existing shared lock, and the requested lock is also shared.
diff --git a/content/browser/file_system_access/file_system_access_write_lock_manager.h b/content/browser/file_system_access/file_system_access_write_lock_manager.h
index a3838e53..60f3b386 100644
--- a/content/browser/file_system_access/file_system_access_write_lock_manager.h
+++ b/content/browser/file_system_access/file_system_access_write_lock_manager.h
@@ -124,14 +124,12 @@
       FileSystemAccessWriteLockManager const&) = delete;
 
   // Attempts to take a lock on `url`. Returns the lock if successful.
-  absl::optional<scoped_refptr<WriteLock>> TakeLock(
-      const storage::FileSystemURL& url,
-      WriteLockType lock_type);
+  scoped_refptr<WriteLock> TakeLock(const storage::FileSystemURL& url,
+                                    WriteLockType lock_type);
 
  private:
-  absl::optional<scoped_refptr<WriteLock>> TakeLockImpl(
-      const EntryLocator& entry_locator,
-      WriteLockType lock_type);
+  scoped_refptr<WriteLock> TakeLockImpl(const EntryLocator& entry_locator,
+                                        WriteLockType lock_type);
 
   // Releases the lock on `entry_locator`. Called from the WriteLock destructor.
   void ReleaseLock(const EntryLocator& entry_locator);
diff --git a/content/browser/file_system_access/file_system_access_write_lock_manager_unittest.cc b/content/browser/file_system_access/file_system_access_write_lock_manager_unittest.cc
index c31b66a..06075cee 100644
--- a/content/browser/file_system_access/file_system_access_write_lock_manager_unittest.cc
+++ b/content/browser/file_system_access/file_system_access_write_lock_manager_unittest.cc
@@ -72,88 +72,68 @@
     {
       auto child_lock =
           manager_->TakeWriteLock(child_url, WriteLockType::kExclusive);
-      ASSERT_TRUE(child_lock.has_value());
-
-      auto parent_lock =
-          manager_->TakeWriteLock(parent_url, WriteLockType::kExclusive);
-      ASSERT_FALSE(parent_lock.has_value());
+      ASSERT_TRUE(child_lock);
+      ASSERT_FALSE(
+          manager_->TakeWriteLock(parent_url, WriteLockType::kExclusive));
     }
 
     // Parent can take shared lock if child is exclusively locked.
     {
       auto child_lock =
           manager_->TakeWriteLock(child_url, WriteLockType::kExclusive);
-      ASSERT_TRUE(child_lock.has_value());
-
-      auto parent_lock =
-          manager_->TakeWriteLock(parent_url, WriteLockType::kShared);
-      ASSERT_TRUE(parent_lock.has_value());
+      ASSERT_TRUE(child_lock);
+      ASSERT_TRUE(manager_->TakeWriteLock(parent_url, WriteLockType::kShared));
     }
 
     // Child cannot take exclusive lock if parent is exclusively locked.
     {
       auto parent_lock =
           manager_->TakeWriteLock(parent_url, WriteLockType::kExclusive);
-      ASSERT_TRUE(parent_lock.has_value());
-
-      auto child_lock =
-          manager_->TakeWriteLock(child_url, WriteLockType::kExclusive);
-      ASSERT_FALSE(child_lock.has_value());
+      ASSERT_TRUE(parent_lock);
+      ASSERT_FALSE(
+          manager_->TakeWriteLock(child_url, WriteLockType::kExclusive));
     }
 
     // Child cannot take shared lock if parent is exclusively locked.
     {
       auto parent_lock =
           manager_->TakeWriteLock(parent_url, WriteLockType::kExclusive);
-      ASSERT_TRUE(parent_lock.has_value());
-
-      auto child_lock =
-          manager_->TakeWriteLock(child_url, WriteLockType::kShared);
-      ASSERT_FALSE(child_lock.has_value());
+      ASSERT_TRUE(parent_lock);
+      ASSERT_FALSE(manager_->TakeWriteLock(child_url, WriteLockType::kShared));
     }
 
     // Parent cannot take exclusive lock if child holds a shared lock.
     {
       auto child_lock =
           manager_->TakeWriteLock(child_url, WriteLockType::kShared);
-      ASSERT_TRUE(child_lock.has_value());
-
-      auto parent_lock =
-          manager_->TakeWriteLock(parent_url, WriteLockType::kExclusive);
-      ASSERT_FALSE(parent_lock.has_value());
+      ASSERT_TRUE(child_lock);
+      ASSERT_FALSE(
+          manager_->TakeWriteLock(parent_url, WriteLockType::kExclusive));
     }
 
     // Parent can take shared lock if child holds a shared lock.
     {
       auto child_lock =
           manager_->TakeWriteLock(child_url, WriteLockType::kShared);
-      ASSERT_TRUE(child_lock.has_value());
-
-      auto parent_lock =
-          manager_->TakeWriteLock(parent_url, WriteLockType::kShared);
-      ASSERT_TRUE(parent_lock.has_value());
+      ASSERT_TRUE(child_lock);
+      ASSERT_TRUE(manager_->TakeWriteLock(parent_url, WriteLockType::kShared));
     }
 
     // Child can take exclusive lock if parent holds a shared lock.
     {
       auto parent_lock =
           manager_->TakeWriteLock(parent_url, WriteLockType::kShared);
-      ASSERT_TRUE(parent_lock.has_value());
-
-      auto child_lock =
-          manager_->TakeWriteLock(child_url, WriteLockType::kExclusive);
-      ASSERT_TRUE(child_lock.has_value());
+      ASSERT_TRUE(parent_lock);
+      ASSERT_TRUE(
+          manager_->TakeWriteLock(child_url, WriteLockType::kExclusive));
     }
 
     // Child can take shared lock if parent holds a shared lock.
     {
       auto parent_lock =
           manager_->TakeWriteLock(parent_url, WriteLockType::kShared);
-      ASSERT_TRUE(parent_lock.has_value());
-
-      auto child_lock =
-          manager_->TakeWriteLock(child_url, WriteLockType::kShared);
-      ASSERT_TRUE(child_lock.has_value());
+      ASSERT_TRUE(parent_lock);
+      ASSERT_TRUE(manager_->TakeWriteLock(child_url, WriteLockType::kShared));
     }
   }
 
@@ -177,20 +157,16 @@
   {
     auto exclusive_lock =
         manager_->TakeWriteLock(url, WriteLockType::kExclusive);
-    ASSERT_TRUE(exclusive_lock.has_value());
+    ASSERT_TRUE(exclusive_lock);
 
     // Cannot take another lock while the file is exclusively locked.
-    auto another_exclusive_lock =
-        manager_->TakeWriteLock(url, WriteLockType::kExclusive);
-    ASSERT_FALSE(another_exclusive_lock.has_value());
-    auto shared_lock = manager_->TakeWriteLock(url, WriteLockType::kShared);
-    ASSERT_FALSE(shared_lock.has_value());
+    ASSERT_FALSE(manager_->TakeWriteLock(url, WriteLockType::kExclusive));
+    ASSERT_FALSE(manager_->TakeWriteLock(url, WriteLockType::kShared));
   }
 
   // The exclusive lock has been released and should be available to be
   // re-acquired.
-  auto exclusive_lock = manager_->TakeWriteLock(url, WriteLockType::kExclusive);
-  ASSERT_TRUE(exclusive_lock.has_value());
+  ASSERT_TRUE(manager_->TakeWriteLock(url, WriteLockType::kExclusive));
 }
 
 TEST_F(FileSystemAccessWriteLockManagerTest, SharedLock) {
@@ -200,21 +176,16 @@
 
   {
     auto shared_lock = manager_->TakeWriteLock(url, WriteLockType::kShared);
-    ASSERT_TRUE(shared_lock.has_value());
+    ASSERT_TRUE(shared_lock);
 
     // Can take another shared lock, but not an exclusive lock.
-    auto another_shared_lock =
-        manager_->TakeWriteLock(url, WriteLockType::kShared);
-    ASSERT_TRUE(another_shared_lock.has_value());
-    auto exclusive_lock =
-        manager_->TakeWriteLock(url, WriteLockType::kExclusive);
-    ASSERT_FALSE(exclusive_lock.has_value());
+    ASSERT_TRUE(manager_->TakeWriteLock(url, WriteLockType::kShared));
+    ASSERT_FALSE(manager_->TakeWriteLock(url, WriteLockType::kExclusive));
   }
 
   // The shared locks have been released and we should be available to acquire
   // an exclusive lock.
-  auto exclusive_lock = manager_->TakeWriteLock(url, WriteLockType::kExclusive);
-  ASSERT_TRUE(exclusive_lock.has_value());
+  ASSERT_TRUE(manager_->TakeWriteLock(url, WriteLockType::kExclusive));
 }
 
 TEST_F(FileSystemAccessWriteLockManagerTest, SandboxedFile) {
@@ -225,20 +196,16 @@
   {
     auto exclusive_lock =
         manager_->TakeWriteLock(url, WriteLockType::kExclusive);
-    ASSERT_TRUE(exclusive_lock.has_value());
+    ASSERT_TRUE(exclusive_lock);
 
     // Cannot take another lock while the file is exclusively locked.
-    auto another_exclusive_lock =
-        manager_->TakeWriteLock(url, WriteLockType::kExclusive);
-    ASSERT_FALSE(another_exclusive_lock.has_value());
-    auto shared_lock = manager_->TakeWriteLock(url, WriteLockType::kShared);
-    ASSERT_FALSE(shared_lock.has_value());
+    ASSERT_FALSE(manager_->TakeWriteLock(url, WriteLockType::kExclusive));
+    ASSERT_FALSE(manager_->TakeWriteLock(url, WriteLockType::kShared));
   }
 
   // The exclusive lock has been released and should be available to be
   // re-acquired.
-  auto exclusive_lock = manager_->TakeWriteLock(url, WriteLockType::kExclusive);
-  ASSERT_TRUE(exclusive_lock.has_value());
+  ASSERT_TRUE(manager_->TakeWriteLock(url, WriteLockType::kExclusive));
 }
 
 TEST_F(FileSystemAccessWriteLockManagerTest, SandboxedFilesSamePath) {
@@ -256,18 +223,14 @@
   // Take a lock on the file in the first file system.
   auto exclusive_lock1 =
       manager_->TakeWriteLock(url1, WriteLockType::kExclusive);
-  ASSERT_TRUE(exclusive_lock1.has_value());
-  auto another_exclusive_lock1 =
-      manager_->TakeWriteLock(url1, WriteLockType::kExclusive);
-  ASSERT_FALSE(another_exclusive_lock1.has_value());
+  ASSERT_TRUE(exclusive_lock1);
+  ASSERT_FALSE(manager_->TakeWriteLock(url1, WriteLockType::kExclusive));
 
   // Can still take a lock on the file in the second file system.
   auto exclusive_lock2 =
       manager_->TakeWriteLock(url2, WriteLockType::kExclusive);
-  ASSERT_TRUE(exclusive_lock2.has_value());
-  auto another_exclusive_lock2 =
-      manager_->TakeWriteLock(url2, WriteLockType::kExclusive);
-  ASSERT_FALSE(another_exclusive_lock2.has_value());
+  ASSERT_TRUE(exclusive_lock2);
+  ASSERT_FALSE(manager_->TakeWriteLock(url2, WriteLockType::kExclusive));
 }
 
 TEST_F(FileSystemAccessWriteLockManagerTest, DifferentBackends) {
@@ -288,18 +251,15 @@
   // Take a lock on the file in the local file system.
   auto local_exclusive_lock =
       manager_->TakeWriteLock(local_url, WriteLockType::kExclusive);
-  ASSERT_TRUE(local_exclusive_lock.has_value());
-  auto another_local_exclusive_lock =
-      manager_->TakeWriteLock(local_url, WriteLockType::kExclusive);
-  ASSERT_FALSE(another_local_exclusive_lock.has_value());
+  ASSERT_TRUE(local_exclusive_lock);
+  ASSERT_FALSE(manager_->TakeWriteLock(local_url, WriteLockType::kExclusive));
 
   // Can still take a lock on the file in the external file system.
   auto external_exclusive_lock =
       manager_->TakeWriteLock(external_url, WriteLockType::kExclusive);
-  ASSERT_TRUE(external_exclusive_lock.has_value());
-  auto another_external_exclusive_lock =
-      manager_->TakeWriteLock(external_url, WriteLockType::kExclusive);
-  ASSERT_FALSE(another_external_exclusive_lock.has_value());
+  ASSERT_TRUE(external_exclusive_lock);
+  ASSERT_FALSE(
+      manager_->TakeWriteLock(external_url, WriteLockType::kExclusive));
 }
 
 TEST_F(FileSystemAccessWriteLockManagerTest, LockAcrossSites) {
@@ -318,21 +278,16 @@
   {
     auto exclusive_lock =
         manager_->TakeWriteLock(url1, WriteLockType::kExclusive);
-    ASSERT_TRUE(exclusive_lock.has_value());
+    ASSERT_TRUE(exclusive_lock);
 
     // Other sites cannot access the file while it is exclusively locked.
-    auto another_exclusive_lock =
-        manager_->TakeWriteLock(url2, WriteLockType::kExclusive);
-    ASSERT_FALSE(another_exclusive_lock.has_value());
-    auto shared_lock = manager_->TakeWriteLock(url2, WriteLockType::kShared);
-    ASSERT_FALSE(shared_lock.has_value());
+    ASSERT_FALSE(manager_->TakeWriteLock(url2, WriteLockType::kExclusive));
+    ASSERT_FALSE(manager_->TakeWriteLock(url2, WriteLockType::kShared));
   }
 
   // The exclusive lock has been released and should be available to be
   // re-acquired.
-  auto exclusive_lock =
-      manager_->TakeWriteLock(url2, WriteLockType::kExclusive);
-  ASSERT_TRUE(exclusive_lock.has_value());
+  ASSERT_TRUE(manager_->TakeWriteLock(url2, WriteLockType::kExclusive));
 }
 
 TEST_F(FileSystemAccessWriteLockManagerTest, AncestorLocks) {
diff --git a/content/browser/file_system_access/safe_move_helper_unittest.cc b/content/browser/file_system_access/safe_move_helper_unittest.cc
index ae4b1eb..505c6fa 100644
--- a/content/browser/file_system_access/safe_move_helper_unittest.cc
+++ b/content/browser/file_system_access/safe_move_helper_unittest.cc
@@ -154,10 +154,9 @@
           quarantine_receivers_.Add(&quarantine_, std::move(receiver));
         });
 
-    auto lock = manager_->TakeWriteLock(
+    ASSERT_TRUE(manager_->TakeWriteLock(
         test_dest_url_,
-        FileSystemAccessWriteLockManager::WriteLockType::kShared);
-    ASSERT_TRUE(lock.has_value());
+        FileSystemAccessWriteLockManager::WriteLockType::kShared));
 
     helper_ = std::make_unique<SafeMoveHelper>(
         manager_->AsWeakPtr(),
diff --git a/content/browser/resources/BUILD.gn b/content/browser/resources/BUILD.gn
index be349189..fa5b8c4 100644
--- a/content/browser/resources/BUILD.gn
+++ b/content/browser/resources/BUILD.gn
@@ -10,9 +10,6 @@
 
 if (enable_js_type_check) {
   group("closure_compile") {
-    deps = [
-      "histograms:closure_compile",
-      "process:closure_compile",
-    ]
+    deps = [ "histograms:closure_compile" ]
   }
 }
diff --git a/content/browser/resources/process/BUILD.gn b/content/browser/resources/process/BUILD.gn
index db6203a..5151efb 100644
--- a/content/browser/resources/process/BUILD.gn
+++ b/content/browser/resources/process/BUILD.gn
@@ -2,19 +2,30 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//third_party/closure_compiler/compile_js.gni")
+import("//tools/typescript/ts_library.gni")
 
-js_type_check("closure_compile") {
-  deps = [ ":process_internals" ]
-  closure_flags =
-      default_closure_args + mojom_js_args + [
-        "js_module_root=" + rebase_path(".", root_build_dir),
-        "js_module_root=" + rebase_path(
-                "$root_gen_dir/mojom-webui/content/browser/process_internals",
-                root_build_dir),
-      ]
+# Copy (via creating sym links) all the other files into the same folder for
+# ts_library.
+copy("copy_files") {
+  deps = [ "//content/browser/process_internals:mojo_bindings_webui_js" ]
+  sources = [
+    "$root_gen_dir/mojom-webui/content/browser/process_internals/process_internals.mojom-webui.js",
+    "process_internals.ts",
+  ]
+  outputs = [ "$target_gen_dir/{{source_file_part}}" ]
 }
 
-js_library("process_internals") {
-  deps = [ "//content/browser/process_internals:mojo_bindings_webui_js" ]
+ts_library("build_ts") {
+  root_dir = target_gen_dir
+  out_dir = "$target_gen_dir/tsc"
+  tsconfig_base = "tsconfig_base.json"
+  in_files = [
+    "process_internals.ts",
+    "process_internals.mojom-webui.js",
+  ]
+  deps = [
+    "//ui/webui/resources:library",
+    "//ui/webui/resources/mojo:library",
+  ]
+  extra_deps = [ ":copy_files" ]
 }
diff --git a/content/browser/resources/process/process_internals.js b/content/browser/resources/process/process_internals.ts
similarity index 77%
rename from content/browser/resources/process/process_internals.js
rename to content/browser/resources/process/process_internals.ts
index 9904bd7..c97d265 100644
--- a/content/browser/resources/process/process_internals.js
+++ b/content/browser/resources/process/process_internals.ts
@@ -4,52 +4,29 @@
 
 import 'chrome://resources/cr_elements/cr_tree/cr_tree.js';
 
-import {MAY_HAVE_CHILDREN_ATTR} from 'chrome://resources/cr_elements/cr_tree/cr_tree_item.js';
+import {CrTreeElement} from 'chrome://resources/cr_elements/cr_tree/cr_tree.js';
+import {CrTreeItemElement, MAY_HAVE_CHILDREN_ATTR} from 'chrome://resources/cr_elements/cr_tree/cr_tree_item.js';
+import {assert} from 'chrome://resources/js/assert_ts.js';
 
 import {FrameInfo, FrameInfo_Type, ProcessInternalsHandler, ProcessInternalsHandlerRemote, WebContentsInfo} from './process_internals.mojom-webui.js';
 
-
-
-// TODO (rbpotter): Remove these temporary definitions after migrating to TS.
-/**
- * @typedef {{
- *   detail: { children: Object, payload: (Object|undefined) },
- *   expanded: boolean,
- *   add: function(CrTreeItemElement): void,
- * }}
- */
-let CrTreeItemElement;
-
-/**
- * @typedef {{
- *   detail: { children: Object, payload: Object },
- *   add: function(CrTreeItemElement): void,
- *   removeTreeItem: function(CrTreeItemElement): void,
- *   expanded: boolean,
- *   items: Array<CrTreeItemElement>,
- *   selectedItem: CrTreeItemElement,
- * }}
- */
-let CrTreeElement;
-
 /**
  * Reference to the backend providing all the data.
- * @type {ProcessInternalsHandlerRemote}
  */
-let pageHandler = null;
+let pageHandler: ProcessInternalsHandlerRemote|null = null;
 
 /**
- * @param {string} id Tab id.
- * @return {boolean} True if successful.
+ * @return True if successful.
  */
-function selectTab(id) {
-  const tabContents = document.querySelectorAll('#content > div');
-  const navigation = document.querySelector('#navigation');
-  const tabHeaders = navigation.querySelectorAll('.tab-header');
+function selectTab(id: string): boolean {
+  const tabContents = document.querySelectorAll<HTMLElement>('#content > div');
+  const navigation = document.querySelector<HTMLElement>('#navigation');
+  assert(navigation);
+  const tabHeaders = navigation.querySelectorAll<HTMLElement>('.tab-header');
   let found = false;
   for (let i = 0; i < tabContents.length; i++) {
-    const tabContent = tabContents[i];
-    const tabHeader = tabHeaders[i];
+    const tabContent = tabContents[i]!;
+    const tabHeader = tabHeaders[i]!;
     const isTargetTab = tabContent.id === id;
 
     found = found || isTargetTab;
@@ -72,9 +49,11 @@
 
 function setupTabs() {
   const tabContents = document.querySelectorAll('#content > div');
-  for (let i = 0; i < tabContents.length; i++) {
-    const tabContent = tabContents[i];
-    const tabName = tabContent.querySelector('.content-header').textContent;
+  for (const tabContent of tabContents) {
+    const contentHeader =
+        tabContent.querySelector<HTMLElement>('.content-header');
+    assert(contentHeader);
+    const tabName = contentHeader.textContent;
 
     const tabHeader = document.createElement('div');
     tabHeader.className = 'tab-header';
@@ -82,25 +61,25 @@
     button.textContent = tabName;
     tabHeader.appendChild(button);
     tabHeader.addEventListener('click', selectTab.bind(null, tabContent.id));
-    document.querySelector('#navigation').appendChild(tabHeader);
+    const navigation = document.querySelector('#navigation');
+    assert(navigation);
+    navigation.appendChild(tabHeader);
   }
   onHashChange();
 }
 
 /**
  * Root of the WebContents tree.
- * @type {CrTreeElement|null}
  */
-let treeViewRoot = null;
+let treeViewRoot: CrTreeElement|null = null;
 
 /**
  * Initialize and return |treeViewRoot|.
- * @return {CrTreeElement} Initialized |treeViewRoot|.
  */
-function getTreeViewRoot() {
+function getTreeViewRoot(): CrTreeElement {
   if (!treeViewRoot) {
-    treeViewRoot =
-        /** @type {CrTreeElement} */ (document.querySelector('cr-tree'));
+    treeViewRoot = document.querySelector('cr-tree');
+    assert(treeViewRoot);
     treeViewRoot.detail = {payload: {}, children: {}};
   }
   return treeViewRoot;
@@ -109,13 +88,12 @@
 /**
  * Initialize and return a tree item representing a FrameInfo object and
  * recursively creates its subframe objects.
- * @param {FrameInfo} frame
- * @return {{item: CrTreeItemElement, count: number}}
  */
-function frameToTreeItem(frame) {
+function frameToTreeItem(frame: FrameInfo):
+    {item: CrTreeItemElement, count: number} {
   // Compose the string which will appear in the entry for this frame.
   let itemLabel = `Frame[${frame.processId}:${frame.routingId}:${
-    frame.agentSchedulingGroupId}]:`;
+      frame.agentSchedulingGroupId}]:`;
   if (frame.type === FrameInfo_Type.kBackForwardCache) {
     itemLabel += ` bfcached`;
   } else if (frame.type === FrameInfo_Type.kPrerender) {
@@ -145,8 +123,7 @@
     itemLabel += ` | url: ${frame.lastCommittedUrl.url}`;
   }
 
-  const item =
-      /** @type {CrTreeItemElement} */ (document.createElement('cr-tree-item'));
+  const item = document.createElement('cr-tree-item');
   item.label = itemLabel;
   item.detail = {payload: {}, children: {}};
   item.toggleAttribute(MAY_HAVE_CHILDREN_ATTR, true);
@@ -168,17 +145,15 @@
 /**
  * Initialize and return a tree item representing the WebContentsInfo object
  * and contains all frames in it as a subtree.
- * @param {WebContentsInfo} webContents
- * @return {!CrTreeItemElement}
  */
-function webContentsToTreeItem(webContents) {
+function webContentsToTreeItem(webContents: WebContentsInfo):
+    CrTreeItemElement {
   let itemLabel = 'WebContents: ';
   if (webContents.title.length > 0) {
     itemLabel += webContents.title + ', ';
   }
 
-  const item =
-      /** @type {CrTreeItemElement} */ (document.createElement('cr-tree-item'));
+  const item = document.createElement('cr-tree-item');
   item.label = itemLabel;
   item.detail = {payload: {}, children: {}};
   item.toggleAttribute(MAY_HAVE_CHILDREN_ATTR, true);
@@ -209,7 +184,7 @@
   // buildCountString(0, 'frame') => "0 frames"
   // buildCountString(1, 'frame') => "1 frame"
   // buildCountString(2, 'frame') => "2 frames"
-  const buildCountString = ((count, name) => {
+  const buildCountString = ((count: number, name: string) => {
     return `${count} ${name}` + (count !== 1 ? 's' : '');
   });
 
@@ -228,9 +203,8 @@
 /**
  * This is a callback which is invoked when the data for WebContents
  * associated with the browser profile is received from the browser process.
- * @param {!Array<!WebContentsInfo>} infos
  */
-function populateWebContentsTab(infos) {
+function populateWebContentsTab(infos: WebContentsInfo[]) {
   const tree = getTreeViewRoot();
 
   // Clear the tree first before populating it with the new content.
@@ -247,6 +221,7 @@
  * current browser profile. The result is passed to populateWebContentsTab.
  */
 async function loadWebContentsInfo() {
+  assert(pageHandler);
   const {infos} = await pageHandler.getAllWebContentsInfo();
   populateWebContentsTab(infos);
 }
@@ -259,6 +234,7 @@
  * profiles.
  */
 function loadIsolatedOriginInfo() {
+  assert(pageHandler);
   // Retrieve any persistent isolated origins for the current profile. Insert
   // them into a list on the page if there is at least one such origin.
   pageHandler.getUserTriggeredIsolatedOrigins().then((response) => {
@@ -268,7 +244,8 @@
     }
 
     const userOrigins =
-        document.querySelector('#user-triggered-isolated-origins');
+        document.querySelector<HTMLElement>('#user-triggered-isolated-origins');
+    assert(userOrigins);
     userOrigins.textContent =
         'The following origins are isolated because you previously typed a ' +
         'password or logged in on these sites (' + originCount + ' total). ' +
@@ -292,7 +269,8 @@
     }
 
     const webOrigins =
-        document.querySelector('#web-triggered-isolated-origins');
+        document.querySelector<HTMLElement>('#web-triggered-isolated-origins');
+    assert(webOrigins);
     webOrigins.textContent =
         'The following origins are isolated based on runtime heuristics ' +
         'triggered directly by web pages, such as Cross-Origin-Opener-Policy ' +
@@ -318,7 +296,9 @@
       return;
     }
 
-    const globalOrigins = document.querySelector('#global-isolated-origins');
+    const globalOrigins =
+        document.querySelector<HTMLElement>('#global-isolated-origins');
+    assert(globalOrigins);
     globalOrigins.textContent =
         'The following origins are isolated by default for all users (' +
         originCount + ' total).  A description of how each origin was ' +
@@ -337,10 +317,14 @@
 document.addEventListener('DOMContentLoaded', function() {
   // Setup Mojo interface to the backend.
   pageHandler = ProcessInternalsHandler.getRemote();
+  assert(pageHandler);
 
   // Get the Site Isolation mode and populate it.
   pageHandler.getIsolationMode().then((response) => {
-    document.querySelector('#isolation-mode').innerText = response.mode;
+    const isolationMode =
+        document.querySelector<HTMLElement>('#isolation-mode');
+    assert(isolationMode);
+    isolationMode.innerText = response.mode;
   });
 
   loadIsolatedOriginInfo();
@@ -351,6 +335,7 @@
   // Start loading the information about WebContents.
   loadWebContentsInfo();
 
-  const refreshButton = document.querySelector('#refresh-button');
+  const refreshButton = document.querySelector<HTMLElement>('#refresh-button');
+  assert(refreshButton);
   refreshButton.addEventListener('click', loadWebContentsInfo);
 });
diff --git a/content/browser/resources/process/tsconfig_base.json b/content/browser/resources/process/tsconfig_base.json
new file mode 100644
index 0000000..99a81eca
--- /dev/null
+++ b/content/browser/resources/process/tsconfig_base.json
@@ -0,0 +1,6 @@
+{
+  "extends": "../../../../tools/typescript/tsconfig_base.json",
+  "compilerOptions": {
+    "allowJs": true
+  }
+}
diff --git a/content/dev_ui_content_resources.grd b/content/dev_ui_content_resources.grd
index eca74292..0d15034 100644
--- a/content/dev_ui_content_resources.grd
+++ b/content/dev_ui_content_resources.grd
@@ -37,10 +37,10 @@
       <include name="IDR_PRERENDER_INTERNALS_HTML" file="browser/resources/prerender/prerender_internals.html" type="BINDATA" />
       <include name="IDR_PRERENDER_INTERNALS_MOJO_JS" file="${root_gen_dir}/mojom-webui/content/browser/prerender/prerender_internals.mojom-webui.js" use_base_dir="false" type="BINDATA" />
       <include name="IDR_PRERENDER_INTERNALS_JS" file="browser/resources/prerender/prerender_internals.js" type="BINDATA" />
-      <include name="IDR_PROCESS_INTERNALS_HTML" file="browser/resources/process/process_internals.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
-      <include name="IDR_PROCESS_INTERNALS_MOJO_JS" file="${root_gen_dir}/mojom-webui/content/browser/process_internals/process_internals.mojom-webui.js" use_base_dir="false" type="BINDATA" />
+      <include name="IDR_PROCESS_INTERNALS_HTML" file="browser/resources/process/process_internals.html" type="BINDATA" />
+      <include name="IDR_PROCESS_INTERNALS_MOJO_JS" file="${root_gen_dir}/content/browser/resources/process/tsc/process_internals.mojom-webui.js" use_base_dir="false" type="BINDATA" />
       <include name="IDR_PROCESS_INTERNALS_CSS" file="browser/resources/process/process_internals.css" type="BINDATA" />
-      <include name="IDR_PROCESS_INTERNALS_JS" file="browser/resources/process/process_internals.js" type="BINDATA" />
+      <include name="IDR_PROCESS_INTERNALS_JS" file="${root_gen_dir}/content/browser/resources/process/tsc/process_internals.js" use_base_dir="false" type="BINDATA" />
       <include name="IDR_SERVICE_WORKER_INTERNALS_HTML" file="browser/resources/service_worker/serviceworker_internals.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
       <include name="IDR_SERVICE_WORKER_INTERNALS_JS" file="browser/resources/service_worker/serviceworker_internals.js" type="BINDATA" />
       <include name="IDR_SERVICE_WORKER_INTERNALS_CSS" file="browser/resources/service_worker/serviceworker_internals.css" type="BINDATA" />
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 4737b8b..96db5dd 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -931,7 +931,7 @@
 
 // Enables subresource loading with Web Bundles.
 const base::Feature kSubresourceWebBundles{"SubresourceWebBundles",
-                                           base::FEATURE_DISABLED_BY_DEFAULT};
+                                           base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Disallows window.{alert, prompt, confirm} if triggered inside a subframe that
 // is not same origin with the main frame.
diff --git a/content/renderer/media/android/stream_texture_wrapper_impl.cc b/content/renderer/media/android/stream_texture_wrapper_impl.cc
index 57638d0..78d4f308 100644
--- a/content/renderer/media/android/stream_texture_wrapper_impl.cc
+++ b/content/renderer/media/android/stream_texture_wrapper_impl.cc
@@ -92,10 +92,8 @@
           coded_size, visible_rect, visible_rect.size(), base::TimeDelta());
   new_frame->set_ycbcr_info(ycbcr_info);
 
-  if (enable_texture_copy_) {
-    new_frame->metadata().copy_mode =
-        media::VideoFrameMetadata::CopyMode::kCopyToNewTexture;
-  }
+  if (enable_texture_copy_)
+    new_frame->metadata().copy_required = true;
 
   SetCurrentFrameInternal(new_frame);
 }
diff --git a/content/test/content_test_suite.cc b/content/test/content_test_suite.cc
index e247d25..528fecf 100644
--- a/content/test/content_test_suite.cc
+++ b/content/test/content_test_suite.cc
@@ -63,12 +63,11 @@
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   bool is_child_process = command_line->HasSwitch(switches::kTestChildProcess);
   if (!is_child_process) {
-    gl::GLDisplay* display =
-        gl::GLSurfaceTestSupport::InitializeNoExtensionsOneOff();
+    gl::GLSurfaceTestSupport::InitializeNoExtensionsOneOff();
     auto* gpu_feature_info = gpu::GetTestGpuThreadHolder()->GetGpuFeatureInfo();
     gl::init::SetDisabledExtensionsPlatform(
         gpu_feature_info->disabled_extensions);
-    gl::init::InitializeExtensionSettingsOneOffPlatform(display);
+    gl::init::InitializeExtensionSettingsOneOffPlatform();
   }
 
   RegisterContentWebUIConfigs();
diff --git a/content/test/data/attribution_reporting/aggregatable_report_goldens/latest/report_1.json b/content/test/data/attribution_reporting/aggregatable_report_goldens/latest/report_1.json
index 263bf888..f9524a9f 100644
--- a/content/test/data/attribution_reporting/aggregatable_report_goldens/latest/report_1.json
+++ b/content/test/data/attribution_reporting/aggregatable_report_goldens/latest/report_1.json
@@ -2,11 +2,12 @@
   "aggregation_service_payloads": [ {
      "debug_cleartext_payload": "omRkYXRhgaJldmFsdWVEAAAAAmZidWNrZXRQAAAAAAAAAAAAAAAAAAAAAWlvcGVyYXRpb25paGlzdG9ncmFt",
      "key_id": "example_id",
-     "payload": "nNJRhchQJaZTld/Cfsz5/4JelfwxVw4wTBwaXdDu0y2YKJ3lKyjjRUKKemGsPtSj+D1MlST0ggABMGuJexhxntg7hO+fK1KIcoSK0IWyvrgfkvdip0enRdtxxEZP7xR3nAd8JFnMGDnRHOjBuOni"
+     "payload": "P6qDfnLgaTL2jLv6tRHXauNGi1DpBn7KFxX2/HyEzVCP+LwzwsRntTyrnalnZuVTux8bdILblwBa6ehWDfyf1tZ/jLr0uFr+DC6oisTb6sDkFpkCELK/62IoDqsNYzl/DyAmFd9NKaepMoS6+GYH"
   } ],
   "attribution_destination": "https://conversion.test",
   "shared_info": "{\"debug_mode\":\"enabled\",\"privacy_budget_key\":\"hTxwDPlUIel3dB39m09GOkeAkMLcYVdE6H0eK2t1RYc=\",\"report_id\":\"21abd97f-73e8-4b88-9389-a9fee6abda5e\",\"reporting_origin\":\"https://report.test\",\"scheduled_report_time\":\"1234486400\",\"version\":\"\"}",
   "source_debug_key": "123",
   "source_registration_time": "1234483200",
+  "source_site": "https://impression.test",
   "trigger_debug_key": "456"
 }
diff --git a/content/test/data/attribution_reporting/interop/basic_aggregatable.json b/content/test/data/attribution_reporting/interop/basic_aggregatable.json
index 34fcb654..2382659 100644
--- a/content/test/data/attribution_reporting/interop/basic_aggregatable.json
+++ b/content/test/data/attribution_reporting/interop/basic_aggregatable.json
@@ -75,6 +75,7 @@
       {
         "payload": {
           "attribution_destination": "https://destination.test",
+          "source_site": "https://source.test",
           "histograms": [
             {
               "key": "0x559",
diff --git a/content/test/data/attribution_reporting/simulator/basic_aggregatable.output.json b/content/test/data/attribution_reporting/simulator/basic_aggregatable.output.json
index 3975dbe8..9ac9594c 100644
--- a/content/test/data/attribution_reporting/simulator/basic_aggregatable.output.json
+++ b/content/test/data/attribution_reporting/simulator/basic_aggregatable.output.json
@@ -2,7 +2,8 @@
   "aggregatable_reports": [
     {
       "report": {
-        "attribution_destination": "https://d.test"
+        "attribution_destination": "https://d.test",
+        "source_site": "https://s.test"
       },
       "report_time": "1643239174123",
       "report_url": "https://r.test/.well-known/attribution-reporting/report-aggregate-attribution",
diff --git a/content/test/data/fuzzer_corpus/attribution_simulator/all_fields.textproto b/content/test/data/fuzzer_corpus/attribution_simulator/all_fields.textproto
index 1ce2f1c..3cb451a 100644
--- a/content/test/data/fuzzer_corpus/attribution_simulator/all_fields.textproto
+++ b/content/test/data/fuzzer_corpus/attribution_simulator/all_fields.textproto
@@ -1,5 +1,40 @@
 object_value {
   field {
+    name: "cookies"
+    value {
+      array_value {
+        value {
+          object_value {
+            field {
+              name: "timestamp"
+              value {
+                string_value {
+                  value: "1643235572"
+                }
+              }
+            }
+            field {
+              name: "url"
+              value {
+                string_value {
+                  value: "https://r.test/cookie"
+                }
+              }
+            }
+            field {
+              name: "Set-Cookie"
+              value {
+                string_value {
+                  value: "ar_debug=1; SameSite=None; Secure; HttpOnly; Max-Age=4"
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  field {
     name: "sources"
     value {
       array_value {
diff --git a/device/fido/hid/fake_hid_impl_for_testing.cc b/device/fido/hid/fake_hid_impl_for_testing.cc
index 66dc088..7d4bafc 100644
--- a/device/fido/hid/fake_hid_impl_for_testing.cc
+++ b/device/fido/hid/fake_hid_impl_for_testing.cc
@@ -183,6 +183,8 @@
       HidBlocklist::Get().GetProtectedReportIds(
           HidBlocklist::kReportTypeFeature, device->vendor_id,
           device->product_id, device->collections);
+  device->is_excluded_by_blocklist = HidBlocklist::Get().IsVendorProductBlocked(
+      device->vendor_id, device->product_id);
   AddDevice(std::move(device));
 }
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
index 76308e5d..1ab9e6d 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -196,10 +196,10 @@
   DCHECK(normalized_init.extensions.empty() ||
          *normalized_init.extensions.rbegin() == ' ');
   gl::SetGLGetProcAddressProc(gl::MockGLInterface::GetGLProcAddress);
-  display_ = gl::GLSurfaceTestSupport::InitializeOneOffWithMockBindings();
+  gl::GLSurfaceTestSupport::InitializeOneOffWithMockBindings();
 
   gl_ = std::make_unique<StrictMock<MockGLInterface>>();
-  gl::MockGLInterface::SetGLInterface(gl_.get());
+  ::gl::MockGLInterface::SetGLInterface(gl_.get());
 
   SetupMockGLBehaviors();
 
@@ -620,9 +620,9 @@
   decoder_.reset();
   group_->Destroy(mock_decoder_.get(), false);
   command_buffer_service_.reset();
-  gl::MockGLInterface::SetGLInterface(nullptr);
+  ::gl::MockGLInterface::SetGLInterface(nullptr);
   gl_.reset();
-  gl::GLSurfaceTestSupport::ShutdownGL(display_);
+  gl::init::ShutdownGL(false);
 }
 
 void GLES2DecoderTestBase::TearDown() {
@@ -2431,7 +2431,7 @@
 
   gl::init::InitializeStaticGLBindingsImplementation(
       gl::GLImplementationParts(gl::kGLImplementationEGLANGLE), false);
-  display_ = gl::init::InitializeGLOneOffPlatformImplementation(
+  gl::init::InitializeGLOneOffPlatformImplementation(
       /*fallback_to_software_gl=*/false,
       /*disable_gl_drawing=*/false,
       /*init_extensions=*/true,
@@ -2493,7 +2493,7 @@
   decoder_.reset();
   group_ = nullptr;
   command_buffer_service_.reset();
-  gl::init::ShutdownGL(display_, false);
+  gl::init::ShutdownGL(false);
 }
 
 void GLES2DecoderPassthroughTestBase::SetBucketData(uint32_t bucket_id,
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
index ed64675..db9c633 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
@@ -42,7 +42,6 @@
 #include "gpu/config/gpu_driver_bug_workarounds.h"
 #include "gpu/config/gpu_preferences.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gl/gl_display.h"
 #include "ui/gl/gl_mock.h"
 #include "ui/gl/gl_surface_stub.h"
 #include "ui/gl/gl_version_info.h"
@@ -703,7 +702,6 @@
   std::unique_ptr<MockGLES2Decoder> mock_decoder_;
   std::unique_ptr<GLES2Decoder> decoder_;
   std::unique_ptr<MemoryTracker> memory_tracker_;
-  gl::GLDisplay* display_ = nullptr;
 
   bool surface_supports_draw_rectangle_ = false;
 
@@ -1037,7 +1035,6 @@
   TraceOutputter outputter_;
   std::unique_ptr<GLES2DecoderPassthroughImpl> decoder_;
   scoped_refptr<ContextGroup> group_;
-  gl::GLDisplay* display_ = nullptr;
 };
 
 }  // namespace gles2
diff --git a/gpu/command_buffer/service/gpu_fence_manager_unittest.cc b/gpu/command_buffer/service/gpu_fence_manager_unittest.cc
index 3ccc31f3..1a77b602 100644
--- a/gpu/command_buffer/service/gpu_fence_manager_unittest.cc
+++ b/gpu/command_buffer/service/gpu_fence_manager_unittest.cc
@@ -61,7 +61,7 @@
   void SetupMockEGL(const char* extensions) {
     gl::SetGLGetProcAddressProc(gl::MockEGLInterface::GetGLProcAddress);
     egl_ = std::make_unique<::testing::NiceMock<::gl::MockEGLInterface>>();
-    gl::MockEGLInterface::SetEGLInterface(egl_.get());
+    ::gl::MockEGLInterface::SetEGLInterface(egl_.get());
 
     const EGLDisplay kDummyDisplay = reinterpret_cast<EGLDisplay>(0x1001);
     ON_CALL(*egl_, QueryString(_, EGL_EXTENSIONS))
@@ -73,13 +73,10 @@
 
     gl::ClearBindingsEGL();
     gl::InitializeStaticGLBindingsEGL();
-    display_ = gl::GLSurfaceEGL::InitializeOneOffForTesting();
+    gl::GLSurfaceEGL::InitializeOneOffForTesting();
   }
 
-  void TeardownMockEGL() {
-    gl::GLSurfaceEGL::ShutdownOneOff(display_);
-    egl_.reset();
-  }
+  void TeardownMockEGL() { egl_.reset(); }
 
   void SetupFeatureInfo(const char* gl_extensions,
                         const char* gl_version,
@@ -94,7 +91,6 @@
   std::unique_ptr<GpuFenceManager> manager_;
   std::unique_ptr<MockErrorState> error_state_;
   std::unique_ptr<::testing::NiceMock<::gl::MockEGLInterface>> egl_;
-  gl::GLDisplayEGL* display_ = nullptr;
 };
 
 TEST_F(GpuFenceManagerTest, Basic) {
diff --git a/gpu/command_buffer/service/gpu_service_test.cc b/gpu/command_buffer/service/gpu_service_test.cc
index 7f57e87..85cd16c 100644
--- a/gpu/command_buffer/service/gpu_service_test.cc
+++ b/gpu/command_buffer/service/gpu_service_test.cc
@@ -29,7 +29,7 @@
   testing::Test::SetUp();
 
   gl::SetGLGetProcAddressProc(gl::MockGLInterface::GetGLProcAddress);
-  display_ = gl::GLSurfaceTestSupport::InitializeOneOffWithMockBindings();
+  gl::GLSurfaceTestSupport::InitializeOneOffWithMockBindings();
   gl_ = std::make_unique<::testing::StrictMock<::gl::MockGLInterface>>();
   ::gl::MockGLInterface::SetGLInterface(gl_.get());
 
@@ -51,7 +51,7 @@
   surface_ = nullptr;
   ::gl::MockGLInterface::SetGLInterface(nullptr);
   gl_.reset();
-  gl::GLSurfaceTestSupport::ShutdownGL(display_);
+  gl::init::ShutdownGL(false);
   ran_teardown_ = true;
 
   testing::Test::TearDown();
diff --git a/gpu/command_buffer/service/gpu_service_test.h b/gpu/command_buffer/service/gpu_service_test.h
index 1bede07..fa4d5fa2 100644
--- a/gpu/command_buffer/service/gpu_service_test.h
+++ b/gpu/command_buffer/service/gpu_service_test.h
@@ -11,7 +11,6 @@
 #include "base/test/task_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gl/gl_display.h"
 #include "ui/gl/gl_mock.h"
 
 namespace gl {
@@ -44,7 +43,6 @@
   scoped_refptr<gl::GLContextStub> context_;
   scoped_refptr<gl::GLSurfaceStub> surface_;
   base::test::SingleThreadTaskEnvironment task_environment_;
-  gl::GLDisplay* display_ = nullptr;
 };
 
 }  // namespace gles2
diff --git a/gpu/command_buffer/service/gr_cache_controller_unittest.cc b/gpu/command_buffer/service/gr_cache_controller_unittest.cc
index 807287c8..3276a0f 100644
--- a/gpu/command_buffer/service/gr_cache_controller_unittest.cc
+++ b/gpu/command_buffer/service/gr_cache_controller_unittest.cc
@@ -26,7 +26,7 @@
 class GrCacheControllerTest : public testing::Test {
  public:
   void SetUp() override {
-    display_ = gl::GLSurfaceTestSupport::InitializeOneOffWithStubBindings();
+    gl::GLSurfaceTestSupport::InitializeOneOffWithStubBindings();
     gpu::GpuDriverBugWorkarounds workarounds;
 
     scoped_refptr<gl::GLShareGroup> share_group = new gl::GLShareGroup();
@@ -53,7 +53,7 @@
     controller_ = nullptr;
     context_state_ = nullptr;
     task_runner_ = nullptr;
-    gl::GLSurfaceTestSupport::ShutdownGL(display_);
+    gl::init::ShutdownGL(false);
   }
 
   GrDirectContext* gr_context() { return context_state_->gr_context(); }
@@ -62,7 +62,6 @@
   scoped_refptr<SharedContextState> context_state_;
   scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
   std::unique_ptr<GrCacheController> controller_;
-  gl::GLDisplay* display_ = nullptr;
 };
 
 TEST_F(GrCacheControllerTest, PurgeGrCache) {
diff --git a/gpu/command_buffer/service/image_reader_gl_owner_unittest.cc b/gpu/command_buffer/service/image_reader_gl_owner_unittest.cc
index 05fb2355..72445a8 100644
--- a/gpu/command_buffer/service/image_reader_gl_owner_unittest.cc
+++ b/gpu/command_buffer/service/image_reader_gl_owner_unittest.cc
@@ -38,7 +38,7 @@
 
     gl::init::InitializeStaticGLBindingsImplementation(
         gl::GLImplementationParts(gl::kGLImplementationEGLGLES2), false);
-    display_ = gl::init::InitializeGLOneOffPlatformImplementation(
+    gl::init::InitializeGLOneOffPlatformImplementation(
         /*fallback_to_software_gl=*/false,
         /*disable_gl_drawing=*/false,
         /*init_extensions=*/true,
@@ -83,7 +83,7 @@
     context_ = nullptr;
     share_group_ = nullptr;
     surface_ = nullptr;
-    gl::init::ShutdownGL(display_, false);
+    gl::init::ShutdownGL(false);
   }
 
   bool IsImageReaderSupported() const {
@@ -99,7 +99,6 @@
   scoped_refptr<gl::GLShareGroup> share_group_;
   scoped_refptr<gl::GLSurface> surface_;
   base::test::TaskEnvironment task_environment_;
-  gl::GLDisplay* display_ = nullptr;
 };
 
 TEST_F(ImageReaderGLOwnerTest, ImageReaderObjectCreation) {
diff --git a/gpu/command_buffer/service/raster_decoder_unittest.cc b/gpu/command_buffer/service/raster_decoder_unittest.cc
index 32940e5..62616ab 100644
--- a/gpu/command_buffer/service/raster_decoder_unittest.cc
+++ b/gpu/command_buffer/service/raster_decoder_unittest.cc
@@ -198,7 +198,7 @@
 class RasterDecoderOOPTest : public testing::Test, DecoderClient {
  public:
   void SetUp() override {
-    display_ = gl::GLSurfaceTestSupport::InitializeOneOff();
+    gl::GLSurfaceTestSupport::InitializeOneOff();
     gpu::GpuDriverBugWorkarounds workarounds;
 
     scoped_refptr<gl::GLShareGroup> share_group = new gl::GLShareGroup();
@@ -252,7 +252,7 @@
 
     context_state_.reset();
     context_state_ = nullptr;
-    gl::GLSurfaceTestSupport::ShutdownGL(display_);
+    gl::init::ShutdownGL(false);
   }
 
   RasterDecoderOOPTest() : memory_tracker_(nullptr) {
@@ -368,7 +368,6 @@
   std::unique_ptr<SharedImageFactory> shared_image_factory_;
   SharedImageManager shared_image_manager_;
   gles2::MailboxManagerImpl mailbox_manager_;
-  gl::GLDisplay* display_ = nullptr;
 };
 
 TEST_F(RasterDecoderOOPTest, CopyTexSubImage2DSizeMismatch) {
diff --git a/gpu/command_buffer/service/raster_decoder_unittest_base.cc b/gpu/command_buffer/service/raster_decoder_unittest_base.cc
index c0da5e4c..95c5de3 100644
--- a/gpu/command_buffer/service/raster_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/raster_decoder_unittest_base.cc
@@ -99,7 +99,7 @@
 
   // For easier substring/extension matching
   gl::SetGLGetProcAddressProc(gl::MockGLInterface::GetGLProcAddress);
-  display_ = gl::GLSurfaceTestSupport::InitializeOneOffWithMockBindings();
+  gl::GLSurfaceTestSupport::InitializeOneOffWithMockBindings();
 
   gl_ = std::make_unique<StrictMock<MockGLInterface>>();
   ::gl::MockGLInterface::SetGLInterface(gl_.get());
@@ -218,7 +218,7 @@
   shared_context_state_.reset();
   ::gl::MockGLInterface::SetGLInterface(nullptr);
   gl_.reset();
-  gl::GLSurfaceTestSupport::ShutdownGL(display_);
+  gl::init::ShutdownGL(false);
 }
 
 void RasterDecoderTestBase::TearDown() {
diff --git a/gpu/command_buffer/service/raster_decoder_unittest_base.h b/gpu/command_buffer/service/raster_decoder_unittest_base.h
index 1625699..b8edc537 100644
--- a/gpu/command_buffer/service/raster_decoder_unittest_base.h
+++ b/gpu/command_buffer/service/raster_decoder_unittest_base.h
@@ -30,7 +30,6 @@
 #include "gpu/config/gpu_driver_bug_workarounds.h"
 #include "gpu/config/gpu_preferences.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gl/gl_display.h"
 #include "ui/gl/gl_mock.h"
 #include "ui/gl/gl_surface_stub.h"
 #include "ui/gl/gl_version_info.h"
@@ -194,7 +193,6 @@
   base::test::SingleThreadTaskEnvironment task_environment_;
   raw_ptr<gles2::MockCopyTextureResourceManager>
       copy_texture_manager_;  // not owned
-  gl::GLDisplay* display_ = nullptr;
 };
 
 class RasterDecoderManualInitTest : public RasterDecoderTestBase {
diff --git a/gpu/command_buffer/service/shared_image_representation_dawn_ozone.cc b/gpu/command_buffer/service/shared_image_representation_dawn_ozone.cc
index 1943c3eab..52c2df0a 100644
--- a/gpu/command_buffer/service/shared_image_representation_dawn_ozone.cc
+++ b/gpu/command_buffer/service/shared_image_representation_dawn_ozone.cc
@@ -107,8 +107,10 @@
   // closed twice (once by ScopedFD and once by the Vulkan implementation).
   int fd = dup(pixmap_->GetDmaBufFd(0));
   descriptor.memoryFD = fd;
-  // stride is not required for multi-planar formats.
-  descriptor.stride = pixmap_->GetDmaBufPitch(0);
+  for (uint32_t plane = 0u; plane < pixmap_->GetNumberOfPlanes(); ++plane) {
+    descriptor.planeLayouts[plane].offset = pixmap_->GetDmaBufOffset(plane);
+    descriptor.planeLayouts[plane].stride = pixmap_->GetDmaBufPitch(plane);
+  }
   descriptor.drmModifier = pixmap_->GetBufferFormatModifier();
   descriptor.waitFDs = {};
 
diff --git a/gpu/command_buffer/service/surface_texture_gl_owner_unittest.cc b/gpu/command_buffer/service/surface_texture_gl_owner_unittest.cc
index e2de124..fa97fd0 100644
--- a/gpu/command_buffer/service/surface_texture_gl_owner_unittest.cc
+++ b/gpu/command_buffer/service/surface_texture_gl_owner_unittest.cc
@@ -39,7 +39,7 @@
   void SetUp() override {
     gl::init::InitializeStaticGLBindingsImplementation(
         gl::GLImplementationParts(gl::kGLImplementationEGLGLES2), false);
-    display_ = gl::init::InitializeGLOneOffPlatformImplementation(
+    gl::init::InitializeGLOneOffPlatformImplementation(
         /*fallback_to_software_gl=*/false,
         /*disable_gl_drawing=*/false,
         /*init_extensions=*/true,
@@ -83,7 +83,7 @@
     context_ = nullptr;
     share_group_ = nullptr;
     surface_ = nullptr;
-    gl::init::ShutdownGL(display_, false);
+    gl::init::ShutdownGL(false);
   }
 
   scoped_refptr<TextureOwner> surface_texture_;
@@ -95,7 +95,6 @@
   scoped_refptr<gl::GLShareGroup> share_group_;
   scoped_refptr<gl::GLSurface> surface_;
   base::test::TaskEnvironment task_environment_;
-  gl::GLDisplay* display_ = nullptr;
 };
 
 TEST_F(SurfaceTextureGLOwnerTest, OwnerReturnsServiceId) {
diff --git a/gpu/command_buffer/service/webgpu_decoder_impl.cc b/gpu/command_buffer/service/webgpu_decoder_impl.cc
index 090cc27..48f0b23 100644
--- a/gpu/command_buffer/service/webgpu_decoder_impl.cc
+++ b/gpu/command_buffer/service/webgpu_decoder_impl.cc
@@ -1031,6 +1031,7 @@
   switch (feature) {
     case WGPUFeatureName_TimestampQuery:
     case WGPUFeatureName_PipelineStatisticsQuery:
+    case WGPUFeatureName_ChromiumExperimentalDp4a:
       return allow_unsafe_apis_;
     case WGPUFeatureName_Depth24UnormStencil8:
     case WGPUFeatureName_Depth32FloatStencil8:
diff --git a/gpu/command_buffer/tests/gl_test_setup_helper.cc b/gpu/command_buffer/tests/gl_test_setup_helper.cc
index 7b7d8f1..54e3acf 100644
--- a/gpu/command_buffer/tests/gl_test_setup_helper.cc
+++ b/gpu/command_buffer/tests/gl_test_setup_helper.cc
@@ -44,7 +44,7 @@
   ui::OzonePlatform::InitializeForGPU(params);
 #endif  // defined(USE_OZONE)
 
-  display_ = gpu::GLTestHelper::InitializeGLDefault();
+  gpu::GLTestHelper::InitializeGLDefault();
   ::gles2::Initialize();
 }
 
@@ -53,7 +53,7 @@
   // Otherwise the gpu-service tries to access GL during tear-down and causes
   // crashes.
   viz::TestGpuServiceHolder::ResetInstance();
-  gl::init::ShutdownGL(display_, /*due_to_fallback=*/false);
+  gl::init::ShutdownGL(/*due_to_fallback=*/false);
   task_environment_ = nullptr;
 }
 
diff --git a/gpu/command_buffer/tests/gl_test_setup_helper.h b/gpu/command_buffer/tests/gl_test_setup_helper.h
index 01d6eba..07b1d7b4 100644
--- a/gpu/command_buffer/tests/gl_test_setup_helper.h
+++ b/gpu/command_buffer/tests/gl_test_setup_helper.h
@@ -7,7 +7,6 @@
 
 #include "base/test/task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gl/gl_display.h"
 
 namespace gpu {
 
@@ -27,7 +26,6 @@
 
  private:
   std::unique_ptr<base::test::TaskEnvironment> task_environment_;
-  gl::GLDisplay* display_ = nullptr;
 };
 
 }  // namespace gpu
diff --git a/gpu/command_buffer/tests/gl_test_utils.cc b/gpu/command_buffer/tests/gl_test_utils.cc
index 28fc32c..d1f3235 100644
--- a/gpu/command_buffer/tests/gl_test_utils.cc
+++ b/gpu/command_buffer/tests/gl_test_utils.cc
@@ -35,27 +35,26 @@
 const uint8_t GLTestHelper::kCheckClearValue;
 #endif
 
-gl::GLDisplay* GLTestHelper::InitializeGL(gl::GLImplementation gl_impl) {
-  gl::GLDisplay* display = nullptr;
+bool GLTestHelper::InitializeGL(gl::GLImplementation gl_impl) {
   if (gl_impl == gl::GLImplementation::kGLImplementationNone) {
-    display = gl::init::InitializeGLNoExtensionsOneOff(/*init_bindings=*/true,
-                                                       /*system_device_id=*/0);
+    if (!gl::init::InitializeGLNoExtensionsOneOff(/*init_bindings=*/true,
+                                                  /*system_device_id=*/0))
+      return false;
   } else {
     if (!gl::init::InitializeStaticGLBindingsImplementation(
             gl::GLImplementationParts(gl_impl),
             /*fallback_to_software_gl=*/false))
-      return nullptr;
+      return false;
 
-    display = gl::init::InitializeGLOneOffPlatformImplementation(
-        /*fallback_to_software_gl=*/false,
-        /*disable_gl_drawing=*/false,
-        /*init_extensions=*/false,
-        /*system_device_id=*/0);
+    if (!gl::init::InitializeGLOneOffPlatformImplementation(
+            /*fallback_to_software_gl=*/false,
+            /*disable_gl_drawing=*/false,
+            /*init_extensions=*/false,
+            /*system_device_id=*/0)) {
+      return false;
+    }
   }
 
-  if (!display)
-    return nullptr;
-
   gpu::GPUInfo gpu_info;
   gpu::CollectGraphicsInfoForTesting(&gpu_info);
   gpu::GLManager::g_gpu_feature_info = gpu::ComputeGpuFeatureInfo(
@@ -65,12 +64,10 @@
 
   gl::init::SetDisabledExtensionsPlatform(
       gpu::GLManager::g_gpu_feature_info.disabled_extensions);
-  if (!gl::init::InitializeExtensionSettingsOneOffPlatform(display))
-    return nullptr;
-  return display;
+  return gl::init::InitializeExtensionSettingsOneOffPlatform();
 }
 
-gl::GLDisplay* GLTestHelper::InitializeGLDefault() {
+bool GLTestHelper::InitializeGLDefault() {
   return GLTestHelper::InitializeGL(
       gl::GLImplementation::kGLImplementationNone);
 }
@@ -412,9 +409,8 @@
     }
 
     gl_reinitialized_ = true;
-    gl::init::ShutdownGL(gl_display_, false /* due_to_fallback */);
-    gl_display_ = GLTestHelper::InitializeGL(new_impl.gl);
-    if (!gl_display_) {
+    gl::init::ShutdownGL(false /* due_to_fallback */);
+    if (!GLTestHelper::InitializeGL(new_impl.gl)) {
       LOG(INFO) << "Skip test, failed to initialize EGL";
       return false;
     }
@@ -448,8 +444,8 @@
   gl_.Destroy();
 
   if (gl_reinitialized_) {
-    gl::init::ShutdownGL(gl_display_, false /* due_to_fallback */);
-    gl_display_ = GLTestHelper::InitializeGLDefault();
+    gl::init::ShutdownGL(false /* due_to_fallback */);
+    GLTestHelper::InitializeGLDefault();
   }
 
   gl_reinitialized_ = false;
diff --git a/gpu/command_buffer/tests/gl_test_utils.h b/gpu/command_buffer/tests/gl_test_utils.h
index 098f649..501f9fd 100644
--- a/gpu/command_buffer/tests/gl_test_utils.h
+++ b/gpu/command_buffer/tests/gl_test_utils.h
@@ -14,7 +14,6 @@
 
 #include "build/build_config.h"
 #include "gpu/command_buffer/tests/gl_manager.h"
-#include "ui/gl/gl_display.h"
 #include "ui/gl/gl_implementation.h"
 
 namespace gl {
@@ -27,8 +26,8 @@
  public:
   static const uint8_t kCheckClearValue = 123u;
 
-  static gl::GLDisplay* InitializeGL(gl::GLImplementation gl_impl);
-  static gl::GLDisplay* InitializeGLDefault();
+  static bool InitializeGL(gl::GLImplementation gl_impl);
+  static bool InitializeGLDefault();
 
   static bool HasExtension(const char* extension);
   static bool CheckGLError(const char* msg, int line);
@@ -141,7 +140,6 @@
   gl::GLWindowSystemBindingInfo window_system_binding_info_;
   gfx::ExtensionSet egl_extensions_;
   gfx::ExtensionSet gl_extensions_;
-  gl::GLDisplay* gl_display_ = nullptr;
 };
 
 }  // namespace gpu
diff --git a/gpu/config/gpu_driver_bug_list.json b/gpu/config/gpu_driver_bug_list.json
index ee0811f9..ef446b9 100644
--- a/gpu/config/gpu_driver_bug_list.json
+++ b/gpu/config/gpu_driver_bug_list.json
@@ -4012,6 +4012,26 @@
       "features": [
           "disable_vp_super_resolution"
       ]
+    },
+    {
+      "id": 395,
+      "cr_bugs": [1327088],
+      "description": "Don't use MPO on Intel TigerLake GPUs with old drivers due to VideoProcessorBlt crash.",
+      "os": {
+        "type": "win"
+      },
+      "vendor_id": "0x8086",
+      "intel_gpu_generation": {
+        "op": ">=",
+        "value": "12"
+      },
+      "driver_version": {
+        "op": "<=",
+        "value": "27.20.100.9168"
+      },
+      "features": [
+        "disable_direct_composition_video_overlays"
+      ]
     }
   ]
 }
diff --git a/gpu/config/gpu_info_collector.cc b/gpu/config/gpu_info_collector.cc
index 56406bb..b0c51a1 100644
--- a/gpu/config/gpu_info_collector.cc
+++ b/gpu/config/gpu_info_collector.cc
@@ -289,10 +289,9 @@
   if (CollectGraphicsDeviceInfoFromCommandLine(command_line, gpu_info))
     return true;
 
-  // We can't check if passthrough is supported yet because GL may not be
-  // initialized.
   gpu_info->passthrough_cmd_decoder =
-      gl::UsePassthroughCommandDecoder(command_line);
+      gl::UsePassthroughCommandDecoder(command_line) &&
+      gl::PassthroughCommandDecoderSupported();
 
   bool fallback_to_software = false;
   absl::optional<gl::GLImplementationParts> implementation =
@@ -338,11 +337,6 @@
   TRACE_EVENT0("startup", "gpu_info_collector::CollectGraphicsInfoGL");
   DCHECK_NE(gl::GetGLImplementation(), gl::kGLImplementationNone);
 
-  // Now that we can check GL extensions, update passthrough support info.
-  if (!gl::PassthroughCommandDecoderSupported()) {
-    gpu_info->passthrough_cmd_decoder = false;
-  }
-
   scoped_refptr<gl::GLSurface> surface(InitializeGLSurface());
   if (!surface.get()) {
     LOG(ERROR) << "Could not create surface for info collection.";
diff --git a/gpu/config/gpu_info_collector_unittest.cc b/gpu/config/gpu_info_collector_unittest.cc
index 9e1881dd..5dfcf87 100644
--- a/gpu/config/gpu_info_collector_unittest.cc
+++ b/gpu/config/gpu_info_collector_unittest.cc
@@ -59,7 +59,7 @@
   void SetUp() override {
     testing::Test::SetUp();
     gl::SetGLGetProcAddressProc(gl::MockGLInterface::GetGLProcAddress);
-    display_ = gl::GLSurfaceTestSupport::InitializeOneOffWithMockBindings();
+    gl::GLSurfaceTestSupport::InitializeOneOffWithMockBindings();
     gl_ = std::make_unique<::testing::StrictMock<::gl::MockGLInterface>>();
     ::gl::MockGLInterface::SetGLInterface(gl_.get());
     switch (GetParam()) {
@@ -184,12 +184,12 @@
   void TearDown() override {
     ::gl::MockGLInterface::SetGLInterface(nullptr);
     gl_.reset();
-    gl::GLSurfaceTestSupport::ShutdownGL(display_);
+    gl::init::ShutdownGL(false);
 
     testing::Test::TearDown();
   }
 
- protected:
+ public:
   // Use StrictMock to make 100% sure we know how GL will be called.
   std::unique_ptr<::testing::StrictMock<::gl::MockGLInterface>> gl_;
   GPUInfo test_values_;
@@ -199,8 +199,6 @@
 
   // Persistent storage is needed for the split extension string.
   std::vector<std::string> split_extensions_;
-
-  gl::GLDisplay* display_ = nullptr;
 };
 
 INSTANTIATE_TEST_SUITE_P(GPUConfig,
diff --git a/gpu/config/gpu_util.cc b/gpu/config/gpu_util.cc
index 7776a4b..33b5b58 100644
--- a/gpu/config/gpu_util.cc
+++ b/gpu/config/gpu_util.cc
@@ -47,7 +47,6 @@
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/gfx/extension_set.h"
 #include "ui/gl/buildflags.h"
-#include "ui/gl/gl_display_manager.h"
 #include "ui/gl/gl_implementation.h"
 #include "ui/gl/gl_switches.h"
 
@@ -128,9 +127,7 @@
   // synchronization, this is based on Android native fence sync
   // support. If that is unavailable, i.e. on emulator or SwiftShader,
   // don't claim SurfaceControl support.
-  if (!gl::GLDisplayManagerEGL::GetInstance()
-           ->GetDisplay(gl::GpuPreference::kDefault)
-           ->IsAndroidNativeFenceSyncSupported())
+  if (!gl::GLSurfaceEGL::GetGLDisplayEGL()->IsAndroidNativeFenceSyncSupported())
     return kGpuFeatureStatusDisabled;
 
   DCHECK(gfx::SurfaceControl::IsSupported());
@@ -750,10 +747,10 @@
 }
 
 #if BUILDFLAG(IS_ANDROID)
-gl::GLDisplay* InitializeGLThreadSafe(base::CommandLine* command_line,
-                                      const GpuPreferences& gpu_preferences,
-                                      GPUInfo* out_gpu_info,
-                                      GpuFeatureInfo* out_gpu_feature_info) {
+bool InitializeGLThreadSafe(base::CommandLine* command_line,
+                            const GpuPreferences& gpu_preferences,
+                            GPUInfo* out_gpu_info,
+                            GpuFeatureInfo* out_gpu_feature_info) {
   static base::NoDestructor<base::Lock> gl_bindings_initialization_lock;
   base::AutoLock auto_lock(*gl_bindings_initialization_lock);
   DCHECK(command_line);
@@ -764,23 +761,15 @@
   if (gpu_info_cached) {
     // GL bindings have already been initialized in another thread.
     DCHECK_NE(gl::kGLImplementationNone, gl::GetGLImplementation());
-    return gl::GLDisplayManagerEGL::GetInstance()->GetDisplay(
-        gl::GpuPreference::kDefault);
+    return true;
   }
-
-  gl::GLDisplay* gl_display = nullptr;
   if (gl::GetGLImplementation() == gl::kGLImplementationNone) {
     // Some tests initialize bindings by themselves.
-    gl_display =
-        gl::init::InitializeGLNoExtensionsOneOff(/*init_bindings=*/true,
-                                                 /*system_device_id=*/0);
-    if (!gl_display) {
+    if (!gl::init::InitializeGLNoExtensionsOneOff(/*init_bindings=*/true,
+                                                  /*system_device_id=*/0)) {
       VLOG(1) << "gl::init::InitializeGLNoExtensionsOneOff failed";
-      return nullptr;
+      return false;
     }
-  } else {
-    gl_display = gl::GLDisplayManagerEGL::GetInstance()->GetDisplay(
-        gl::GpuPreference::kDefault);
   }
   CollectContextGraphicsInfo(out_gpu_info);
   *out_gpu_feature_info = ComputeGpuFeatureInfo(*out_gpu_info, gpu_preferences,
@@ -789,13 +778,13 @@
     gl::init::SetDisabledExtensionsPlatform(
         out_gpu_feature_info->disabled_extensions);
   }
-  if (!gl::init::InitializeExtensionSettingsOneOffPlatform(gl_display)) {
+  if (!gl::init::InitializeExtensionSettingsOneOffPlatform()) {
     VLOG(1) << "gl::init::InitializeExtensionSettingsOneOffPlatform failed";
-    return nullptr;
+    return false;
   }
   CacheGPUInfo(*out_gpu_info);
   CacheGpuFeatureInfo(*out_gpu_feature_info);
-  return gl_display;
+  return true;
 }
 #endif  // BUILDFLAG(IS_ANDROID)
 
diff --git a/gpu/config/gpu_util.h b/gpu/config/gpu_util.h
index 08b18c4..f72970c 100644
--- a/gpu/config/gpu_util.h
+++ b/gpu/config/gpu_util.h
@@ -8,7 +8,6 @@
 #include "build/build_config.h"
 #include "gpu/config/gpu_feature_info.h"
 #include "gpu/gpu_export.h"
-#include "ui/gl/gl_display.h"
 
 namespace base {
 class CommandLine;
@@ -63,11 +62,10 @@
 // bindings, create a GL context, collects GPUInfo, make blocklist and
 // GPU driver bug workaround decisions. This is intended to be called
 // by Android WebView render thread and in-process GPU thread.
-GPU_EXPORT gl::GLDisplay* InitializeGLThreadSafe(
-    base::CommandLine* command_line,
-    const GpuPreferences& gpu_preferences,
-    GPUInfo* out_gpu_info,
-    GpuFeatureInfo* out_gpu_feature_info);
+GPU_EXPORT bool InitializeGLThreadSafe(base::CommandLine* command_line,
+                                       const GpuPreferences& gpu_preferences,
+                                       GPUInfo* out_gpu_info,
+                                       GpuFeatureInfo* out_gpu_feature_info);
 #endif  // BUILDFLAG(IS_ANDROID)
 
 // Returns whether SwiftShader should be enabled. If true, the proper command
diff --git a/gpu/gles2_conform_support/egl/thread_state.cc b/gpu/gles2_conform_support/egl/thread_state.cc
index e7764db..624b9dc0 100644
--- a/gpu/gles2_conform_support/egl/thread_state.cc
+++ b/gpu/gles2_conform_support/egl/thread_state.cc
@@ -22,7 +22,6 @@
 #include "gpu/gles2_conform_support/egl/surface.h"
 #include "gpu/gles2_conform_support/egl/test_support.h"
 #include "ui/gl/gl_context.h"
-#include "ui/gl/gl_display.h"
 #include "ui/gl/gl_surface.h"
 #include "ui/gl/gl_switches.h"
 #include "ui/gl/init/gl_factory.h"
@@ -89,9 +88,8 @@
 #if defined(USE_OZONE)
       ui::OzonePlatform::InitializeForGPU(ui::OzonePlatform::InitParams());
 #endif
-      gl::GLDisplay* display =
-          gl::init::InitializeGLNoExtensionsOneOff(/*init_bindings=*/true,
-                                                   /*system_device_id=*/0);
+      gl::init::InitializeGLNoExtensionsOneOff(/*init_bindings=*/true,
+                                               /*system_device_id=*/0);
       gpu::GpuFeatureInfo gpu_feature_info;
       if (!command_line->HasSwitch(switches::kDisableGpuDriverBugWorkarounds)) {
         gpu::GPUInfo gpu_info;
@@ -103,7 +101,7 @@
 
       gl::init::SetDisabledExtensionsPlatform(
           gpu_feature_info.disabled_extensions);
-      gl::init::InitializeExtensionSettingsOneOffPlatform(display);
+      gl::init::InitializeExtensionSettingsOneOffPlatform();
     }
 
     g_egl_default_display = new egl::Display();
diff --git a/gpu/ipc/common/gpu_memory_buffer_impl_test_template.h b/gpu/ipc/common/gpu_memory_buffer_impl_test_template.h
index cbbffd6c..c8c6bca 100644
--- a/gpu/ipc/common/gpu_memory_buffer_impl_test_template.h
+++ b/gpu/ipc/common/gpu_memory_buffer_impl_test_template.h
@@ -22,7 +22,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/buffer_format_util.h"
 #include "ui/gfx/mojom/buffer_types.mojom.h"
-#include "ui/gl/gl_display.h"
 
 #if BUILDFLAG(IS_WIN) || defined(USE_OZONE)
 #include "ui/gl/init/gl_factory.h"
@@ -53,10 +52,8 @@
 
 #if BUILDFLAG(IS_WIN) || defined(USE_OZONE)
   // Overridden from testing::Test:
-  void SetUp() override {
-    display_ = gl::GLSurfaceTestSupport::InitializeOneOff();
-  }
-  void TearDown() override { gl::GLSurfaceTestSupport::ShutdownGL(display_); }
+  void SetUp() override { gl::GLSurfaceTestSupport::InitializeOneOff(); }
+  void TearDown() override { gl::init::ShutdownGL(false); }
 #endif
 
  protected:
@@ -65,7 +62,6 @@
 
  private:
   GpuMemoryBufferSupport gpu_memory_buffer_support_;
-  gl::GLDisplay* display_ = nullptr;
 
   void FreeGpuMemoryBuffer(base::OnceClosure free_callback,
                            bool* destroyed,
diff --git a/gpu/ipc/service/gpu_channel_test_common.cc b/gpu/ipc/service/gpu_channel_test_common.cc
index 0149d19..f2dbc67 100644
--- a/gpu/ipc/service/gpu_channel_test_common.cc
+++ b/gpu/ipc/service/gpu_channel_test_common.cc
@@ -86,9 +86,9 @@
           new TestGpuChannelManagerDelegate(scheduler_.get())) {
   // We need GL bindings to actually initialize command buffers.
   if (use_stub_bindings) {
-    display_ = gl::GLSurfaceTestSupport::InitializeOneOffWithStubBindings();
+    gl::GLSurfaceTestSupport::InitializeOneOffWithStubBindings();
   } else {
-    display_ = gl::GLSurfaceTestSupport::InitializeOneOff();
+    gl::GLSurfaceTestSupport::InitializeOneOff();
   }
 
   GpuFeatureInfo feature_info;
@@ -110,7 +110,7 @@
   // Command buffers can post tasks and run GL in destruction so do this first.
   channel_manager_ = nullptr;
   task_environment_.RunUntilIdle();
-  gl::GLSurfaceTestSupport::ShutdownGL(display_);
+  gl::init::ShutdownGL(false);
 }
 
 GpuChannel* GpuChannelTestCommon::CreateChannel(int32_t client_id,
diff --git a/gpu/ipc/service/gpu_channel_test_common.h b/gpu/ipc/service/gpu_channel_test_common.h
index 338a579..d56372d 100644
--- a/gpu/ipc/service/gpu_channel_test_common.h
+++ b/gpu/ipc/service/gpu_channel_test_common.h
@@ -16,7 +16,6 @@
 #include "gpu/command_buffer/common/context_result.h"
 #include "gpu/ipc/common/gpu_channel.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gl/gl_display.h"
 
 namespace base {
 namespace trace_event {
@@ -68,7 +67,6 @@
   std::unique_ptr<Scheduler> scheduler_;
   std::unique_ptr<TestGpuChannelManagerDelegate> channel_manager_delegate_;
   std::unique_ptr<GpuChannelManager> channel_manager_;
-  gl::GLDisplay* display_ = nullptr;
 };
 
 }  // namespace gpu
diff --git a/gpu/ipc/service/gpu_init.cc b/gpu/ipc/service/gpu_init.cc
index f1ea8c0..37e2ce5 100644
--- a/gpu/ipc/service/gpu_init.cc
+++ b/gpu/ipc/service/gpu_init.cc
@@ -421,13 +421,11 @@
     return false;
 #else   // !(BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS))
     SaveHardwareGpuInfoAndGpuFeatureInfo();
-    gl::init::ShutdownGL(nullptr, true);
+    gl::init::ShutdownGL(true);
     gl_initialized = false;
 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
   }
 
-  gl::GLDisplay* gl_display = nullptr;
-
   if (!gl_initialized) {
     // Pause watchdog. LoadLibrary in GLBindings may take long time.
     if (watchdog_thread_)
@@ -441,9 +439,8 @@
     if (watchdog_thread_)
       watchdog_thread_->ResumeWatchdog();
     if (gl::GetGLImplementation() != gl::kGLImplementationDisabled) {
-      gl_display = gl::init::InitializeGLNoExtensionsOneOff(
+      gl_initialized = gl::init::InitializeGLNoExtensionsOneOff(
           /*init_bindings*/ false, system_device_id);
-      gl_initialized = !!gl_display;
       if (!gl_initialized) {
         VLOG(1) << "gl::init::InitializeGLNoExtensionsOneOff failed";
         return false;
@@ -517,12 +514,11 @@
         return false;
 #else
         SaveHardwareGpuInfoAndGpuFeatureInfo();
-        gl::init::ShutdownGL(gl_display, true);
+        gl::init::ShutdownGL(true);
         watchdog_thread_ = nullptr;
         watchdog_init.SetGpuWatchdogPtr(nullptr);
-        gl_display = gl::init::InitializeGLNoExtensionsOneOff(
-            /*init_bindings=*/true, system_device_id);
-        if (!gl_display) {
+        if (!gl::init::InitializeGLNoExtensionsOneOff(/*init_bindings*/ true,
+                                                      system_device_id)) {
           VLOG(1)
               << "gl::init::InitializeGLNoExtensionsOneOff with SwiftShader "
               << "failed";
@@ -625,7 +621,7 @@
       gl::init::SetDisabledExtensionsPlatform(
           gpu_feature_info_.disabled_extensions);
     }
-    if (!gl::init::InitializeExtensionSettingsOneOffPlatform(gl_display)) {
+    if (!gl::init::InitializeExtensionSettingsOneOffPlatform()) {
       VLOG(1) << "gl::init::InitializeExtensionSettingsOneOffPlatform failed";
       return false;
     }
@@ -808,14 +804,11 @@
   }
 #endif  // !BUILDFLAG(IS_CASTOS)
 
-  gl::GLDisplay* gl_display = nullptr;
-
   gl_use_swiftshader_ = EnableSwiftShaderIfNeeded(
       command_line, gpu_feature_info_,
       gpu_preferences_.disable_software_rasterizer, needs_more_info);
-  gl_display = gl::init::InitializeGLNoExtensionsOneOff(/*init_bindings=*/true,
-                                                        /*system_device_id=*/0);
-  if (!gl_display) {
+  if (!gl::init::InitializeGLNoExtensionsOneOff(/*init_bindings=*/true,
+                                                /*system_device_id=*/0)) {
     VLOG(1) << "gl::init::InitializeGLNoExtensionsOneOff failed";
     return;
   }
@@ -830,10 +823,9 @@
         gpu_preferences_.disable_software_rasterizer, false);
     if (gl_use_swiftshader_) {
       SaveHardwareGpuInfoAndGpuFeatureInfo();
-      gl::init::ShutdownGL(gl_display, true);
-      gl_display = gl::init::InitializeGLNoExtensionsOneOff(
-          /*init_bindings=*/true, /*system_device_id=*/0);
-      if (!gl_display) {
+      gl::init::ShutdownGL(true);
+      if (!gl::init::InitializeGLNoExtensionsOneOff(/*init_bindings=*/true,
+                                                    /*system_device_id=*/0)) {
         VLOG(1) << "gl::init::InitializeGLNoExtensionsOneOff failed "
                 << "with SwiftShader";
         return;
@@ -861,7 +853,7 @@
       gl::init::SetDisabledExtensionsPlatform(
           gpu_feature_info_.disabled_extensions);
     }
-    if (!gl::init::InitializeExtensionSettingsOneOffPlatform(gl_display)) {
+    if (!gl::init::InitializeExtensionSettingsOneOffPlatform()) {
       VLOG(1) << "gl::init::InitializeExtensionSettingsOneOffPlatform failed";
     }
     default_offscreen_surface_ =
@@ -886,10 +878,9 @@
         gpu_preferences_.disable_software_rasterizer, false);
     if (gl_use_swiftshader_) {
       SaveHardwareGpuInfoAndGpuFeatureInfo();
-      gl::init::ShutdownGL(gl_display, true);
-      gl_display = gl::init::InitializeGLNoExtensionsOneOff(
-          /*init_bindings=*/true, /*system_device_id=*/0);
-      if (!gl_display) {
+      gl::init::ShutdownGL(true);
+      if (!gl::init::InitializeGLNoExtensionsOneOff(/*init_bindings=*/true,
+                                                    /*system_device_id=*/0)) {
         VLOG(1) << "gl::init::InitializeGLNoExtensionsOneOff failed "
                 << "with SwiftShader";
         return;
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_test_template.h b/gpu/ipc/service/gpu_memory_buffer_factory_test_template.h
index 36663b2..8d4888b 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_test_template.h
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_test_template.h
@@ -14,7 +14,6 @@
 #include "gpu/ipc/service/gpu_memory_buffer_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/buffer_format_util.h"
-#include "ui/gl/gl_display.h"
 
 #if BUILDFLAG(IS_WIN) || defined(USE_OZONE)
 #include "base/command_line.h"
@@ -36,9 +35,9 @@
     DCHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
         switches::kUseGpuInTests));
 #endif
-    display_ = gl::GLSurfaceTestSupport::InitializeOneOff();
+    gl::GLSurfaceTestSupport::InitializeOneOff();
   }
-  void TearDown() override { gl::GLSurfaceTestSupport::ShutdownGL(display_); }
+  void TearDown() override { gl::init::ShutdownGL(false); }
 #endif  // BUILDFLAG(IS_WIN) || defined(USE_OZONE)
 
  protected:
@@ -46,7 +45,6 @@
       base::test::TaskEnvironment::MainThreadType::UI};
 
   GpuMemoryBufferFactoryType factory_;
-  gl::GLDisplay* display_ = nullptr;
 };
 
 TYPED_TEST_SUITE_P(GpuMemoryBufferFactoryTest);
diff --git a/ios/chrome/browser/sync/sync_service_factory_unittest.cc b/ios/chrome/browser/sync/sync_service_factory_unittest.cc
index 6b73e6c..644a9ec 100644
--- a/ios/chrome/browser/sync/sync_service_factory_unittest.cc
+++ b/ios/chrome/browser/sync/sync_service_factory_unittest.cc
@@ -9,9 +9,11 @@
 #include <vector>
 
 #include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/task/thread_pool/thread_pool_instance.h"
 #include "components/browser_sync/browser_sync_switches.h"
 #include "components/sync/base/command_line_switches.h"
+#include "components/sync/base/features.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/base/pref_names.h"
 #include "components/sync/driver/data_type_controller.h"
@@ -66,7 +68,9 @@
     datatypes.Put(syncer::AUTOFILL_WALLET_OFFER);
     datatypes.Put(syncer::BOOKMARKS);
     datatypes.Put(syncer::DEVICE_INFO);
-    // TODO(crbug.com/1318028): Add HISTORY once it has a Controller.
+    if (base::FeatureList::IsEnabled(syncer::kSyncEnableHistoryDataType)) {
+      datatypes.Put(syncer::HISTORY);
+    }
     datatypes.Put(syncer::HISTORY_DELETE_DIRECTIVES);
     datatypes.Put(syncer::PREFERENCES);
     datatypes.Put(syncer::PRIORITY_PREFERENCES);
diff --git a/ios/chrome/browser/u2f/BUILD.gn b/ios/chrome/browser/u2f/BUILD.gn
index 9b0dd70..4dc6136 100644
--- a/ios/chrome/browser/u2f/BUILD.gn
+++ b/ios/chrome/browser/u2f/BUILD.gn
@@ -31,6 +31,7 @@
     "//ios/chrome/common",
     "//ios/web/public",
     "//ios/web/public/deprecated",
+    "//ios/web/public/js_messaging",
     "//net",
     "//url",
   ]
diff --git a/ios/chrome/browser/u2f/u2f_controller.mm b/ios/chrome/browser/u2f/u2f_controller.mm
index be25cf9..334fe168 100644
--- a/ios/chrome/browser/u2f/u2f_controller.mm
+++ b/ios/chrome/browser/u2f/u2f_controller.mm
@@ -14,6 +14,8 @@
 #import "ios/chrome/browser/chrome_url_util.h"
 #include "ios/chrome/common/x_callback_url.h"
 #include "ios/web/public/deprecated/url_verification_constants.h"
+#include "ios/web/public/js_messaging/web_frame.h"
+#import "ios/web/public/js_messaging/web_frame_util.h"
 #import "ios/web/public/web_state.h"
 #include "net/base/url_util.h"
 
@@ -126,13 +128,18 @@
     return;
   }
 
+  web::WebFrame* mainFrame = web::GetMainFrame(webState);
+  if (!mainFrame) {
+    return;
+  }
+
   // If the URLs match and the page URL is trusted, inject the response JS.
   web::URLVerificationTrustLevel trustLevel =
       web::URLVerificationTrustLevel::kNone;
   GURL currentTabURL = webState->GetCurrentURL(&trustLevel);
   if (trustLevel == web::URLVerificationTrustLevel::kAbsolute &&
       GURL(base::SysNSStringToUTF8(originalTabURL)) == currentTabURL) {
-    webState->ExecuteJavaScript([self JSStringFromReponseURL:U2FURL]);
+    mainFrame->ExecuteJavaScript([self JSStringFromReponseURL:U2FURL]);
   }
 
   // Remove bookkept URL for returned U2F call.
diff --git a/ios/chrome/browser/u2f/u2f_controller_unittest.mm b/ios/chrome/browser/u2f/u2f_controller_unittest.mm
index fe157a5a..39f789f 100644
--- a/ios/chrome/browser/u2f/u2f_controller_unittest.mm
+++ b/ios/chrome/browser/u2f/u2f_controller_unittest.mm
@@ -10,6 +10,8 @@
 #include "base/strings/utf_string_conversions.h"
 #import "ios/chrome/browser/chrome_url_util.h"
 #include "ios/web/public/deprecated/url_verification_constants.h"
+#import "ios/web/public/test/fakes/fake_web_frame.h"
+#import "ios/web/public/test/fakes/fake_web_frames_manager.h"
 #import "ios/web/public/test/fakes/fake_web_state.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -20,16 +22,6 @@
 #error "This file requires ARC support."
 #endif
 
-namespace {
-
-// Mocks ExecuteJavaScript method.
-class WebStateMock : public web::FakeWebState {
- public:
-  MOCK_METHOD1(ExecuteJavaScript, void(const std::u16string&));
-};
-
-}  // namespace
-
 class U2FControllerTest : public PlatformTest {
  protected:
   U2FControllerTest() : _U2FController([[U2FController alloc] init]) {
@@ -166,18 +158,26 @@
                                                         tabID:tabID];
   NSString* requestUUIDString = this->requestUUIDFromXCallbackURL(XCallbackURL);
 
-  WebStateMock webState;
+  web::FakeWebState webState;
   webState.SetTrustLevel(web::URLVerificationTrustLevel::kAbsolute);
   webState.SetCurrentURL(tabURL);
 
+  auto webFramesManager = std::make_unique<web::FakeWebFramesManager>();
+  web::FakeWebFramesManager* webFramesManagerPtr = webFramesManager.get();
+  webState.SetWebFramesManager(std::move(webFramesManager));
+
+  auto mainFrame = web::FakeWebFrame::CreateMainWebFrame(tabURL);
+  web::FakeWebFrame* mainFramePtr = mainFrame.get();
+  webFramesManagerPtr->AddWebFrame(std::move(mainFrame));
+
   // Test when U2F callback has correct information, Tab URL has not changed and
   // is trusted.
   GURL correctRequestUUIDURL("chromium://u2f-callback?requestUUID=" +
                              base::SysNSStringToUTF8(requestUUIDString) +
                              "&tabID=" + base::SysNSStringToUTF8(tabID));
-  EXPECT_CALL(webState, ExecuteJavaScript(testing::_)).Times(1);
   [_U2FController evaluateU2FResultFromU2FURL:correctRequestUUIDURL
                                      webState:&webState];
+  EXPECT_EQ(1ul, mainFramePtr->GetJavaScriptCallHistory().size());
 }
 
 TEST_F(U2FControllerTest, EvaluateU2FResultFromU2FURLWithReplayAttackTest) {
@@ -191,24 +191,32 @@
                                                         tabID:tabID];
   NSString* requestUUIDString = this->requestUUIDFromXCallbackURL(XCallbackURL);
 
-  WebStateMock webState;
+  web::FakeWebState webState;
   webState.SetTrustLevel(web::URLVerificationTrustLevel::kAbsolute);
   webState.SetCurrentURL(tabURL);
 
+  auto webFramesManager = std::make_unique<web::FakeWebFramesManager>();
+  web::FakeWebFramesManager* webFramesManagerPtr = webFramesManager.get();
+  webState.SetWebFramesManager(std::move(webFramesManager));
+
+  auto mainFrame = web::FakeWebFrame::CreateMainWebFrame(tabURL);
+  web::FakeWebFrame* mainFramePtr = mainFrame.get();
+  webFramesManagerPtr->AddWebFrame(std::move(mainFrame));
+
   // Test when U2F callback has correct information, Tab URL has not changed and
   // is trusted.
   GURL correctRequestUUIDURL("chromium://u2f-callback?requestUUID=" +
                              base::SysNSStringToUTF8(requestUUIDString) +
                              "&tabID=" + base::SysNSStringToUTF8(tabID));
-  EXPECT_CALL(webState, ExecuteJavaScript(testing::_)).Times(1);
   [_U2FController evaluateU2FResultFromU2FURL:correctRequestUUIDURL
                                      webState:&webState];
+  EXPECT_EQ(1ul, mainFramePtr->GetJavaScriptCallHistory().size());
 
   // Test when requestUUID is used for multiple times. Subsequent calls with the
   // same requestUUID should not do anything.
-  EXPECT_CALL(webState, ExecuteJavaScript(testing::_)).Times(0);
   [_U2FController evaluateU2FResultFromU2FURL:correctRequestUUIDURL
                                      webState:&webState];
+  EXPECT_EQ(1ul, mainFramePtr->GetJavaScriptCallHistory().size());
 }
 
 TEST_F(U2FControllerTest, EvaluateU2FResultFromU2FURLWithBadURLFormatTest) {
@@ -222,31 +230,39 @@
                                                         tabID:tabID];
   NSString* requestUUIDString = this->requestUUIDFromXCallbackURL(XCallbackURL);
 
-  WebStateMock webState;
+  web::FakeWebState webState;
   webState.SetTrustLevel(web::URLVerificationTrustLevel::kAbsolute);
   webState.SetCurrentURL(tabURL);
 
+  auto webFramesManager = std::make_unique<web::FakeWebFramesManager>();
+  web::FakeWebFramesManager* webFramesManagerPtr = webFramesManager.get();
+  webState.SetWebFramesManager(std::move(webFramesManager));
+
+  auto mainFrame = web::FakeWebFrame::CreateMainWebFrame(tabURL);
+  web::FakeWebFrame* mainFramePtr = mainFrame.get();
+  webFramesManagerPtr->AddWebFrame(std::move(mainFrame));
+
   // Test when U2F callback has no requestUUID info.
   GURL noRequestUUIDURL("chromium://u2f-callback?tabID=" +
                         base::SysNSStringToUTF8(tabID));
-  EXPECT_CALL(webState, ExecuteJavaScript(testing::_)).Times(0);
   [_U2FController evaluateU2FResultFromU2FURL:noRequestUUIDURL
                                      webState:&webState];
+  EXPECT_EQ(0ul, mainFramePtr->GetJavaScriptCallHistory().size());
 
   // Test when U2F callback has wrong requestUUID value.
   GURL wrongRequestUUIDURL("chromium://u2f-callback?requestUUID=123&tabID=" +
                            base::SysNSStringToUTF8(tabID));
-  EXPECT_CALL(webState, ExecuteJavaScript(testing::_)).Times(0);
   [_U2FController evaluateU2FResultFromU2FURL:wrongRequestUUIDURL
                                      webState:&webState];
+  EXPECT_EQ(0ul, mainFramePtr->GetJavaScriptCallHistory().size());
 
   // Test when U2F callback hostname is unexpected.
   GURL wrongHostnameURL("chromium://evil-callback?requestUUID=" +
-                        base::SysNSStringToUTF8(requestUUIDString) + "&tabID=" +
-                        base::SysNSStringToUTF8(tabID));
-  EXPECT_CALL(webState, ExecuteJavaScript(testing::_)).Times(0);
+                        base::SysNSStringToUTF8(requestUUIDString) +
+                        "&tabID=" + base::SysNSStringToUTF8(tabID));
   [_U2FController evaluateU2FResultFromU2FURL:wrongHostnameURL
                                      webState:&webState];
+  EXPECT_EQ(0ul, mainFramePtr->GetJavaScriptCallHistory().size());
 }
 
 TEST_F(U2FControllerTest, EvaluateU2FResultFromU2FURLWithBadTabStateTest) {
@@ -260,21 +276,36 @@
                                                         tabID:tabID];
   NSString* requestUUIDString = this->requestUUIDFromXCallbackURL(XCallbackURL);
 
-  WebStateMock webState;
+  web::FakeWebState webState;
+
+  auto webFramesManager = std::make_unique<web::FakeWebFramesManager>();
+  web::FakeWebFramesManager* webFramesManagerPtr = webFramesManager.get();
+  webState.SetWebFramesManager(std::move(webFramesManager));
 
   // Test when U2F callback has correct information but Tab URL changed.
   webState.SetTrustLevel(web::URLVerificationTrustLevel::kAbsolute);
-  webState.SetCurrentURL(GURL("http://www.dummy.com"));
+  auto url = GURL("http://www.dummy.com");
+  webState.SetCurrentURL(url);
+
+  auto mainFrame = web::FakeWebFrame::CreateMainWebFrame(url);
+  web::FakeWebFrame* mainFramePtr = mainFrame.get();
+  webFramesManagerPtr->AddWebFrame(std::move(mainFrame));
+
   GURL correctRequestUUIDURL("chromium://u2f-callback?requestUUID=" +
                              base::SysNSStringToUTF8(requestUUIDString) +
                              "&tabID=" + base::SysNSStringToUTF8(tabID));
   [_U2FController evaluateU2FResultFromU2FURL:correctRequestUUIDURL
                                      webState:&webState];
-  EXPECT_CALL(webState, ExecuteJavaScript(testing::_)).Times(0);
+  EXPECT_EQ(0ul, mainFramePtr->GetJavaScriptCallHistory().size());
+
+  webFramesManagerPtr->RemoveWebFrame(mainFramePtr->GetFrameId());
 
   // Test when U2F callback has correct information but Tab URL not trusted.
   webState.SetTrustLevel(web::URLVerificationTrustLevel::kNone);
   webState.SetCurrentURL(tabURL);
+  auto mainFrame2 = web::FakeWebFrame::CreateMainWebFrame(tabURL);
+  web::FakeWebFrame* mainFramePtr2 = mainFrame2.get();
+  webFramesManagerPtr->AddWebFrame(std::move(mainFrame2));
   XCallbackURL = [_U2FController XCallbackFromRequestURL:requestURL
                                                originURL:originURL
                                                   tabURL:tabURL
@@ -283,7 +314,7 @@
   correctRequestUUIDURL = GURL("chromium://u2f-callback?requestUUID=" +
                                base::SysNSStringToUTF8(requestUUIDString) +
                                "&tabID=" + base::SysNSStringToUTF8(tabID));
-  EXPECT_CALL(webState, ExecuteJavaScript(testing::_)).Times(0);
   [_U2FController evaluateU2FResultFromU2FURL:correctRequestUUIDURL
                                      webState:&webState];
+  EXPECT_EQ(0ul, mainFramePtr2->GetJavaScriptCallHistory().size());
 }
diff --git a/ios/chrome/browser/u2f/u2f_tab_helper_unittest.mm b/ios/chrome/browser/u2f/u2f_tab_helper_unittest.mm
index fd39675..8e9c8de 100644
--- a/ios/chrome/browser/u2f/u2f_tab_helper_unittest.mm
+++ b/ios/chrome/browser/u2f/u2f_tab_helper_unittest.mm
@@ -11,6 +11,8 @@
 #include "base/strings/utf_string_conversions.h"
 #import "ios/chrome/browser/chrome_url_util.h"
 #include "ios/web/public/deprecated/url_verification_constants.h"
+#import "ios/web/public/test/fakes/fake_web_frame.h"
+#import "ios/web/public/test/fakes/fake_web_frames_manager.h"
 #import "ios/web/public/test/fakes/fake_web_state.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
@@ -180,18 +182,25 @@
       "&requestId=TestID&registrationData=TestData&tabID=" +
       base::SysNSStringToUTF8(web_state_.GetStableIdentifier()));
 
-  EXPECT_TRUE(web_state_.GetLastExecutedJavascript().empty());
+  auto web_frames_manager = std::make_unique<web::FakeWebFramesManager>();
+  web::FakeWebFramesManager* web_frames_manager_ptr = web_frames_manager.get();
+  web_state_.SetWebFramesManager(std::move(web_frames_manager));
+
+  auto main_frame = web::FakeWebFrame::CreateMainWebFrame(tab_url);
+  web::FakeWebFrame* main_frame_ptr = main_frame.get();
+  web_frames_manager_ptr->AddWebFrame(std::move(main_frame));
+
+  EXPECT_TRUE(main_frame_ptr->GetLastJavaScriptCall().empty());
 
   tab_helper()->EvaluateU2FResult(correct_request_uuid_url);
-  std::string last_executed_js =
-      base::UTF16ToUTF8(web_state_.GetLastExecutedJavascript());
-  EXPECT_EQ(0, static_cast<int>(last_executed_js.find("u2f.callbackMap_")));
+  EXPECT_EQ(0ul,
+            main_frame_ptr->GetLastJavaScriptCall().find(u"u2f.callbackMap_"));
 
   // Test Replay Attack - Subsequent calls with the
   // same requestUUID should not do anything.
-  web_state_.ClearLastExecutedJavascript();
+  main_frame_ptr->ClearJavaScriptCallHistory();
   tab_helper()->EvaluateU2FResult(correct_request_uuid_url);
-  EXPECT_TRUE(web_state_.GetLastExecutedJavascript().empty());
+  EXPECT_TRUE(main_frame_ptr->GetLastJavaScriptCall().empty());
 }
 
 // Tests when U2F callback is not formatted correctly.
@@ -204,7 +213,15 @@
   NSString* request_uuid = GetRequestUuidFromXCallbackUrl(xcallback_url);
   web_state_.SetTrustLevel(web::URLVerificationTrustLevel::kAbsolute);
 
-  EXPECT_TRUE(web_state_.GetLastExecutedJavascript().empty());
+  auto web_frames_manager = std::make_unique<web::FakeWebFramesManager>();
+  web::FakeWebFramesManager* web_frames_manager_ptr = web_frames_manager.get();
+  web_state_.SetWebFramesManager(std::move(web_frames_manager));
+
+  auto main_frame = web::FakeWebFrame::CreateMainWebFrame(tab_url);
+  web::FakeWebFrame* main_frame_ptr = main_frame.get();
+  web_frames_manager_ptr->AddWebFrame(std::move(main_frame));
+
+  EXPECT_TRUE(main_frame_ptr->GetLastJavaScriptCall().empty());
 
   // Test when U2F callback has no requestUUID info.
   GURL no_request_uuid_url(
@@ -212,7 +229,7 @@
       "u2f-callback?requestId=TestID&registrationData=TestData&tabID=" +
       base::SysNSStringToUTF8(web_state_.GetStableIdentifier()));
   tab_helper()->EvaluateU2FResult(no_request_uuid_url);
-  EXPECT_TRUE(web_state_.GetLastExecutedJavascript().empty());
+  EXPECT_TRUE(main_frame_ptr->GetLastJavaScriptCall().empty());
 
   // Test when U2F callback has wrong requestUUID value.
   GURL wrong_request_uuid_url(
@@ -221,7 +238,7 @@
       "TestData&requestUUID=123&tabID=" +
       base::SysNSStringToUTF8(web_state_.GetStableIdentifier()));
   tab_helper()->EvaluateU2FResult(wrong_request_uuid_url);
-  EXPECT_TRUE(web_state_.GetLastExecutedJavascript().empty());
+  EXPECT_TRUE(main_frame_ptr->GetLastJavaScriptCall().empty());
 
   // Test when U2F callback has no registrationData value.
   GURL no_registration_request_url(
@@ -230,7 +247,7 @@
       base::SysNSStringToUTF8(web_state_.GetStableIdentifier()));
 
   tab_helper()->EvaluateU2FResult(no_registration_request_url);
-  EXPECT_TRUE(web_state_.GetLastExecutedJavascript().empty());
+  EXPECT_TRUE(main_frame_ptr->GetLastJavaScriptCall().empty());
 
   // Test when U2F callback hostname is unexpected.
   GURL wrong_host_name_url(
@@ -239,7 +256,7 @@
       base::SysNSStringToUTF8(request_uuid) +
       "&tabID=" + base::SysNSStringToUTF8(web_state_.GetStableIdentifier()));
   tab_helper()->EvaluateU2FResult(wrong_host_name_url);
-  EXPECT_TRUE(web_state_.GetLastExecutedJavascript().empty());
+  EXPECT_TRUE(main_frame_ptr->GetLastJavaScriptCall().empty());
 }
 
 // Tests when last committed URL is not valid for U2F.
@@ -251,12 +268,22 @@
   GURL xcallback_url = tab_helper()->GetXCallbackUrl(request_url, origin_url);
   NSString* request_uuid = GetRequestUuidFromXCallbackUrl(xcallback_url);
 
-  // Verify that last executed javascript is empty.
-  EXPECT_TRUE(web_state_.GetLastExecutedJavascript().empty());
+  auto web_frames_manager = std::make_unique<web::FakeWebFramesManager>();
+  web::FakeWebFramesManager* web_frames_manager_ptr = web_frames_manager.get();
+  web_state_.SetWebFramesManager(std::move(web_frames_manager));
 
   // Test when U2F callback has correct information but Tab URL changed.
   web_state_.SetTrustLevel(web::URLVerificationTrustLevel::kAbsolute);
-  web_state_.SetCurrentURL(GURL("http://www.dummy.com"));
+  auto url = GURL("http://www.dummy.com");
+  web_state_.SetCurrentURL(url);
+
+  auto main_frame = web::FakeWebFrame::CreateMainWebFrame(url);
+  web::FakeWebFrame* main_frame_ptr = main_frame.get();
+  web_frames_manager_ptr->AddWebFrame(std::move(main_frame));
+
+  // Verify that last executed javascript is empty.
+  EXPECT_TRUE(main_frame_ptr->GetLastJavaScriptCall().empty());
+
   GURL correct_request_uuid_url(
       "chromium://"
       "u2f-callback?requestId=TestID&registrationData=TestData&requestUUID=" +
@@ -264,11 +291,17 @@
       "&tabID=" + base::SysNSStringToUTF8(web_state_.GetStableIdentifier()));
 
   tab_helper()->EvaluateU2FResult(correct_request_uuid_url);
-  EXPECT_TRUE(web_state_.GetLastExecutedJavascript().empty());
+  EXPECT_TRUE(main_frame_ptr->GetLastJavaScriptCall().empty());
+
+  web_frames_manager_ptr->RemoveWebFrame(main_frame_ptr->GetFrameId());
 
   // Test when U2F callback has correct information but Tab URL not trusted.
   web_state_.SetTrustLevel(web::URLVerificationTrustLevel::kNone);
   web_state_.SetCurrentURL(correct_tab_url);
+  auto main_frame2 = web::FakeWebFrame::CreateMainWebFrame(correct_tab_url);
+  web::FakeWebFrame* main_frame_ptr2 = main_frame2.get();
+  web_frames_manager_ptr->AddWebFrame(std::move(main_frame2));
+
   xcallback_url = tab_helper()->GetXCallbackUrl(request_url, origin_url);
   request_uuid = GetRequestUuidFromXCallbackUrl(xcallback_url);
   correct_request_uuid_url = GURL(
@@ -278,5 +311,5 @@
       "&tabID=" + base::SysNSStringToUTF8(web_state_.GetStableIdentifier()));
 
   tab_helper()->EvaluateU2FResult(correct_request_uuid_url);
-  EXPECT_TRUE(web_state_.GetLastExecutedJavascript().empty());
+  EXPECT_TRUE(main_frame_ptr2->GetLastJavaScriptCall().empty());
 }
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
index a3777c0d..0a260c4 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-68fab8fc9226e6579db684a3d14acf5b654a5478
\ No newline at end of file
+49de4d4b28448fbeb53cce8163071f91f1548bd7
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
index adb6b6c..fb1028c 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-caa462f6f432c8b13d484eb49200b058d4a4256f
\ No newline at end of file
+7a9682bc75e3f9f31cf971491a9513ea80637567
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
index 30fc99d..b09b35cc 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-450904f0a8c51deced1f8cb664b4795b38db0de3
\ No newline at end of file
+d169de0fca9b4877a41c970bf1fc94a811330ad9
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
index acda0ca..2d353d7 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-ac2d6010c8b2edbd6a804e23d12f3cd3f50fd29b
\ No newline at end of file
+72467222d067617e7088c526ca4b24750f3534b6
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
index 1dc503b..06efe29d 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-f7c52d2ffe76ea884072b0720a9ed097f5be7d81
\ No newline at end of file
+a38c0458ab355abe778d74a51fd2b00270a96804
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
index 3e11286..a37444e7 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-b8846835ac42e18f5a4f2104c8ce73319485d832
\ No newline at end of file
+db7ad368e610c4259b4fa3041062cee198ce287b
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
index 72f5f68..059aaf3 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-3eac3899dca38a3a6ba86904c2c969011deff95e
\ No newline at end of file
+c3ed462a5d006f94c8d6fa2bb86c3d0e8d897c8a
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
index d3dbffb3..5977804 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-5b858c77c8be47ad40261ffc192b7f1a70fa0c03
\ No newline at end of file
+f2062e0f7ae779d4ff6517c1a889613e86ae1c17
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
index e7584bd..7e2be80d 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-7c31dba391f1af7bfb2a9b53f658a128236e28d4
\ No newline at end of file
+483c9cecbd4565d96582ff88c5472e69139e2d34
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
index 7da47043..29d826f 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-a19aa3467f108a49c9e99943b027dde6049bbe5c
\ No newline at end of file
+32119785c1f19d9e37ad808ccb7c29d54e62ff29
\ No newline at end of file
diff --git a/media/base/video_frame_metadata.cc b/media/base/video_frame_metadata.cc
index 3a958605..6e82873 100644
--- a/media/base/video_frame_metadata.cc
+++ b/media/base/video_frame_metadata.cc
@@ -37,7 +37,7 @@
   MERGE_OPTIONAL_FIELD(capture_update_rect, metadata_source);
   MERGE_OPTIONAL_FIELD(region_capture_rect, metadata_source);
   MERGE_VALUE_FIELD(crop_version, metadata_source);
-  MERGE_OPTIONAL_FIELD(copy_mode, metadata_source);
+  MERGE_OPTIONAL_FIELD(copy_required, metadata_source);
   MERGE_VALUE_FIELD(end_of_stream, metadata_source);
   MERGE_OPTIONAL_FIELD(frame_duration, metadata_source);
   MERGE_OPTIONAL_FIELD(frame_rate, metadata_source);
diff --git a/media/base/video_frame_metadata.h b/media/base/video_frame_metadata.h
index f5e852e0..26dbe8a 100644
--- a/media/base/video_frame_metadata.h
+++ b/media/base/video_frame_metadata.h
@@ -24,27 +24,6 @@
 
   VideoFrameMetadata(const VideoFrameMetadata& other);
 
-  enum CopyMode {
-    // Indicates that mailbox created in one context, is also being used in a
-    // different context belonging to another share group and video frames are
-    // using SurfaceTexture to render frames.
-    // Textures generated from SurfaceTexture can't be shared between contexts
-    // of different share group and hence this frame must be copied to a new
-    // texture before use, rather than being used directly.
-    kCopyToNewTexture = 0,
-
-    // Indicates that mailbox created in one context, is also being used in a
-    // different context belonging to another share group and video frames are
-    // using AImageReader to render frames.
-    // AImageReader allows to render image data to AHardwareBuffer which can be
-    // shared between contexts of different share group. AHB from existing
-    // mailbox is wrapped into a new mailbox(AHB backed) which can then be used
-    // by another context.
-    // NO LONGER USED: After enabling WebViewThreadSafeMedia, ZeroCopy path is
-    // no longer used.
-    kCopyMailboxesOnly = 1,
-  };
-
   // Merges internal values from |metadata_source|.
   void MergeMetadataFrom(const VideoFrameMetadata& metadata_source);
 
@@ -88,9 +67,13 @@
   // have this value set to zero.
   uint32_t crop_version = 0;
 
-  // If not null, it indicates how video frame mailbox should be copied to a
-  // new mailbox.
-  absl::optional<CopyMode> copy_mode;
+  // Indicates that mailbox created in one context, is also being used in a
+  // different context belonging to another share group and video frames are
+  // using SurfaceTexture to render frames.
+  // Textures generated from SurfaceTexture can't be shared between contexts
+  // of different share group and hence this frame must be copied to a new
+  // texture before use, rather than being used directly.
+  bool copy_required = false;
 
   // Indicates if the current frame is the End of its current Stream.
   bool end_of_stream = false;
diff --git a/media/base/video_frame_unittest.cc b/media/base/video_frame_unittest.cc
index 5db228c0..cc1b210 100644
--- a/media/base/video_frame_unittest.cc
+++ b/media/base/video_frame_unittest.cc
@@ -62,11 +62,9 @@
   // media::VideoTransformation
   metadata.transformation = media::VIDEO_ROTATION_90;
 
-  // media::VideoFrameMetadata::CopyMode
-  metadata.copy_mode = media::VideoFrameMetadata::CopyMode::kCopyToNewTexture;
-
   // bools
   metadata.allow_overlay = true;
+  metadata.copy_required = true;
   metadata.end_of_stream = true;
   metadata.texture_owner = true;
   metadata.wants_promotion_hint = true;
@@ -112,7 +110,7 @@
   EXPECT_EQ(a.capture_end_time, b.capture_end_time);
   EXPECT_EQ(a.capture_counter, b.capture_counter);
   EXPECT_EQ(a.capture_update_rect, b.capture_update_rect);
-  EXPECT_EQ(a.copy_mode, b.copy_mode);
+  EXPECT_EQ(a.copy_required, b.copy_required);
   EXPECT_EQ(a.end_of_stream, b.end_of_stream);
   EXPECT_EQ(a.frame_duration, b.frame_duration);
   EXPECT_EQ(a.frame_rate, b.frame_rate);
diff --git a/media/base/video_util.cc b/media/base/video_util.cc
index 64d5bae..60475b69d 100644
--- a/media/base/video_util.cc
+++ b/media/base/video_util.cc
@@ -768,6 +768,9 @@
 EncoderStatus ConvertAndScaleFrame(const VideoFrame& src_frame,
                                    VideoFrame& dst_frame,
                                    std::vector<uint8_t>& tmp_buf) {
+  TRACE_EVENT2("media", "ConvertAndScaleFrame", "src_format",
+               VideoPixelFormatToString(src_frame.format()), "dst_format",
+               VideoPixelFormatToString(dst_frame.format()));
   constexpr auto kDefaultFiltering = libyuv::kFilterBox;
   if (!src_frame.IsMappable() || !dst_frame.IsMappable())
     return EncoderStatus::Codes::kUnsupportedFrameFormat;
diff --git a/media/base/win/dxgi_device_manager.cc b/media/base/win/dxgi_device_manager.cc
index aefa9238..b1bcfbd 100644
--- a/media/base/win/dxgi_device_manager.cc
+++ b/media/base/win/dxgi_device_manager.cc
@@ -97,9 +97,13 @@
     Microsoft::WRL::ComPtr<ID3D11Device>& d3d_device) {
   constexpr uint32_t kDeviceFlags =
       D3D11_CREATE_DEVICE_VIDEO_SUPPORT | D3D11_CREATE_DEVICE_BGRA_SUPPORT;
-  HRESULT hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr,
-                                 kDeviceFlags, nullptr, 0, D3D11_SDK_VERSION,
-                                 &d3d_device, nullptr, nullptr);
+  const D3D_FEATURE_LEVEL kFeatureLevels[] = {
+      D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1,
+      D3D_FEATURE_LEVEL_10_0};
+  HRESULT hr =
+      D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr,
+                        kDeviceFlags, kFeatureLevels, std::size(kFeatureLevels),
+                        D3D11_SDK_VERSION, &d3d_device, nullptr, nullptr);
   RETURN_ON_HR_FAILURE(hr, "D3D11 device creation failed", hr);
   RETURN_ON_HR_FAILURE(
       hr, media::SetDebugName(d3d_device.Get(), "Media_DXGIDeviceManager"), hr);
diff --git a/media/gpu/android/codec_image_unittest.cc b/media/gpu/android/codec_image_unittest.cc
index e55f6858..70dd296 100644
--- a/media/gpu/android/codec_image_unittest.cc
+++ b/media/gpu/android/codec_image_unittest.cc
@@ -52,7 +52,7 @@
 
     gl::init::InitializeStaticGLBindingsImplementation(
         gl::GLImplementationParts(gl::kGLImplementationEGLGLES2), false);
-    display_ = gl::init::InitializeGLOneOffPlatformImplementation(
+    gl::init::InitializeGLOneOffPlatformImplementation(
         /*fallback_to_software_gl=*/false,
         /*disable_gl_drawing=*/false,
         /*init_extensions=*/false,
@@ -83,7 +83,7 @@
     context_ = nullptr;
     share_group_ = nullptr;
     surface_ = nullptr;
-    gl::init::ShutdownGL(display_, false);
+    gl::init::ShutdownGL(false);
     wrapper_->TakeCodecSurfacePair();
   }
 
@@ -121,7 +121,6 @@
   scoped_refptr<gl::GLShareGroup> share_group_;
   scoped_refptr<gl::GLSurface> surface_;
   GLuint texture_id_ = 0;
-  gl::GLDisplay* display_ = nullptr;
 
   class PromotionHintReceiver {
    public:
diff --git a/media/gpu/android/video_frame_factory_impl.cc b/media/gpu/android/video_frame_factory_impl.cc
index 1865f1da..f03da544 100644
--- a/media/gpu/android/video_frame_factory_impl.cc
+++ b/media/gpu/android/video_frame_factory_impl.cc
@@ -34,22 +34,6 @@
 namespace media {
 namespace {
 
-// The frames must be copied when threaded texture mailboxes are in use
-// (http://crbug.com/582170). This texture copy can be avoided if
-// AImageReader/AHardwareBuffer is supported and AImageReader
-// max size is not limited to 1 (crbug.com/1091945).
-absl::optional<VideoFrameMetadata::CopyMode> GetVideoFrameCopyMode(
-    bool enable_threaded_texture_mailboxes) {
-  if (!enable_threaded_texture_mailboxes)
-    return absl::nullopt;
-
-  // If we can run thread-safe, we don't need to copy.
-  if (features::NeedThreadSafeAndroidMedia())
-    return absl::nullopt;
-
-  return VideoFrameMetadata::CopyMode::kCopyToNewTexture;
-}
-
 gpu::TextureOwner::Mode GetTextureOwnerMode(
     VideoFrameFactory::OverlayMode overlay_mode) {
   switch (overlay_mode) {
@@ -102,13 +86,11 @@
     : gpu::RefCountedLockHelperDrDc(std::move(drdc_lock)),
       image_provider_(std::move(image_provider)),
       gpu_task_runner_(std::move(gpu_task_runner)),
-      copy_mode_(GetVideoFrameCopyMode(
-          gpu_preferences.enable_threaded_texture_mailboxes)),
+      video_frame_copy_required_(
+          gpu_preferences.enable_threaded_texture_mailboxes &&
+          !features::NeedThreadSafeAndroidMedia()),
       mre_manager_(std::move(mre_manager)),
-      frame_info_helper_(std::move(frame_info_helper)) {
-  DCHECK(!copy_mode_.has_value() ||
-         *copy_mode_ != VideoFrameMetadata::CopyMode::kCopyMailboxesOnly);
-}
+      frame_info_helper_(std::move(frame_info_helper)) {}
 
 VideoFrameFactoryImpl::~VideoFrameFactoryImpl() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -190,11 +172,12 @@
     return;
   }
 
-  auto image_ready_cb = base::BindOnce(
-      &VideoFrameFactoryImpl::CreateVideoFrame_OnImageReady,
-      weak_factory_.GetWeakPtr(), std::move(output_cb), timestamp, natural_size,
-      !!codec_buffer_wait_coordinator_, std::move(promotion_hint_cb),
-      pixel_format, overlay_mode_, copy_mode_, gpu_task_runner_);
+  auto image_ready_cb =
+      base::BindOnce(&VideoFrameFactoryImpl::CreateVideoFrame_OnImageReady,
+                     weak_factory_.GetWeakPtr(), std::move(output_cb),
+                     timestamp, natural_size, !!codec_buffer_wait_coordinator_,
+                     std::move(promotion_hint_cb), pixel_format, overlay_mode_,
+                     video_frame_copy_required_, gpu_task_runner_);
 
   RequestImage(std::move(output_buffer_renderer), std::move(image_ready_cb));
 }
@@ -251,7 +234,7 @@
     PromotionHintAggregator::NotifyPromotionHintCB promotion_hint_cb,
     VideoPixelFormat pixel_format,
     OverlayMode overlay_mode,
-    const absl::optional<VideoFrameMetadata::CopyMode>& copy_mode,
+    bool video_frame_copy_required,
     scoped_refptr<base::SequencedTaskRunner> gpu_task_runner,
     std::unique_ptr<CodecOutputBufferRenderer> output_buffer_renderer,
     FrameInfoHelper::FrameInfo frame_info,
@@ -302,7 +285,9 @@
     std::move(output_cb).Run(nullptr);
     return;
   }
-  frame->metadata().copy_mode = copy_mode;
+
+  frame->metadata().copy_required = video_frame_copy_required;
+
   const bool is_surface_control =
       overlay_mode == OverlayMode::kSurfaceControlSecure ||
       overlay_mode == OverlayMode::kSurfaceControlInsecure;
diff --git a/media/gpu/android/video_frame_factory_impl.h b/media/gpu/android/video_frame_factory_impl.h
index cd30f4b..4210978 100644
--- a/media/gpu/android/video_frame_factory_impl.h
+++ b/media/gpu/android/video_frame_factory_impl.h
@@ -101,7 +101,7 @@
       PromotionHintAggregator::NotifyPromotionHintCB promotion_hint_cb,
       VideoPixelFormat pixel_format,
       OverlayMode overlay_mode,
-      const absl::optional<VideoFrameMetadata::CopyMode>& copy_mode,
+      bool video_frame_copy_required,
       scoped_refptr<base::SequencedTaskRunner> gpu_task_runner,
       std::unique_ptr<CodecOutputBufferRenderer> output_buffer_renderer,
       FrameInfoHelper::FrameInfo frame_info,
@@ -122,8 +122,8 @@
 
   OverlayMode overlay_mode_ = OverlayMode::kDontRequestPromotionHints;
 
-  // Indicates how video frame needs to be copied when required.
-  absl::optional<VideoFrameMetadata::CopyMode> copy_mode_;
+  // Is the video frame copy required?
+  bool video_frame_copy_required_ = false;
 
   // Current group that new CodecImages should belong to.  Do not use this on
   // our thread; everything must be posted to the gpu main thread, including
diff --git a/media/gpu/vaapi/vaapi_video_encode_accelerator.cc b/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
index 9eb02a6b..91e101af 100644
--- a/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
+++ b/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
@@ -102,19 +102,8 @@
     VaapiWrapper& vaapi_wrapper,
     const gfx::Size& encode_size,
     const std::vector<VaapiWrapper::SurfaceUsageHint>& surface_usage_hints) {
-  // iHD driver doesn't align a resolution for encoding properly. Align it only
-  // with encoder driver.
-  // TODO(https://github.com/intel/media-driver/issues/1232): Remove this
-  // workaround of aligning |encode_size|.
-  gfx::Size surface_size = encode_size;
-  if (!base::Contains(surface_usage_hints,
-                      VaapiWrapper::SurfaceUsageHint::kVideoProcessWrite)) {
-    surface_size = gfx::Size(base::bits::AlignUp(encode_size.width(), 16u),
-                             base::bits::AlignUp(encode_size.height(), 16u));
-  }
-
   auto surfaces = vaapi_wrapper.CreateScopedVASurfaces(
-      kVaSurfaceFormat, surface_size, surface_usage_hints, 1u,
+      kVaSurfaceFormat, encode_size, surface_usage_hints, 1u,
       /*visible_size=*/absl::nullopt,
       /*va_fourcc=*/absl::nullopt);
   return surfaces.empty() ? nullptr : std::move(surfaces.front());
diff --git a/media/gpu/vaapi/vaapi_video_encode_accelerator_unittest.cc b/media/gpu/vaapi/vaapi_video_encode_accelerator_unittest.cc
index 1fae441..71a48b7 100644
--- a/media/gpu/vaapi/vaapi_video_encode_accelerator_unittest.cc
+++ b/media/gpu/vaapi/vaapi_video_encode_accelerator_unittest.cc
@@ -538,16 +538,10 @@
 
       // For reconstructed surface.
       if (va_encode_surface_ids_[i].empty()) {
-        // TODO(https://github.com/intel/media-driver/issues/1232): Remove this
-        // workaround of aligning |encode_size|.
-        gfx::Size aligned_size(
-            base::bits::AlignUp(svc_resolutions[i].width(), 16),
-            base::bits::AlignUp(svc_resolutions[i].height(), 16));
-
         EXPECT_CALL(
             *mock_vaapi_wrapper_,
             CreateScopedVASurfaces(
-                VA_RT_FORMAT_YUV420, aligned_size,
+                VA_RT_FORMAT_YUV420, svc_resolutions[i],
                 std::vector<VaapiWrapper::SurfaceUsageHint>{
                     VaapiWrapper::SurfaceUsageHint::kVideoEncoder},
                 _, absl::optional<gfx::Size>(), absl::optional<uint32_t>()))
diff --git a/media/gpu/windows/d3d11_texture_wrapper_unittest.cc b/media/gpu/windows/d3d11_texture_wrapper_unittest.cc
index 313de844..3a182d0 100644
--- a/media/gpu/windows/d3d11_texture_wrapper_unittest.cc
+++ b/media/gpu/windows/d3d11_texture_wrapper_unittest.cc
@@ -44,7 +44,7 @@
 
     task_runner_ = task_environment_.GetMainThreadTaskRunner();
 
-    display_ = gl::GLSurfaceTestSupport::InitializeOneOffImplementation(
+    gl::GLSurfaceTestSupport::InitializeOneOffImplementation(
         gl::GLImplementationParts(gl::ANGLEImplementation::kD3D11), false);
     surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size());
     share_group_ = new gl::GLShareGroup();
@@ -66,7 +66,7 @@
     context_ = nullptr;
     share_group_ = nullptr;
     surface_ = nullptr;
-    gl::GLSurfaceTestSupport::ShutdownGL(display_);
+    gl::init::ShutdownGL(false);
   }
 
   base::test::TaskEnvironment task_environment_;
@@ -83,8 +83,6 @@
   // a wrapper.
   scoped_refptr<FakeCommandBufferHelper> fake_command_buffer_helper_;
   GetCommandBufferHelperCB get_helper_cb_;
-
-  gl::GLDisplay* display_ = nullptr;
 };
 
 TEST_F(D3D11TextureWrapperUnittest, NV12InitSucceeds) {
diff --git a/media/mojo/mojom/BUILD.gn b/media/mojo/mojom/BUILD.gn
index cbeae27..008e0bc9 100644
--- a/media/mojo/mojom/BUILD.gn
+++ b/media/mojo/mojom/BUILD.gn
@@ -260,15 +260,6 @@
     {
       types = [
         {
-          mojom = "media.mojom.CopyMode"
-          cpp = "::media::VideoFrameMetadata::CopyMode"
-        },
-      ]
-      traits_headers = [ "media_types_enum_mojom_traits.h" ]
-    },
-    {
-      types = [
-        {
           mojom = "media.mojom.VideoRotation"
           cpp = "::media::VideoRotation"
         },
diff --git a/media/mojo/mojom/media_types.mojom b/media/mojo/mojom/media_types.mojom
index 38493d3..e5ff8d6 100644
--- a/media/mojo/mojom/media_types.mojom
+++ b/media/mojo/mojom/media_types.mojom
@@ -76,12 +76,6 @@
   kVideoRotation270,
 };
 
-// see media/base/video_frame_metadata.h for descriptions.
-enum CopyMode {
-  kCopyToNewTexture,
-  kCopyMailboxesOnly,
-};
-
 // see third_party/blink/public/platform/web_fullscreen_video_status.h for
 // descriptions.
 [Native]
@@ -311,8 +305,7 @@
   gfx.mojom.Rect? region_capture_rect;
   uint32 crop_version;
 
-  bool has_copy_mode;
-  CopyMode copy_mode;
+  bool copy_required;
 
   bool end_of_stream;
 
diff --git a/media/mojo/mojom/media_types_enum_mojom_traits.h b/media/mojo/mojom/media_types_enum_mojom_traits.h
index 18924b4..2105313 100644
--- a/media/mojo/mojom/media_types_enum_mojom_traits.h
+++ b/media/mojo/mojom/media_types_enum_mojom_traits.h
@@ -9,7 +9,6 @@
 #include "build/build_config.h"
 #include "media/base/renderer_factory_selector.h"
 #include "media/base/svc_scalability_mode.h"
-#include "media/base/video_frame_metadata.h"
 #include "media/base/video_transformation.h"
 #include "media/cdm/cdm_document_service.h"
 #include "media/mojo/mojom/media_types.mojom-shared.h"
@@ -271,40 +270,6 @@
 };
 
 template <>
-struct EnumTraits<media::mojom::CopyMode,
-                  ::media::VideoFrameMetadata::CopyMode> {
-  static media::mojom::CopyMode ToMojom(
-      ::media::VideoFrameMetadata::CopyMode input) {
-    switch (input) {
-      case ::media::VideoFrameMetadata::CopyMode::kCopyToNewTexture:
-        return media::mojom::CopyMode::kCopyToNewTexture;
-      case ::media::VideoFrameMetadata::CopyMode::kCopyMailboxesOnly:
-        return media::mojom::CopyMode::kCopyMailboxesOnly;
-    }
-
-    NOTREACHED();
-    return static_cast<media::mojom::CopyMode>(input);
-  }
-
-  // Returning false results in deserialization failure and causes the
-  // message pipe receiving it to be disconnected.
-  static bool FromMojom(media::mojom::CopyMode input,
-                        media::VideoFrameMetadata::CopyMode* output) {
-    switch (input) {
-      case media::mojom::CopyMode::kCopyToNewTexture:
-        *output = ::media::VideoFrameMetadata::CopyMode::kCopyToNewTexture;
-        return true;
-      case media::mojom::CopyMode::kCopyMailboxesOnly:
-        *output = ::media::VideoFrameMetadata::CopyMode::kCopyMailboxesOnly;
-        return true;
-    }
-
-    NOTREACHED();
-    return false;
-  }
-};
-
-template <>
 struct EnumTraits<media::mojom::RendererType, ::media::RendererType> {
   static media::mojom::RendererType ToMojom(::media::RendererType input) {
     switch (input) {
diff --git a/media/mojo/mojom/stable/stable_video_decoder_types.mojom b/media/mojo/mojom/stable/stable_video_decoder_types.mojom
index acc70e7..810c4fc6a 100644
--- a/media/mojo/mojom/stable/stable_video_decoder_types.mojom
+++ b/media/mojo/mojom/stable/stable_video_decoder_types.mojom
@@ -425,7 +425,7 @@
 };
 
 // Based on |media.mojom.VideoFrameMetadata| but does not depend on
-// |media.mojom.VideoTransformation| or |media.mojom.CopyMode|.
+// |media.mojom.VideoTransformation|.
 // Next min field ID: 6
 [Stable]
 struct VideoFrameMetadata {
diff --git a/media/mojo/mojom/video_frame_metadata_mojom_traits.cc b/media/mojo/mojom/video_frame_metadata_mojom_traits.cc
index 0187c8c3..c8417a4b 100644
--- a/media/mojo/mojom/video_frame_metadata_mojom_traits.cc
+++ b/media/mojo/mojom/video_frame_metadata_mojom_traits.cc
@@ -37,6 +37,7 @@
 
   // bool.
   output->allow_overlay = input.allow_overlay();
+  output->copy_required = input.copy_required();
   output->end_of_stream = input.end_of_stream();
   output->texture_owner = input.texture_owner();
   output->wants_promotion_hint = input.wants_promotion_hint();
@@ -60,13 +61,6 @@
   READ_AND_ASSIGN_OPT(media::VideoTransformation, transformation,
                       Transformation);
 
-  if (input.has_copy_mode()) {
-    media::VideoFrameMetadata::CopyMode copy_mode;
-    if (!input.ReadCopyMode(&copy_mode))
-      return false;
-    output->copy_mode = copy_mode;
-  }
-
   READ_AND_ASSIGN_OPT(base::UnguessableToken, overlay_plane_id, OverlayPlaneId);
 
   READ_AND_ASSIGN_OPT(gfx::Rect, capture_update_rect, CaptureUpdateRect);
@@ -87,4 +81,4 @@
   return true;
 }
 
-}  // namespace mojo
+}  // namespace mojo
\ No newline at end of file
diff --git a/media/mojo/mojom/video_frame_metadata_mojom_traits.h b/media/mojo/mojom/video_frame_metadata_mojom_traits.h
index 06578553..1ce7fbd2 100644
--- a/media/mojo/mojom/video_frame_metadata_mojom_traits.h
+++ b/media/mojo/mojom/video_frame_metadata_mojom_traits.h
@@ -35,6 +35,10 @@
     return input.allow_overlay;
   }
 
+  static bool copy_required(const media::VideoFrameMetadata& input) {
+    return input.copy_required;
+  }
+
   static bool end_of_stream(const media::VideoFrameMetadata& input) {
     return input.end_of_stream;
   }
@@ -82,11 +86,6 @@
 
   GENERATE_OPT_SERIALIZATION(int, capture_counter, 0)
 
-  GENERATE_OPT_SERIALIZATION(
-      media::VideoFrameMetadata::CopyMode,
-      copy_mode,
-      media::VideoFrameMetadata::CopyMode::kCopyToNewTexture)
-
   static const absl::optional<media::VideoTransformation>& transformation(
       const media::VideoFrameMetadata& input) {
     return input.transformation;
diff --git a/media/mojo/mojom/video_frame_metadata_mojom_traits_unittest.cc b/media/mojo/mojom/video_frame_metadata_mojom_traits_unittest.cc
index 7c646430..cf7090d 100644
--- a/media/mojo/mojom/video_frame_metadata_mojom_traits_unittest.cc
+++ b/media/mojo/mojom/video_frame_metadata_mojom_traits_unittest.cc
@@ -66,7 +66,7 @@
   EXPECT_FALSE(metadata_out.capture_update_rect.has_value());
   EXPECT_FALSE(metadata_out.transformation.has_value());
   EXPECT_FALSE(metadata_out.allow_overlay);
-  EXPECT_FALSE(metadata_out.copy_mode.has_value());
+  EXPECT_FALSE(metadata_out.copy_required);
   EXPECT_FALSE(metadata_out.end_of_stream);
   EXPECT_FALSE(metadata_out.texture_owner);
   EXPECT_FALSE(metadata_out.wants_promotion_hint);
@@ -109,11 +109,9 @@
   // VideoTransformation
   metadata_in.transformation = VideoTransformation(VIDEO_ROTATION_90, true);
 
-  // VideoFrameMetadata::CopyMode
-  metadata_in.copy_mode = VideoFrameMetadata::CopyMode::kCopyToNewTexture;
-
   // bools
   metadata_in.allow_overlay = true;
+  metadata_in.copy_required = true;
   metadata_in.end_of_stream = true;
   metadata_in.texture_owner = true;
   metadata_in.wants_promotion_hint = true;
@@ -158,7 +156,7 @@
   EXPECT_EQ(metadata_in.capture_update_rect, metadata_out.capture_update_rect);
   EXPECT_EQ(metadata_in.transformation, metadata_out.transformation);
   EXPECT_EQ(metadata_in.allow_overlay, metadata_out.allow_overlay);
-  EXPECT_EQ(metadata_in.copy_mode, metadata_out.copy_mode);
+  EXPECT_EQ(metadata_in.copy_required, metadata_out.copy_required);
   EXPECT_EQ(metadata_in.end_of_stream, metadata_out.end_of_stream);
   EXPECT_EQ(metadata_in.texture_owner, metadata_out.texture_owner);
   EXPECT_EQ(metadata_in.wants_promotion_hint,
diff --git a/media/renderers/paint_canvas_video_renderer_unittest.cc b/media/renderers/paint_canvas_video_renderer_unittest.cc
index fa81b71..98363ec 100644
--- a/media/renderers/paint_canvas_video_renderer_unittest.cc
+++ b/media/renderers/paint_canvas_video_renderer_unittest.cc
@@ -1047,7 +1047,7 @@
   using GetColorCallback = base::RepeatingCallback<SkColor(int, int)>;
 
   void SetUp() override {
-    display_ = gl::GLSurfaceTestSupport::InitializeOneOff();
+    gl::GLSurfaceTestSupport::InitializeOneOff();
     enable_pixels_.emplace();
     media_context_ = base::MakeRefCounted<viz::TestInProcessContextProvider>(
         viz::TestContextType::kGpuRaster, /*support_locking=*/false);
@@ -1074,7 +1074,7 @@
     media_context_.reset();
     enable_pixels_.reset();
     viz::TestGpuServiceHolder::ResetInstance();
-    gl::GLSurfaceTestSupport::ShutdownGL(display_);
+    gl::GLSurfaceTestSupport::ShutdownGL();
   }
 
   // Uses CopyVideoFrameTexturesToGLTexture to copy |frame| into a GL texture,
@@ -1237,7 +1237,6 @@
   PaintCanvasVideoRenderer renderer_;
   scoped_refptr<VideoFrame> cropped_frame_;
   base::test::TaskEnvironment task_environment_;
-  gl::GLDisplay* display_ = nullptr;
 };
 
 TEST_F(PaintCanvasVideoRendererWithGLTest, CopyVideoFrameYUVDataToGLTexture) {
diff --git a/media/renderers/video_resource_updater.cc b/media/renderers/video_resource_updater.cc
index 8fb5dea..de46e68 100644
--- a/media/renderers/video_resource_updater.cc
+++ b/media/renderers/video_resource_updater.cc
@@ -870,10 +870,11 @@
   VideoFrameExternalResources external_resources;
   gfx::ColorSpace resource_color_space = video_frame->ColorSpace();
 
-  const auto& copy_mode = video_frame->metadata().copy_mode;
+  const bool copy_required = video_frame->metadata().copy_required;
+
   GLuint target = video_frame->mailbox_holder(0).texture_target;
-  // If texture copy is required, then we will copy into a GL_TEXTURE_2D target.
-  if (copy_mode == VideoFrameMetadata::CopyMode::kCopyToNewTexture)
+  // If |copy_required| then we will copy into a GL_TEXTURE_2D target.
+  if (copy_required)
     target = GL_TEXTURE_2D;
 
   gfx::BufferFormat buffer_formats[VideoFrame::kMaxPlanes];
@@ -897,7 +898,8 @@
     const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(i);
     if (mailbox_holder.mailbox.IsZero())
       break;
-    if (copy_mode == VideoFrameMetadata::CopyMode::kCopyToNewTexture) {
+
+    if (copy_required) {
       CopyHardwarePlane(video_frame.get(), resource_color_space, mailbox_holder,
                         &external_resources);
     } else {
@@ -910,8 +912,10 @@
           video_frame->metadata().allow_overlay);
       transfer_resource.color_space = resource_color_space;
       transfer_resource.hdr_metadata = video_frame->hdr_metadata();
-      transfer_resource.read_lock_fences_enabled =
-          video_frame->metadata().read_lock_fences_enabled;
+      if (video_frame->metadata().read_lock_fences_enabled) {
+        transfer_resource.synchronization_type = viz::TransferableResource::
+            SynchronizationType::kGpuCommandsCompleted;
+      }
       transfer_resource.format = viz::GetResourceFormat(buffer_formats[i]);
       transfer_resource.ycbcr_info = video_frame->ycbcr_info();
 
diff --git a/media/renderers/video_resource_updater_unittest.cc b/media/renderers/video_resource_updater_unittest.cc
index b9025e87..3cd5e2b 100644
--- a/media/renderers/video_resource_updater_unittest.cc
+++ b/media/renderers/video_resource_updater_unittest.cc
@@ -214,10 +214,10 @@
   }
 
   scoped_refptr<VideoFrame> CreateTestStreamTextureHardwareVideoFrame(
-      absl::optional<VideoFrameMetadata::CopyMode> copy_mode) {
+      bool needs_copy) {
     scoped_refptr<VideoFrame> video_frame = CreateTestHardwareVideoFrame(
         PIXEL_FORMAT_ARGB, GL_TEXTURE_EXTERNAL_OES);
-    video_frame->metadata().copy_mode = std::move(copy_mode);
+    video_frame->metadata().copy_required = needs_copy;
     return video_frame;
   }
 
@@ -557,18 +557,27 @@
   EXPECT_EQ(VideoFrameResourceType::YUV, resources.type);
   EXPECT_EQ(3u, resources.resources.size());
   EXPECT_EQ(3u, resources.release_callbacks.size());
-  EXPECT_FALSE(resources.resources[0].read_lock_fences_enabled);
-  EXPECT_FALSE(resources.resources[1].read_lock_fences_enabled);
-  EXPECT_FALSE(resources.resources[2].read_lock_fences_enabled);
+  EXPECT_EQ(resources.resources[0].synchronization_type,
+            viz::TransferableResource::SynchronizationType::kSyncToken);
+  EXPECT_EQ(resources.resources[1].synchronization_type,
+            viz::TransferableResource::SynchronizationType::kSyncToken);
+  EXPECT_EQ(resources.resources[2].synchronization_type,
+            viz::TransferableResource::SynchronizationType::kSyncToken);
 
   video_frame = CreateTestYuvHardwareVideoFrame(PIXEL_FORMAT_I420, 3,
                                                 GL_TEXTURE_RECTANGLE_ARB);
   video_frame->metadata().read_lock_fences_enabled = true;
 
   resources = updater->CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_TRUE(resources.resources[0].read_lock_fences_enabled);
-  EXPECT_TRUE(resources.resources[1].read_lock_fences_enabled);
-  EXPECT_TRUE(resources.resources[2].read_lock_fences_enabled);
+  EXPECT_EQ(
+      resources.resources[0].synchronization_type,
+      viz::TransferableResource::SynchronizationType::kGpuCommandsCompleted);
+  EXPECT_EQ(
+      resources.resources[1].synchronization_type,
+      viz::TransferableResource::SynchronizationType::kGpuCommandsCompleted);
+  EXPECT_EQ(
+      resources.resources[2].synchronization_type,
+      viz::TransferableResource::SynchronizationType::kGpuCommandsCompleted);
 }
 
 TEST_F(VideoResourceUpdaterTest,
@@ -578,7 +587,7 @@
       CreateUpdaterForHardware(true);
   EXPECT_EQ(0u, GetSharedImageCount());
   scoped_refptr<VideoFrame> video_frame =
-      CreateTestStreamTextureHardwareVideoFrame(absl::nullopt);
+      CreateTestStreamTextureHardwareVideoFrame(/*needs_copy=*/false);
 
   VideoFrameExternalResources resources =
       updater->CreateExternalResourcesFromVideoFrame(video_frame);
@@ -591,8 +600,7 @@
 
   // A copied stream texture should return an RGBA resource in a new
   // GL_TEXTURE_2D texture.
-  video_frame = CreateTestStreamTextureHardwareVideoFrame(
-      VideoFrameMetadata::CopyMode::kCopyToNewTexture);
+  video_frame = CreateTestStreamTextureHardwareVideoFrame(/*needs_copy=*/true);
   resources = updater->CreateExternalResourcesFromVideoFrame(video_frame);
   EXPECT_EQ(VideoFrameResourceType::RGBA_PREMULTIPLIED, resources.type);
   EXPECT_EQ(1u, resources.resources.size());
@@ -606,7 +614,7 @@
   std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
   EXPECT_EQ(0u, GetSharedImageCount());
   scoped_refptr<VideoFrame> video_frame =
-      CreateTestStreamTextureHardwareVideoFrame(absl::nullopt);
+      CreateTestStreamTextureHardwareVideoFrame(/*needs_copy=*/false);
 
   VideoFrameExternalResources resources =
       updater->CreateExternalResourcesFromVideoFrame(video_frame);
@@ -692,8 +700,7 @@
   std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
 
   scoped_refptr<VideoFrame> video_frame =
-      CreateTestStreamTextureHardwareVideoFrame(
-          VideoFrameMetadata::CopyMode::kCopyToNewTexture);
+      CreateTestStreamTextureHardwareVideoFrame(/*needs_copy=*/true);
 
   VideoFrameExternalResources resources =
       updater->CreateExternalResourcesFromVideoFrame(video_frame);
diff --git a/media/renderers/win/media_foundation_source_wrapper.cc b/media/renderers/win/media_foundation_source_wrapper.cc
index 8d5d492..b1464b7 100644
--- a/media/renderers/win/media_foundation_source_wrapper.cc
+++ b/media/renderers/win/media_foundation_source_wrapper.cc
@@ -192,7 +192,7 @@
     }
 
     ComPtr<MediaFoundationStreamWrapper> stream = media_streams_[stream_id];
-    stream->SetFlushed(false);
+    stream->SetFlushing(false);
     if (selected) {
       MediaEventType event_type = MENewStream;
       if (stream->IsSelected()) {
@@ -556,7 +556,7 @@
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
   for (auto stream : media_streams_) {
-    stream->SetFlushed(true);
+    stream->SetFlushing(true);
   }
 }
 
diff --git a/media/renderers/win/media_foundation_stream_wrapper.cc b/media/renderers/win/media_foundation_stream_wrapper.cc
index 2102ff8cc..69ad479 100644
--- a/media/renderers/win/media_foundation_stream_wrapper.cc
+++ b/media/renderers/win/media_foundation_stream_wrapper.cc
@@ -227,15 +227,17 @@
   ProcessRequestsIfPossible();
 }
 
-void MediaFoundationStreamWrapper::SetFlushed(bool flushed) {
-  DVLOG_FUNC(2) << "flushed=" << flushed;
+void MediaFoundationStreamWrapper::SetFlushing(bool flushing) {
+  DVLOG_FUNC(2) << "flushing=" << flushing;
 
   base::AutoLock auto_lock(lock_);
-  flushed_ = flushed;
-  if (flushed_) {
-    while (!post_flush_buffers_.empty()) {
-      post_flush_buffers_.pop();
+  flushing_ = flushing;
+  if (flushing_) {
+    while (!queued_buffers_.empty()) {
+      queued_buffers_.pop();
     }
+  } else {
+    seek_awaiting_key_frame_ = true;
   }
 }
 
@@ -293,7 +295,6 @@
 
   {
     base::AutoLock auto_lock(lock_);
-
     if (state_ == State::kPaused || !enabled_)
       return;
 
@@ -303,7 +304,7 @@
   }
 
   if (ServicePostFlushSampleRequest()) {
-    // A sample has been consumed from the |post_flush_buffers_|.
+    // A sample has been consumed from the |queued_buffers_|.
     return;
   }
 
@@ -316,16 +317,47 @@
   pending_stream_read_ = true;
 }
 
-HRESULT MediaFoundationStreamWrapper::ServiceSampleRequest(
-    IUnknown* token,
-    DecoderBuffer* buffer) {
+// If servicing the request fails, we'll end up re-attempting to service the
+// buffer(s) from queued_buffers_ after the demuxer read. There is an
+// assumption here that a failure to process a specific buffer from
+// queued_buffers_ is recoverable.
+HRESULT MediaFoundationStreamWrapper::ServiceSampleRequest() {
   DVLOG_FUNC(3);
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
   lock_.AssertAcquired();
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  DCHECK(!queued_buffers_.empty());
+  DCHECK(!pending_sample_request_tokens_.empty());
+
+  DecoderBuffer* buffer = queued_buffers_.front().get();
+  IUnknown* token = pending_sample_request_tokens_.front().Get();
+
+  // Drain all non-key and non-EOS frames in a loop. Then if there are no
+  // frames left, return E_FAIL to trigger a new demuxer read; otherwise, use
+  // the new key frame to service the sample request or handle the EOS frame.
+  if (seek_awaiting_key_frame_) {
+    while (!queued_buffers_.empty()) {
+      buffer = queued_buffers_.front().get();
+
+      if (buffer->is_key_frame() || buffer->end_of_stream()) {
+        seek_awaiting_key_frame_ = false;
+        break;
+      } else {
+        queued_buffers_.pop();
+      }
+    }
+
+    if (seek_awaiting_key_frame_) {
+      DCHECK(queued_buffers_.empty());
+      return E_FAIL;
+    }
+
+    DCHECK(buffer->is_key_frame() || buffer->end_of_stream());
+  }
 
   if (buffer->end_of_stream()) {
     if (!enabled_) {
       DVLOG_FUNC(2) << "Ignoring EOS for disabled stream";
+      queued_buffers_.pop();
       // token not dropped to reflect an outstanding request that stream wrapper
       // should service when the stream is enabled
       return S_OK;
@@ -333,6 +365,7 @@
     DVLOG_FUNC(2) << "End of stream";
     RETURN_IF_FAILED(mf_media_event_queue_->QueueEventParamUnk(
         MEEndOfStream, GUID_NULL, S_OK, nullptr));
+
     stream_ended_ = true;
     if (parent_source_) {
       static_cast<MediaFoundationSourceWrapper*>(parent_source_.Get())
@@ -343,6 +376,10 @@
                   << ", is_key_frame=" << buffer->is_key_frame();
     ComPtr<IMFSample> mf_sample;
     RETURN_IF_FAILED(GenerateSampleFromDecoderBuffer(buffer, &mf_sample));
+
+    // The MF pipeline should usually provide a token when requesting a sample,
+    // but the API contract doesn't guarantee it and this could change. (see
+    // https://docs.microsoft.com/en-us/windows/win32/api/mfidl/nf-mfidl-imfmediastream-requestsample)
     if (token) {
       RETURN_IF_FAILED(mf_sample->SetUnknown(MFSampleExtension_Token, token));
     }
@@ -352,6 +389,7 @@
   }
 
   pending_sample_request_tokens_.pop();
+  queued_buffers_.pop();
 
   return S_OK;
 }
@@ -361,20 +399,16 @@
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
   base::AutoLock auto_lock(lock_);
-  if ((flushed_ && state_ != State::kStarted) || post_flush_buffers_.empty()) {
+  if ((flushing_ && state_ != State::kStarted) || queued_buffers_.empty()) {
     return false;
   }
 
-  DCHECK(!pending_sample_request_tokens_.empty());
-  ComPtr<IUnknown> request_token = pending_sample_request_tokens_.front();
-  HRESULT hr = ServiceSampleRequest(request_token.Get(),
-                                    post_flush_buffers_.front().get());
+  HRESULT hr = ServiceSampleRequest();
   if (FAILED(hr)) {
     DLOG(WARNING) << "Failed to service post flush sample: " << PrintHr(hr);
     return false;
   }
 
-  post_flush_buffers_.pop();
   return true;
 }
 
@@ -400,7 +434,6 @@
     DCHECK(pending_stream_read_);
     pending_stream_read_ = false;
 
-    ComPtr<IUnknown> token = pending_sample_request_tokens_.front();
     HRESULT hr = S_OK;
 
     if (status == DemuxerStream::Status::kOk) {
@@ -409,19 +442,10 @@
         ReportEncryptionType(buffer);
       }
 
-      // Push |buffer| to process later if needed. Otherwise, process it
-      // immediately.
-      if (flushed_ || !post_flush_buffers_.empty()) {
-        DVLOG_FUNC(3) << "push buffer.";
-        post_flush_buffers_.push(buffer);
-      } else {
-        hr = ServiceSampleRequest(token.Get(), buffer.get());
-        if (FAILED(hr)) {
-          DLOG(ERROR) << __func__
-                      << ": ServiceSampleRequest failed: " << PrintHr(hr);
-          return;
-        }
-      }
+      // Push |buffer| to process later.
+      DCHECK(buffer != nullptr);
+      DVLOG_FUNC(3) << "push buffer.";
+      queued_buffers_.push(buffer);
     } else if (status == DemuxerStream::Status::kConfigChanged) {
       DVLOG_FUNC(2) << "Stream config changed, AreFormatChangesEnabled="
                     << AreFormatChangesEnabled();
diff --git a/media/renderers/win/media_foundation_stream_wrapper.h b/media/renderers/win/media_foundation_stream_wrapper.h
index 22cf6c3..3b855c04 100644
--- a/media/renderers/win/media_foundation_stream_wrapper.h
+++ b/media/renderers/win/media_foundation_stream_wrapper.h
@@ -70,7 +70,7 @@
   bool IsSelected();
   bool IsEnabled();
   void SetEnabled(bool enabled);
-  void SetFlushed(bool flushed);
+  void SetFlushing(bool flushing);
 
   // TODO: revisting inheritance and potentially replacing it with composition.
 
@@ -116,8 +116,7 @@
   HRESULT GenerateStreamDescriptor();
   HRESULT GenerateSampleFromDecoderBuffer(DecoderBuffer* buffer,
                                           IMFSample** sample_out);
-  HRESULT ServiceSampleRequest(IUnknown* token, DecoderBuffer* buffer)
-      EXCLUSIVE_LOCKS_REQUIRED(lock_);
+  HRESULT ServiceSampleRequest() EXCLUSIVE_LOCKS_REQUIRED(lock_);
   // Returns true when a sample request has been serviced.
   bool ServicePostFlushSampleRequest();
   virtual HRESULT GetMediaType(IMFMediaType** media_type_out) = 0;
@@ -148,9 +147,13 @@
 
   // Indicates whether the Chromium pipeline has flushed the renderer
   // (prior to a seek).
-  // Since SetFlushed() can be invoked by media stack thread or MF threadpool
-  // thread, |flushed_| and |post_flush_buffers_| are protected by lock.
-  bool flushed_ GUARDED_BY(lock_) = false;
+  // Since SetFlushing() can be invoked by media stack thread or MF threadpool
+  // thread, |flushing_| and |queued_buffers_| are protected by lock.
+  bool flushing_ GUARDED_BY(lock_) = false;
+
+  // Indicates whether the stream has just performed a seek and is
+  // awaiting a KeyFrame before rendering further.
+  bool seek_awaiting_key_frame_ GUARDED_BY(lock_) = false;
 
   int stream_id_;
 
@@ -171,10 +174,8 @@
   bool stream_ended_ = false;
   GUID last_key_id_ = GUID_NULL;
 
-  // Save media::DecoderBuffer from OnDemuxerStreamRead call when we are in
-  // progress of a flush operation.
-  std::queue<scoped_refptr<DecoderBuffer>> post_flush_buffers_
-      GUARDED_BY(lock_);
+  // Save media::DecoderBuffer from OnDemuxerStreamRead call.
+  std::queue<scoped_refptr<DecoderBuffer>> queued_buffers_ GUARDED_BY(lock_);
 
   bool encryption_type_reported_ = false;
 
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index b51d9d3c..7ffc06b 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -274,7 +274,7 @@
   return GetSocketPoolManager(pool_type)->GetSocketPool(proxy_server);
 }
 
-std::unique_ptr<base::Value> HttpNetworkSession::SocketPoolInfoToValue() const {
+base::Value HttpNetworkSession::SocketPoolInfoToValue() const {
   // TODO(yutak): Should merge values from normal pools and WebSocket pools.
   return normal_socket_pool_manager_->SocketPoolInfoToValue();
 }
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index 3b96c6c..536aaab 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -22,6 +22,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
+#include "base/values.h"
 #include "build/buildflag.h"
 #include "net/base/host_mapping_rules.h"
 #include "net/base/host_port_pair.h"
@@ -261,7 +262,7 @@
 #endif
 
   // Creates a Value summary of the state of the socket pools.
-  std::unique_ptr<base::Value> SocketPoolInfoToValue() const;
+  base::Value SocketPoolInfoToValue() const;
 
   // Creates a Value summary of the state of the SPDY sessions.
   std::unique_ptr<base::Value> SpdySessionPoolInfoToValue() const;
diff --git a/net/log/net_log_util.cc b/net/log/net_log_util.cc
index 21c53e6..38d1e00 100644
--- a/net/log/net_log_util.cc
+++ b/net/log/net_log_util.cc
@@ -400,8 +400,7 @@
   // Log Socket Pool info.
   {
     net_info_dict.Set(kNetInfoSocketPool,
-                      base::Value::FromUniquePtrValue(
-                          http_network_session->SocketPoolInfoToValue()));
+                      http_network_session->SocketPoolInfoToValue());
   }
 
   // Log SPDY Sessions.
diff --git a/net/socket/client_socket_pool.cc b/net/socket/client_socket_pool.cc
index 63bf2f8..2bf7964 100644
--- a/net/socket/client_socket_pool.cc
+++ b/net/socket/client_socket_pool.cc
@@ -162,9 +162,9 @@
 }
 
 base::Value ClientSocketPool::NetLogGroupIdParams(const GroupId& group_id) {
-  base::Value event_params(base::Value::Type::DICTIONARY);
-  event_params.SetStringKey("group_id", group_id.ToString());
-  return event_params;
+  base::Value::Dict event_params;
+  event_params.Set("group_id", group_id.ToString());
+  return base::Value(std::move(event_params));
 }
 
 std::unique_ptr<ConnectJob> ClientSocketPool::CreateConnectJob(
diff --git a/net/socket/client_socket_pool.h b/net/socket/client_socket_pool.h
index 7556425d..674f645 100644
--- a/net/socket/client_socket_pool.h
+++ b/net/socket/client_socket_pool.h
@@ -11,6 +11,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/ref_counted.h"
 #include "base/time/time.h"
+#include "base/values.h"
 #include "net/base/completion_once_callback.h"
 #include "net/base/load_states.h"
 #include "net/base/net_export.h"
@@ -26,10 +27,6 @@
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "url/scheme_host_port.h"
 
-namespace base {
-class Value;
-}  // namespace base
-
 namespace net {
 
 class ClientSocketHandle;
diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc
index a0ebbf4..80ff89b5 100644
--- a/net/socket/client_socket_pool_base_unittest.cc
+++ b/net/socket/client_socket_pool_base_unittest.cc
@@ -687,7 +687,8 @@
     ASSERT_EQ(1u, entries.size());
     ASSERT_TRUE(entries[0].HasParams());
     ASSERT_TRUE(entries[0].params.is_dict());
-    const std::string* reason = entries[0].params.FindStringKey("reason");
+    const std::string* reason =
+        entries[0].params.GetDict().FindString("reason");
     ASSERT_TRUE(reason);
     EXPECT_EQ(expected_reason, *reason);
   }
diff --git a/net/socket/client_socket_pool_manager.h b/net/socket/client_socket_pool_manager.h
index 8e4652d..eb21b97 100644
--- a/net/socket/client_socket_pool_manager.h
+++ b/net/socket/client_socket_pool_manager.h
@@ -9,8 +9,7 @@
 #ifndef NET_SOCKET_CLIENT_SOCKET_POOL_MANAGER_H_
 #define NET_SOCKET_CLIENT_SOCKET_POOL_MANAGER_H_
 
-#include <string>
-
+#include "base/values.h"
 #include "net/base/completion_once_callback.h"
 #include "net/base/net_export.h"
 #include "net/base/request_priority.h"
@@ -19,10 +18,6 @@
 #include "net/socket/client_socket_pool.h"
 #include "url/scheme_host_port.h"
 
-namespace base {
-class Value;
-}
-
 namespace net {
 
 class ClientSocketHandle;
@@ -74,7 +69,7 @@
   virtual ClientSocketPool* GetSocketPool(const ProxyServer& proxy_server) = 0;
 
   // Creates a Value summary of the state of the socket pools.
-  virtual std::unique_ptr<base::Value> SocketPoolInfoToValue() const = 0;
+  virtual base::Value SocketPoolInfoToValue() const = 0;
 };
 
 // A helper method that uses the passed in proxy information to initialize a
diff --git a/net/socket/client_socket_pool_manager_impl.cc b/net/socket/client_socket_pool_manager_impl.cc
index a30284e..4ba9a053 100644
--- a/net/socket/client_socket_pool_manager_impl.cc
+++ b/net/socket/client_socket_pool_manager_impl.cc
@@ -94,9 +94,8 @@
   return ret.first->second.get();
 }
 
-std::unique_ptr<base::Value>
-ClientSocketPoolManagerImpl::SocketPoolInfoToValue() const {
-  std::unique_ptr<base::ListValue> list(new base::ListValue());
+base::Value ClientSocketPoolManagerImpl::SocketPoolInfoToValue() const {
+  base::Value::List list;
   for (const auto& socket_pool : socket_pools_) {
     // TODO(menke): Is this really needed?
     const char* type;
@@ -107,11 +106,11 @@
     } else {
       type = "http_proxy_socket_pool";
     }
-    list->Append(socket_pool.second->GetInfoAsValue(
+    list.Append(socket_pool.second->GetInfoAsValue(
         ProxyServerToProxyUri(socket_pool.first), type));
   }
 
-  return std::move(list);
+  return base::Value(std::move(list));
 }
 
 }  // namespace net
diff --git a/net/socket/client_socket_pool_manager_impl.h b/net/socket/client_socket_pool_manager_impl.h
index c85f6b5..925e16c5 100644
--- a/net/socket/client_socket_pool_manager_impl.h
+++ b/net/socket/client_socket_pool_manager_impl.h
@@ -13,6 +13,7 @@
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/threading/thread_checker.h"
+#include "base/values.h"
 #include "net/base/net_export.h"
 #include "net/http/http_network_session.h"
 #include "net/socket/client_socket_pool_manager.h"
@@ -48,7 +49,7 @@
   ClientSocketPool* GetSocketPool(const ProxyServer& proxy_server) override;
 
   // Creates a Value summary of the state of the socket pools.
-  std::unique_ptr<base::Value> SocketPoolInfoToValue() const override;
+  base::Value SocketPoolInfoToValue() const override;
 
  private:
   using SocketPoolMap =
diff --git a/net/socket/mock_client_socket_pool_manager.cc b/net/socket/mock_client_socket_pool_manager.cc
index 49b50b2..23ae107 100644
--- a/net/socket/mock_client_socket_pool_manager.cc
+++ b/net/socket/mock_client_socket_pool_manager.cc
@@ -39,10 +39,9 @@
   return nullptr;
 }
 
-std::unique_ptr<base::Value>
-MockClientSocketPoolManager::SocketPoolInfoToValue() const {
+base::Value MockClientSocketPoolManager::SocketPoolInfoToValue() const {
   NOTIMPLEMENTED();
-  return std::unique_ptr<base::Value>(nullptr);
+  return base::Value();
 }
 
 }  // namespace net
diff --git a/net/socket/mock_client_socket_pool_manager.h b/net/socket/mock_client_socket_pool_manager.h
index d215c0f..967ae19 100644
--- a/net/socket/mock_client_socket_pool_manager.h
+++ b/net/socket/mock_client_socket_pool_manager.h
@@ -36,7 +36,7 @@
                                  const char* net_log_reason_utf8) override;
   void CloseIdleSockets(const char* net_log_reason_utf8) override;
   ClientSocketPool* GetSocketPool(const ProxyServer& proxy_server) override;
-  std::unique_ptr<base::Value> SocketPoolInfoToValue() const override;
+  base::Value SocketPoolInfoToValue() const override;
 
  private:
   using ClientSocketPoolMap =
diff --git a/net/socket/socket_net_log_params.cc b/net/socket/socket_net_log_params.cc
index bbd594d..f2360b1 100644
--- a/net/socket/socket_net_log_params.cc
+++ b/net/socket/socket_net_log_params.cc
@@ -17,10 +17,10 @@
 namespace net {
 
 base::Value NetLogSocketErrorParams(int net_error, int os_error) {
-  base::Value dict(base::Value::Type::DICTIONARY);
-  dict.SetIntKey("net_error", net_error);
-  dict.SetIntKey("os_error", os_error);
-  return dict;
+  base::Value::Dict dict;
+  dict.Set("net_error", net_error);
+  dict.Set("os_error", os_error);
+  return base::Value(std::move(dict));
 }
 
 void NetLogSocketError(const NetLogWithSource& net_log,
@@ -32,24 +32,24 @@
 }
 
 base::Value CreateNetLogHostPortPairParams(const HostPortPair* host_and_port) {
-  base::Value dict(base::Value::Type::DICTIONARY);
-  dict.SetStringKey("host_and_port", host_and_port->ToString());
-  return dict;
+  base::Value::Dict dict;
+  dict.Set("host_and_port", host_and_port->ToString());
+  return base::Value(std::move(dict));
 }
 
 base::Value CreateNetLogIPEndPointParams(const IPEndPoint* address) {
-  base::Value dict(base::Value::Type::DICTIONARY);
-  dict.SetStringKey("address", address->ToString());
-  return dict;
+  base::Value::Dict dict;
+  dict.Set("address", address->ToString());
+  return base::Value(std::move(dict));
 }
 
 base::Value CreateNetLogAddressPairParams(
     const net::IPEndPoint& local_address,
     const net::IPEndPoint& remote_address) {
-  base::Value dict(base::Value::Type::DICTIONARY);
-  dict.SetStringKey("local_address", local_address.ToString());
-  dict.SetStringKey("remote_address", remote_address.ToString());
-  return dict;
+  base::Value::Dict dict;
+  dict.Set("local_address", local_address.ToString());
+  dict.Set("remote_address", remote_address.ToString());
+  return base::Value(std::move(dict));
 }
 
 }  // namespace net
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc
index 9fb3208..9943a21e 100644
--- a/net/socket/ssl_client_socket_impl.cc
+++ b/net/socket/ssl_client_socket_impl.cc
@@ -86,11 +86,11 @@
 
 base::Value NetLogPrivateKeyOperationParams(uint16_t algorithm,
                                             SSLPrivateKey* key) {
-  base::Value value(base::Value::Type::DICTIONARY);
-  value.SetStringKey("algorithm", SSL_get_signature_algorithm_name(
-                                      algorithm, 0 /* exclude curve */));
-  value.SetStringKey("provider", key->GetProviderName());
-  return value;
+  base::Value::Dict dict;
+  dict.Set("algorithm",
+           SSL_get_signature_algorithm_name(algorithm, 0 /* exclude curve */));
+  dict.Set("provider", key->GetProviderName());
+  return base::Value(std::move(dict));
 }
 
 base::Value NetLogSSLInfoParams(SSLClientSocketImpl* socket) {
@@ -98,45 +98,43 @@
   if (!socket->GetSSLInfo(&ssl_info))
     return base::Value();
 
-  base::Value dict(base::Value::Type::DICTIONARY);
+  base::Value::Dict dict;
   const char* version_str;
   SSLVersionToString(&version_str,
                      SSLConnectionStatusToVersion(ssl_info.connection_status));
-  dict.SetStringKey("version", version_str);
-  dict.SetBoolKey("is_resumed",
-                  ssl_info.handshake_type == SSLInfo::HANDSHAKE_RESUME);
-  dict.SetIntKey("cipher_suite",
-                 SSLConnectionStatusToCipherSuite(ssl_info.connection_status));
-  dict.SetIntKey("key_exchange_group", ssl_info.key_exchange_group);
-  dict.SetIntKey("peer_signature_algorithm", ssl_info.peer_signature_algorithm);
-  dict.SetBoolKey("encrypted_client_hello", ssl_info.encrypted_client_hello);
+  dict.Set("version", version_str);
+  dict.Set("is_resumed", ssl_info.handshake_type == SSLInfo::HANDSHAKE_RESUME);
+  dict.Set("cipher_suite",
+           SSLConnectionStatusToCipherSuite(ssl_info.connection_status));
+  dict.Set("key_exchange_group", ssl_info.key_exchange_group);
+  dict.Set("peer_signature_algorithm", ssl_info.peer_signature_algorithm);
+  dict.Set("encrypted_client_hello", ssl_info.encrypted_client_hello);
 
-  dict.SetStringKey("next_proto",
-                    NextProtoToString(socket->GetNegotiatedProtocol()));
+  dict.Set("next_proto", NextProtoToString(socket->GetNegotiatedProtocol()));
 
-  return dict;
+  return base::Value(std::move(dict));
 }
 
 base::Value NetLogSSLAlertParams(const void* bytes, size_t len) {
-  base::Value dict(base::Value::Type::DICTIONARY);
-  dict.SetKey("bytes", NetLogBinaryValue(bytes, len));
-  return dict;
+  base::Value::Dict dict;
+  dict.Set("bytes", NetLogBinaryValue(bytes, len));
+  return base::Value(std::move(dict));
 }
 
 base::Value NetLogSSLMessageParams(bool is_write,
                                    const void* bytes,
                                    size_t len,
                                    NetLogCaptureMode capture_mode) {
-  base::Value dict(base::Value::Type::DICTIONARY);
   if (len == 0) {
     NOTREACHED();
-    return dict;
+    return base::Value();
   }
 
+  base::Value::Dict dict;
   // The handshake message type is the first byte. Include it so elided messages
   // still report their type.
   uint8_t type = reinterpret_cast<const uint8_t*>(bytes)[0];
-  dict.SetIntKey("type", type);
+  dict.Set("type", type);
 
   // Elide client certificate messages unless logging socket bytes. The client
   // certificate does not contain information needed to impersonate the user
@@ -144,10 +142,10 @@
   // information on the user's identity.
   if (!is_write || type != SSL3_MT_CERTIFICATE ||
       NetLogCaptureIncludesSocketBytes(capture_mode)) {
-    dict.SetKey("bytes", NetLogBinaryValue(bytes, len));
+    dict.Set("bytes", NetLogBinaryValue(bytes, len));
   }
 
-  return dict;
+  return base::Value(std::move(dict));
 }
 
 // This enum is used in histograms, so values may not be reused.
@@ -926,9 +924,9 @@
   if (!ssl_config_.ech_config_list.empty()) {
     DCHECK(base::FeatureList::IsEnabled(features::kEncryptedClientHello));
     net_log_.AddEvent(NetLogEventType::SSL_ECH_CONFIG_LIST, [&] {
-      base::Value dict(base::Value::Type::DICTIONARY);
-      dict.SetKey("bytes", NetLogBinaryValue(ssl_config_.ech_config_list));
-      return dict;
+      base::Value::Dict dict;
+      dict.Set("bytes", NetLogBinaryValue(ssl_config_.ech_config_list));
+      return base::Value(std::move(dict));
     });
     if (!SSL_set1_ech_config_list(ssl_.get(),
                                   ssl_config_.ech_config_list.data(),
@@ -1158,9 +1156,9 @@
   }
 
   net_log_.AddEvent(NetLogEventType::SSL_CERTIFICATES_RECEIVED, [&] {
-    base::Value dict(base::Value::Type::DICTIONARY);
-    dict.SetKey("certificates", NetLogX509CertificateList(server_cert_.get()));
-    return dict;
+    base::Value::Dict dict;
+    dict.Set("certificates", NetLogX509CertificateList(server_cert_.get()));
+    return base::Value(std::move(dict));
   });
 
   // If the certificate is bad and has been previously accepted, use
diff --git a/net/socket/ssl_connect_job.cc b/net/socket/ssl_connect_job.cc
index 8528080..af1a435 100644
--- a/net/socket/ssl_connect_job.cc
+++ b/net/socket/ssl_connect_job.cc
@@ -455,9 +455,9 @@
     ech_retry_configs_ = ssl_socket_->GetECHRetryConfigs();
     net_log().AddEvent(
         NetLogEventType::SSL_CONNECT_JOB_RESTART_WITH_ECH_CONFIG_LIST, [&] {
-          base::Value dict(base::Value::Type::DICTIONARY);
-          dict.SetKey("bytes", NetLogBinaryValue(*ech_retry_configs_));
-          return dict;
+          base::Value::Dict dict;
+          dict.Set("bytes", NetLogBinaryValue(*ech_retry_configs_));
+          return base::Value(std::move(dict));
         });
 
     // TODO(https://crbug.com/1091403): Add histograms for how often this
diff --git a/net/socket/transport_client_socket_pool.cc b/net/socket/transport_client_socket_pool.cc
index 915c2b51..5b0471f8 100644
--- a/net/socket/transport_client_socket_pool.cc
+++ b/net/socket/transport_client_socket_pool.cc
@@ -43,10 +43,10 @@
 base::Value NetLogCreateConnectJobParams(
     bool backup_job,
     const ClientSocketPool::GroupId* group_id) {
-  base::Value dict(base::Value::Type::DICTIONARY);
-  dict.SetBoolKey("backup_job", backup_job);
-  dict.SetStringKey("group_id", group_id->ToString());
-  return dict;
+  base::Value::Dict dict;
+  dict.Set("backup_job", backup_job);
+  dict.Set("group_id", group_id->ToString());
+  return base::Value(std::move(dict));
 }
 
 }  // namespace
@@ -689,57 +689,55 @@
     const std::string& name,
     const std::string& type) const {
   // TODO(mmenke): This currently doesn't return bound Requests or ConnectJobs.
-  base::Value dict(base::Value::Type::DICTIONARY);
-  dict.SetStringKey("name", name);
-  dict.SetStringKey("type", type);
-  dict.SetIntKey("handed_out_socket_count", handed_out_socket_count_);
-  dict.SetIntKey("connecting_socket_count", connecting_socket_count_);
-  dict.SetIntKey("idle_socket_count", idle_socket_count_);
-  dict.SetIntKey("max_socket_count", max_sockets_);
-  dict.SetIntKey("max_sockets_per_group", max_sockets_per_group_);
+  base::Value::Dict dict;
+  dict.Set("name", name);
+  dict.Set("type", type);
+  dict.Set("handed_out_socket_count", handed_out_socket_count_);
+  dict.Set("connecting_socket_count", connecting_socket_count_);
+  dict.Set("idle_socket_count", idle_socket_count_);
+  dict.Set("max_socket_count", max_sockets_);
+  dict.Set("max_sockets_per_group", max_sockets_per_group_);
 
   if (group_map_.empty())
-    return dict;
+    return base::Value(std::move(dict));
 
-  base::Value all_groups_dict(base::Value::Type::DICTIONARY);
+  base::Value::Dict all_groups_dict;
   for (const auto& entry : group_map_) {
     const Group* group = entry.second;
-    base::Value group_dict(base::Value::Type::DICTIONARY);
+    base::Value::Dict group_dict;
 
-    group_dict.SetIntKey("pending_request_count",
-                         group->unbound_request_count());
+    group_dict.Set("pending_request_count",
+                   static_cast<int>(group->unbound_request_count()));
     if (group->has_unbound_requests()) {
-      group_dict.SetStringKey(
-          "top_pending_priority",
-          RequestPriorityToString(group->TopPendingPriority()));
+      group_dict.Set("top_pending_priority",
+                     RequestPriorityToString(group->TopPendingPriority()));
     }
 
-    group_dict.SetIntKey("active_socket_count", group->active_socket_count());
+    group_dict.Set("active_socket_count", group->active_socket_count());
 
-    std::vector<base::Value> idle_socket_list;
+    base::Value::List idle_socket_list;
     for (const auto& idle_socket : group->idle_sockets()) {
       int source_id = idle_socket.socket->NetLog().source().id;
-      idle_socket_list.push_back(base::Value(source_id));
+      idle_socket_list.Append(source_id);
     }
-    group_dict.SetKey("idle_sockets", base::Value(std::move(idle_socket_list)));
+    group_dict.Set("idle_sockets", std::move(idle_socket_list));
 
-    std::vector<base::Value> connect_jobs_list;
+    base::Value::List connect_jobs_list;
     for (const auto& job : group->jobs()) {
       int source_id = job->net_log().source().id;
-      connect_jobs_list.push_back(base::Value(source_id));
+      connect_jobs_list.Append(source_id);
     }
-    group_dict.SetKey("connect_jobs",
-                      base::Value(std::move(connect_jobs_list)));
+    group_dict.Set("connect_jobs", std::move(connect_jobs_list));
 
-    group_dict.SetBoolKey("is_stalled", group->CanUseAdditionalSocketSlot(
-                                            max_sockets_per_group_));
-    group_dict.SetBoolKey("backup_job_timer_is_running",
-                          group->BackupJobTimerIsRunning());
+    group_dict.Set("is_stalled",
+                   group->CanUseAdditionalSocketSlot(max_sockets_per_group_));
+    group_dict.Set("backup_job_timer_is_running",
+                   group->BackupJobTimerIsRunning());
 
-    all_groups_dict.SetKey(entry.first.ToString(), std::move(group_dict));
+    all_groups_dict.Set(entry.first.ToString(), std::move(group_dict));
   }
-  dict.SetKey("groups", std::move(all_groups_dict));
-  return dict;
+  dict.Set("groups", std::move(all_groups_dict));
+  return base::Value(std::move(dict));
 }
 
 bool TransportClientSocketPool::IdleSocket::IsUsable(
diff --git a/net/socket/udp_net_log_parameters.cc b/net/socket/udp_net_log_parameters.cc
index b084f01..fa82284d 100644
--- a/net/socket/udp_net_log_parameters.cc
+++ b/net/socket/udp_net_log_parameters.cc
@@ -19,23 +19,23 @@
                                         const char* bytes,
                                         const IPEndPoint* address,
                                         NetLogCaptureMode capture_mode) {
-  base::Value dict(base::Value::Type::DICTIONARY);
-  dict.SetIntKey("byte_count", byte_count);
+  base::Value::Dict dict;
+  dict.Set("byte_count", byte_count);
   if (NetLogCaptureIncludesSocketBytes(capture_mode))
-    dict.SetKey("bytes", NetLogBinaryValue(bytes, byte_count));
+    dict.Set("bytes", NetLogBinaryValue(bytes, byte_count));
   if (address)
-    dict.SetStringKey("address", address->ToString());
-  return dict;
+    dict.Set("address", address->ToString());
+  return base::Value(std::move(dict));
 }
 
 base::Value NetLogUDPConnectParams(
     const IPEndPoint& address,
     NetworkChangeNotifier::NetworkHandle network) {
-  base::Value dict(base::Value::Type::DICTIONARY);
-  dict.SetStringKey("address", address.ToString());
+  base::Value::Dict dict;
+  dict.Set("address", address.ToString());
   if (network != NetworkChangeNotifier::kInvalidNetworkHandle)
-    dict.SetIntKey("bound_to_network", network);
-  return dict;
+    dict.Set("bound_to_network", static_cast<int>(network));
+  return base::Value(std::move(dict));
 }
 
 }  // namespace
diff --git a/net/socket/websocket_transport_client_socket_pool.cc b/net/socket/websocket_transport_client_socket_pool.cc
index efeaf6e..4d77f000 100644
--- a/net/socket/websocket_transport_client_socket_pool.cc
+++ b/net/socket/websocket_transport_client_socket_pool.cc
@@ -238,15 +238,16 @@
 base::Value WebSocketTransportClientSocketPool::GetInfoAsValue(
     const std::string& name,
     const std::string& type) const {
-  base::Value dict(base::Value::Type::DICTIONARY);
-  dict.SetStringKey("name", name);
-  dict.SetStringKey("type", type);
-  dict.SetIntKey("handed_out_socket_count", handed_out_socket_count_);
-  dict.SetIntKey("connecting_socket_count", pending_connects_.size());
-  dict.SetIntKey("idle_socket_count", 0);
-  dict.SetIntKey("max_socket_count", max_sockets_);
-  dict.SetIntKey("max_sockets_per_group", max_sockets_);
-  return dict;
+  base::Value::Dict dict;
+  dict.Set("name", name);
+  dict.Set("type", type);
+  dict.Set("handed_out_socket_count", handed_out_socket_count_);
+  dict.Set("connecting_socket_count",
+           static_cast<int>(pending_connects_.size()));
+  dict.Set("idle_socket_count", 0);
+  dict.Set("max_socket_count", max_sockets_);
+  dict.Set("max_sockets_per_group", max_sockets_);
+  return base::Value(std::move(dict));
 }
 
 bool WebSocketTransportClientSocketPool::IsStalled() const {
diff --git a/services/audio/BUILD.gn b/services/audio/BUILD.gn
index 6a99c91..80db1c46 100644
--- a/services/audio/BUILD.gn
+++ b/services/audio/BUILD.gn
@@ -53,6 +53,8 @@
     "output_stream.h",
     "owning_audio_manager_accessor.cc",
     "owning_audio_manager_accessor.h",
+    "realtime_audio_thread.cc",
+    "realtime_audio_thread.h",
     "reference_output.h",
     "service.cc",
     "service.h",
@@ -170,6 +172,7 @@
     "output_stream_unittest.cc",
     "public/cpp/input_ipc_unittest.cc",
     "public/cpp/output_device_unittest.cc",
+    "realtime_audio_thread_test.cc",
     "service_metrics_unittest.cc",
     "snooper_node_unittest.cc",
     "sync_reader_unittest.cc",
diff --git a/services/audio/processing_audio_fifo.cc b/services/audio/processing_audio_fifo.cc
index 7511df10..61be9735 100644
--- a/services/audio/processing_audio_fifo.cc
+++ b/services/audio/processing_audio_fifo.cc
@@ -81,7 +81,8 @@
     : fifo_size_(fifo_size),
       fifo_(fifo_size_),
       input_params_(input_params),
-      audio_processing_thread_("AudioProcessingThread"),
+      audio_processing_thread_("AudioProcessingThread",
+                               input_params_.GetBufferDuration()),
       processing_callback_(std::move(processing_callback)),
       new_data_captured_(base::WaitableEvent::ResetPolicy::AUTOMATIC),
       stats_reporter_(
diff --git a/services/audio/processing_audio_fifo.h b/services/audio/processing_audio_fifo.h
index 8fc967e..bccd1d9 100644
--- a/services/audio/processing_audio_fifo.h
+++ b/services/audio/processing_audio_fifo.h
@@ -12,8 +12,8 @@
 #include "base/synchronization/lock.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/thread_annotations.h"
-#include "base/threading/thread.h"
 #include "media/base/audio_parameters.h"
+#include "services/audio/realtime_audio_thread.h"
 
 namespace media {
 class AudioBus;
@@ -102,7 +102,7 @@
 
   // Real-time audio processing thread, on which |processing_callback_| is
   // called.
-  base::Thread audio_processing_thread_;
+  RealtimeAudioThread audio_processing_thread_;
 
   // Processes captured audio data. Only run on |audio_processing_thread_|.
   ProcessAudioCallback processing_callback_;
diff --git a/services/audio/realtime_audio_thread.cc b/services/audio/realtime_audio_thread.cc
new file mode 100644
index 0000000..adc9dd7f
--- /dev/null
+++ b/services/audio/realtime_audio_thread.cc
@@ -0,0 +1,22 @@
+// 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.
+
+#include "services/audio/realtime_audio_thread.h"
+
+namespace audio {
+RealtimeAudioThread::RealtimeAudioThread(const std::string& name,
+                                         base::TimeDelta realtime_period)
+    : base::Thread(name), realtime_period_(realtime_period) {}
+
+RealtimeAudioThread::~RealtimeAudioThread() {
+  // As per API contract. See base/threading/thread.h.
+  Stop();
+}
+
+#if BUILDFLAG(IS_APPLE)
+base::TimeDelta RealtimeAudioThread::GetRealtimePeriod() {
+  return realtime_period_;
+}
+#endif
+}  // namespace audio
\ No newline at end of file
diff --git a/services/audio/realtime_audio_thread.h b/services/audio/realtime_audio_thread.h
new file mode 100644
index 0000000..9a59360
--- /dev/null
+++ b/services/audio/realtime_audio_thread.h
@@ -0,0 +1,29 @@
+// 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.
+
+#ifndef SERVICES_AUDIO_REALTIME_AUDIO_THREAD_H_
+#define SERVICES_AUDIO_REALTIME_AUDIO_THREAD_H_
+
+#include "base/threading/thread.h"
+
+namespace audio {
+
+// Simple base::Thread which uses a configurable realtime thread period for Mac.
+class RealtimeAudioThread : public base::Thread {
+ public:
+  RealtimeAudioThread(const std::string& name, base::TimeDelta realtime_period);
+  ~RealtimeAudioThread() override;
+
+#if BUILDFLAG(IS_APPLE)
+  // base::PlatformThread::Delegate override.
+  base::TimeDelta GetRealtimePeriod() override;
+#endif
+
+ private:
+  base::TimeDelta realtime_period_;
+};
+
+}  // namespace audio
+
+#endif  // SERVICES_AUDIO_PROCESSING_AUDIO_FIFO_H_
diff --git a/services/audio/realtime_audio_thread_test.cc b/services/audio/realtime_audio_thread_test.cc
new file mode 100644
index 0000000..23790ca
--- /dev/null
+++ b/services/audio/realtime_audio_thread_test.cc
@@ -0,0 +1,60 @@
+// 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.
+
+#include "services/audio/realtime_audio_thread.h"
+
+#include <cstring>
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/run_loop.h"
+#include "base/test/bind.h"
+#include "media/audio/simple_sources.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace audio {
+
+class RealtimeAudioThreadTest : public testing::Test {
+ public:
+  RealtimeAudioThreadTest() = default;
+  ~RealtimeAudioThreadTest() override = default;
+};
+
+#if BUILDFLAG(IS_APPLE)
+TEST_F(RealtimeAudioThreadTest, GetRealtimePeriod) {
+  constexpr base::TimeDelta kPeriod = base::Milliseconds(123);
+
+  RealtimeAudioThread thread("TestThread", kPeriod);
+
+  EXPECT_EQ(thread.GetRealtimePeriod(), kPeriod);
+}
+#endif
+
+TEST_F(RealtimeAudioThreadTest, StartStop) {
+  constexpr base::TimeDelta kPeriod = base::Milliseconds(123);
+
+  RealtimeAudioThread thread("TestThread", kPeriod);
+
+  base::Thread::Options options;
+  options.timer_slack = base::TIMER_SLACK_NONE;
+  options.priority = base::ThreadPriority::REALTIME_AUDIO;
+  EXPECT_TRUE(thread.StartWithOptions(std::move(options)));
+
+  thread.Stop();
+}
+
+TEST_F(RealtimeAudioThreadTest, StartDestroy) {
+  constexpr base::TimeDelta kPeriod = base::Milliseconds(123);
+
+  RealtimeAudioThread thread("TestThread", kPeriod);
+
+  base::Thread::Options options;
+  options.timer_slack = base::TIMER_SLACK_NONE;
+  options.priority = base::ThreadPriority::REALTIME_AUDIO;
+  EXPECT_TRUE(thread.StartWithOptions(std::move(options)));
+
+  // ~RealtimeAudioThread() will be called without Stop() here.
+}
+
+}  // namespace audio
diff --git a/services/device/hid/hid_device_info.cc b/services/device/hid/hid_device_info.cc
index e9585f2..baf0096 100644
--- a/services/device/hid/hid_device_info.cc
+++ b/services/device/hid/hid_device_info.cc
@@ -70,6 +70,8 @@
       HidBlocklist::kReportTypeOutput, vendor_id, product_id, collections);
   auto protected_feature_report_ids = HidBlocklist::Get().GetProtectedReportIds(
       HidBlocklist::kReportTypeFeature, vendor_id, product_id, collections);
+  auto is_excluded_by_blocklist =
+      HidBlocklist::Get().IsVendorProductBlocked(vendor_id, product_id);
 
   std::vector<uint8_t> report_ids;
   if (has_report_id) {
@@ -89,7 +91,7 @@
       std::move(collections), has_report_id, max_input_report_size,
       max_output_report_size, max_feature_report_size, device_node,
       protected_input_report_ids, protected_output_report_ids,
-      protected_feature_report_ids);
+      protected_feature_report_ids, is_excluded_by_blocklist);
 }
 
 HidDeviceInfo::HidDeviceInfo(HidPlatformDeviceId platform_device_id,
@@ -121,6 +123,8 @@
       HidBlocklist::kReportTypeOutput, vendor_id, product_id, collections);
   auto protected_feature_report_ids = HidBlocklist::Get().GetProtectedReportIds(
       HidBlocklist::kReportTypeFeature, vendor_id, product_id, collections);
+  auto is_excluded_by_blocklist =
+      HidBlocklist::Get().IsVendorProductBlocked(vendor_id, product_id);
 
   device_ = mojom::HidDeviceInfo::New(
       base::GenerateGUID(), physical_device_id, vendor_id, product_id,
@@ -128,7 +132,8 @@
       /*report_descriptor=*/std::vector<uint8_t>{}, std::move(collections),
       has_report_id, max_input_report_size, max_output_report_size,
       max_feature_report_size, /*device_node=*/"", protected_input_report_ids,
-      protected_output_report_ids, protected_feature_report_ids);
+      protected_output_report_ids, protected_feature_report_ids,
+      is_excluded_by_blocklist);
 }
 
 HidDeviceInfo::~HidDeviceInfo() = default;
@@ -178,6 +183,10 @@
       HidBlocklist::Get().GetProtectedReportIds(
           HidBlocklist::kReportTypeFeature, device_->vendor_id,
           device_->product_id, device_->collections);
+
+  device_->is_excluded_by_blocklist =
+      HidBlocklist::Get().IsVendorProductBlocked(device_->vendor_id,
+                                                 device_->product_id);
 }
 
 const mojom::HidCollectionInfo* HidDeviceInfo::FindCollectionWithReport(
diff --git a/services/device/hid/test_util.cc b/services/device/hid/test_util.cc
index 3b8e038..e5526c5 100644
--- a/services/device/hid/test_util.cc
+++ b/services/device/hid/test_util.cc
@@ -44,6 +44,8 @@
   device->protected_feature_report_ids = blocklist.GetProtectedReportIds(
       HidBlocklist::kReportTypeFeature, vendor_id, product_id,
       device->collections);
+  device->is_excluded_by_blocklist =
+      blocklist.IsVendorProductBlocked(vendor_id, product_id);
   return device;
 }
 
diff --git a/services/device/public/cpp/hid/fake_hid_manager.cc b/services/device/public/cpp/hid/fake_hid_manager.cc
index c24d1e93..c6bc3e4 100644
--- a/services/device/public/cpp/hid/fake_hid_manager.cc
+++ b/services/device/public/cpp/hid/fake_hid_manager.cc
@@ -257,6 +257,8 @@
       HidBlocklist::Get().GetProtectedReportIds(
           HidBlocklist::kReportTypeFeature, vendor_id, product_id,
           device->collections);
+  device->is_excluded_by_blocklist =
+      HidBlocklist::Get().IsVendorProductBlocked(vendor_id, product_id);
   AddDevice(device.Clone());
   return device;
 }
diff --git a/services/device/public/cpp/hid/hid_blocklist.cc b/services/device/public/cpp/hid/hid_blocklist.cc
index 191e3f9..f2322e6 100644
--- a/services/device/public/cpp/hid/hid_blocklist.cc
+++ b/services/device/public/cpp/hid/hid_blocklist.cc
@@ -210,42 +210,39 @@
   return *instance;
 }
 
-// static
-bool HidBlocklist::IsDeviceExcluded(const mojom::HidDeviceInfo& device_info) {
-  // A device should only be excluded if all its reports are protected.
-  for (const auto& collection : device_info.collections) {
-    if (device_info.protected_input_report_ids) {
-      for (const auto& report : collection->input_reports) {
-        if (!base::Contains(*device_info.protected_input_report_ids,
-                            report->report_id)) {
-          return false;
-        }
-      }
-    } else if (!collection->input_reports.empty()) {
-      return false;
-    }
-    if (device_info.protected_output_report_ids) {
-      for (const auto& report : collection->output_reports) {
-        if (!base::Contains(*device_info.protected_output_report_ids,
-                            report->report_id)) {
-          return false;
-        }
-      }
-    } else if (!collection->output_reports.empty()) {
-      return false;
-    }
-    if (device_info.protected_feature_report_ids) {
-      for (const auto& report : collection->feature_reports) {
-        if (!base::Contains(*device_info.protected_feature_report_ids,
-                            report->report_id)) {
-          return false;
-        }
-      }
-    } else if (!collection->feature_reports.empty()) {
-      return false;
-    }
+bool HidBlocklist::IsVendorProductBlocked(uint16_t vendor_id,
+                                          uint16_t product_id) {
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisableHidBlocklist)) {
+    return false;
   }
-  return true;
+
+  for (const auto& entry : kStaticEntries) {
+    if (IsVendorProductBlockedByEntry(entry, vendor_id, product_id))
+      return true;
+  }
+  for (const auto& entry : dynamic_entries_) {
+    if (IsVendorProductBlockedByEntry(entry, vendor_id, product_id))
+      return true;
+  }
+  return false;
+}
+
+// static
+bool HidBlocklist::IsVendorProductBlockedByEntry(
+    const HidBlocklist::Entry& entry,
+    uint16_t vendor_id,
+    uint16_t product_id) {
+  // The blocklist `entry` must match on device IDs and nothing else.
+  if (!entry.has_vendor_id || entry.has_usage_page || entry.has_report_id ||
+      entry.report_type != kReportTypeAny) {
+    return false;
+  }
+  // If `product_id` is specified, it must match.
+  if (entry.has_product_id && entry.product_id != product_id)
+    return false;
+  // `vendor_id` must match.
+  return entry.vendor_id == vendor_id;
 }
 
 std::vector<uint8_t> HidBlocklist::GetProtectedReportIds(
diff --git a/services/device/public/cpp/hid/hid_blocklist.h b/services/device/public/cpp/hid/hid_blocklist.h
index c5dbc2e..596e417 100644
--- a/services/device/public/cpp/hid/hid_blocklist.h
+++ b/services/device/public/cpp/hid/hid_blocklist.h
@@ -54,9 +54,13 @@
   // Returns a singleton instance of the blocklist.
   static HidBlocklist& Get();
 
-  // Returns true if a device is excluded from access. A device is excluded if
-  // all of its reports are blocked.
-  static bool IsDeviceExcluded(const device::mojom::HidDeviceInfo& device_info);
+  // Returns true if a device is blocked given the |vendor_id| and |product_id|.
+  bool IsVendorProductBlocked(uint16_t vendor_id, uint16_t product_id);
+
+  // Returns true if |vendor_id| and |product_id| are blocked by an |entry|.
+  static bool IsVendorProductBlockedByEntry(const HidBlocklist::Entry& entry,
+                                            uint16_t vendor_id,
+                                            uint16_t product_id);
 
   // Given the |vendor_id|, |product_id|, and |collections| for a HID device,
   // returns a vector of protected report IDs for reports of type |report_type|.
diff --git a/services/device/public/cpp/hid/hid_blocklist_unittest.cc b/services/device/public/cpp/hid/hid_blocklist_unittest.cc
index 5dd275c..af4edb01 100644
--- a/services/device/public/cpp/hid/hid_blocklist_unittest.cc
+++ b/services/device/public/cpp/hid/hid_blocklist_unittest.cc
@@ -85,6 +85,8 @@
     device->protected_feature_report_ids = blocklist_.GetProtectedReportIds(
         HidBlocklist::kReportTypeFeature, vendor_id, product_id,
         device->collections);
+    device->is_excluded_by_blocklist =
+        blocklist_.IsVendorProductBlocked(vendor_id, product_id);
     return device;
   }
 
@@ -136,6 +138,8 @@
     device->protected_feature_report_ids = blocklist_.GetProtectedReportIds(
         HidBlocklist::kReportTypeFeature, vendor_id, product_id,
         device->collections);
+    device->is_excluded_by_blocklist =
+        blocklist_.IsVendorProductBlocked(vendor_id, product_id);
     return device;
   }
 
@@ -210,12 +214,20 @@
   auto device = CreateTestDeviceWithOneReport(
       kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kTestReportId,
       HidBlocklist::kReportTypeInput);
-  EXPECT_FALSE(HidBlocklist::IsDeviceExcluded(*device));
+  EXPECT_FALSE(device->is_excluded_by_blocklist);
   EXPECT_TRUE(device->protected_input_report_ids->empty());
   EXPECT_TRUE(device->protected_output_report_ids->empty());
   EXPECT_TRUE(device->protected_feature_report_ids->empty());
 }
 
+TEST_F(HidBlocklistTest, UnexcludedDeviceWithNoCollections) {
+  auto device = mojom::HidDeviceInfo::New();
+  device->guid = base::GenerateGUID();
+  device->vendor_id = kTestVendorId;
+  device->product_id = kTestProductId;
+  EXPECT_FALSE(device->is_excluded_by_blocklist);
+}
+
 TEST_F(HidBlocklistTest, VendorRule) {
   // Exclude all devices with matching vendor ID.
   SetDynamicBlocklist("1234:::::");
@@ -224,14 +236,14 @@
   auto device1 = CreateTestDeviceWithOneReport(
       kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kTestReportId,
       HidBlocklist::kReportTypeInput);
-  EXPECT_TRUE(HidBlocklist::IsDeviceExcluded(*device1));
+  EXPECT_TRUE(device1->is_excluded_by_blocklist);
   EXPECT_THAT(*device1->protected_input_report_ids, ElementsAre(kTestReportId));
 
   // A device with a different vendor ID is not excluded.
   auto device2 = CreateTestDeviceWithOneReport(
       kTestVendorId + 1, kTestProductId, kTestUsagePage, kTestUsage,
       kTestReportId, HidBlocklist::kReportTypeInput);
-  EXPECT_FALSE(HidBlocklist::IsDeviceExcluded(*device2));
+  EXPECT_FALSE(device2->is_excluded_by_blocklist);
   EXPECT_TRUE(device2->protected_input_report_ids->empty());
 }
 
@@ -243,14 +255,14 @@
   auto device1 = CreateTestDeviceWithOneReport(
       kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kTestReportId,
       HidBlocklist::kReportTypeInput);
-  EXPECT_TRUE(HidBlocklist::IsDeviceExcluded(*device1));
+  EXPECT_TRUE(device1->is_excluded_by_blocklist);
   EXPECT_THAT(*device1->protected_input_report_ids, ElementsAre(kTestReportId));
 
   // A device with matching vendor ID but different product ID is not excluded.
   auto device2 = CreateTestDeviceWithOneReport(
       kTestVendorId, kTestProductId + 1, kTestUsagePage, kTestUsage,
       kTestReportId, HidBlocklist::kReportTypeInput);
-  EXPECT_FALSE(HidBlocklist::IsDeviceExcluded(*device2));
+  EXPECT_FALSE(device2->is_excluded_by_blocklist);
   EXPECT_TRUE(device2->protected_input_report_ids->empty());
 }
 
@@ -266,7 +278,7 @@
   auto device = CreateTestDeviceWithOneReport(
       kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kTestReportId,
       HidBlocklist::kReportTypeInput);
-  EXPECT_FALSE(HidBlocklist::IsDeviceExcluded(*device));
+  EXPECT_FALSE(device->is_excluded_by_blocklist);
   EXPECT_TRUE(device->protected_input_report_ids->empty());
   EXPECT_TRUE(device->protected_output_report_ids->empty());
   EXPECT_TRUE(device->protected_feature_report_ids->empty());
@@ -280,7 +292,7 @@
   auto device = CreateTestDeviceWithOneReport(
       kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kTestReportId,
       HidBlocklist::kReportTypeInput);
-  EXPECT_FALSE(HidBlocklist::IsDeviceExcluded(*device));
+  EXPECT_FALSE(device->is_excluded_by_blocklist);
   EXPECT_TRUE(device->protected_input_report_ids->empty());
 }
 
@@ -288,18 +300,18 @@
   // Protect reports by the usage page of the top-level collection.
   SetDynamicBlocklist("::ff00:::");
 
-  // A device with matching usage page is excluded.
+  // A device with matching usage page is not excluded.
   auto device1 = CreateTestDeviceWithOneReport(
       kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kTestReportId,
       HidBlocklist::kReportTypeInput);
-  EXPECT_TRUE(HidBlocklist::IsDeviceExcluded(*device1));
+  EXPECT_FALSE(device1->is_excluded_by_blocklist);
   EXPECT_THAT(*device1->protected_input_report_ids, ElementsAre(kTestReportId));
 
   // A device with a different usage page is not excluded.
   auto device2 = CreateTestDeviceWithOneReport(
       kTestVendorId, kTestProductId, kTestUsagePage + 1, kTestUsage,
       kTestReportId, HidBlocklist::kReportTypeInput);
-  EXPECT_FALSE(HidBlocklist::IsDeviceExcluded(*device2));
+  EXPECT_FALSE(device2->is_excluded_by_blocklist);
   EXPECT_TRUE(device2->protected_input_report_ids->empty());
 }
 
@@ -307,18 +319,18 @@
   // Protect reports by the usage page and usage ID of the top-level collection.
   SetDynamicBlocklist("::ff00:0001::");
 
-  // A device with matching usage page is excluded.
+  // A device with matching usage page is not excluded.
   auto device1 = CreateTestDeviceWithOneReport(
       kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kTestReportId,
       HidBlocklist::kReportTypeInput);
-  EXPECT_TRUE(HidBlocklist::IsDeviceExcluded(*device1));
+  EXPECT_FALSE(device1->is_excluded_by_blocklist);
   EXPECT_THAT(*device1->protected_input_report_ids, ElementsAre(kTestReportId));
 
   // A device with a different usage page is not excluded.
   auto device2 = CreateTestDeviceWithOneReport(
       kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage + 1,
       kTestReportId, HidBlocklist::kReportTypeInput);
-  EXPECT_FALSE(HidBlocklist::IsDeviceExcluded(*device2));
+  EXPECT_FALSE(device2->is_excluded_by_blocklist);
   EXPECT_TRUE(device2->protected_input_report_ids->empty());
 }
 
@@ -330,7 +342,7 @@
   auto device = CreateTestDeviceWithOneReport(
       kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kTestReportId,
       HidBlocklist::kReportTypeInput);
-  EXPECT_FALSE(HidBlocklist::IsDeviceExcluded(*device));
+  EXPECT_FALSE(device->is_excluded_by_blocklist);
   EXPECT_TRUE(device->protected_input_report_ids->empty());
 }
 
@@ -338,18 +350,18 @@
   // Protect reports by report ID.
   SetDynamicBlocklist("::::01:");
 
-  // A device with matching report ID is excluded.
+  // A device with matching report ID is not excluded.
   auto device1 = CreateTestDeviceWithOneReport(
       kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kTestReportId,
       HidBlocklist::kReportTypeInput);
-  EXPECT_TRUE(HidBlocklist::IsDeviceExcluded(*device1));
+  EXPECT_FALSE(device1->is_excluded_by_blocklist);
   EXPECT_THAT(*device1->protected_input_report_ids, ElementsAre(kTestReportId));
 
   // A device with a different report ID is not excluded.
   auto device2 = CreateTestDeviceWithOneReport(
       kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage,
       kTestReportId + 1, HidBlocklist::kReportTypeInput);
-  EXPECT_FALSE(HidBlocklist::IsDeviceExcluded(*device2));
+  EXPECT_FALSE(device2->is_excluded_by_blocklist);
   EXPECT_TRUE(device2->protected_input_report_ids->empty());
 }
 
@@ -357,18 +369,18 @@
   // Protect reports from devices that do not use report IDs.
   SetDynamicBlocklist("::::00:");
 
-  // A device that does not use report IDs is excluded.
+  // A device that does not use report IDs is not excluded.
   auto device1 = CreateTestDeviceWithOneReport(
       kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kNoReportId,
       HidBlocklist::kReportTypeInput);
-  EXPECT_TRUE(HidBlocklist::IsDeviceExcluded(*device1));
+  EXPECT_FALSE(device1->is_excluded_by_blocklist);
   EXPECT_THAT(*device1->protected_input_report_ids, ElementsAre(kNoReportId));
 
   // A device that uses report IDs is not excluded.
   auto device2 = CreateTestDeviceWithOneReport(
       kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kTestReportId,
       HidBlocklist::kReportTypeInput);
-  EXPECT_FALSE(HidBlocklist::IsDeviceExcluded(*device2));
+  EXPECT_FALSE(device2->is_excluded_by_blocklist);
   EXPECT_TRUE(device2->protected_input_report_ids->empty());
 }
 
@@ -376,18 +388,18 @@
   // Protect reports by report type.
   SetDynamicBlocklist(":::::I");
 
-  // A device with only an input report is excluded.
+  // A device with only an input report is not excluded.
   auto device1 = CreateTestDeviceWithOneReport(
       kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kTestReportId,
       HidBlocklist::kReportTypeInput);
-  EXPECT_TRUE(HidBlocklist::IsDeviceExcluded(*device1));
+  EXPECT_FALSE(device1->is_excluded_by_blocklist);
   EXPECT_THAT(*device1->protected_input_report_ids, ElementsAre(kTestReportId));
 
   // A device with an output report is not excluded.
   auto device2 = CreateTestDeviceWithOneReport(
       kTestVendorId, kTestProductId, kTestUsagePage, kTestUsage, kTestReportId,
       HidBlocklist::kReportTypeOutput);
-  EXPECT_FALSE(HidBlocklist::IsDeviceExcluded(*device2));
+  EXPECT_FALSE(device2->is_excluded_by_blocklist);
   EXPECT_TRUE(device2->protected_output_report_ids->empty());
 }
 
@@ -400,13 +412,13 @@
   // reports should not be protected.
   auto device =
       CreateTestDeviceWithMultipleCollections(kTestVendorId, kTestProductId, 2);
-  EXPECT_FALSE(HidBlocklist::IsDeviceExcluded(*device));
+  EXPECT_FALSE(device->is_excluded_by_blocklist);
   EXPECT_THAT(*device->protected_input_report_ids, ElementsAre(0x01));
   EXPECT_TRUE(device->protected_output_report_ids->empty());
   EXPECT_TRUE(device->protected_feature_report_ids->empty());
 }
 
-TEST_F(HidBlocklistTest, DeviceWithAllProtectedReportsIsExcluded) {
+TEST_F(HidBlocklistTest, DeviceWithAllProtectedReportsIsNotExcluded) {
   // Protect six reports by report ID and report type.
   SetDynamicBlocklist(
       "::::01:I, ::::02:O, ::::03:F, ::::04:I, ::::05:O, ::::06:F");
@@ -415,13 +427,13 @@
   // reports match the above blocklist rules and should be protected.
   auto device =
       CreateTestDeviceWithMultipleCollections(kTestVendorId, kTestProductId, 2);
-  EXPECT_TRUE(HidBlocklist::IsDeviceExcluded(*device));
+  EXPECT_FALSE(device->is_excluded_by_blocklist);
   EXPECT_THAT(*device->protected_input_report_ids, ElementsAre(0x01, 0x04));
   EXPECT_THAT(*device->protected_output_report_ids, ElementsAre(0x02, 0x05));
   EXPECT_THAT(*device->protected_feature_report_ids, ElementsAre(0x03, 0x06));
 }
 
-TEST_F(HidBlocklistTest, SpecificOutputReportExcluded) {
+TEST_F(HidBlocklistTest, SpecificOutputReportIsProtected) {
   // Block report 0x05 from usage page 0xff00 on devices from vendor 0x0b0e.
   SetDynamicBlocklist("0b0e::ff00::05:O");
 
@@ -432,7 +444,7 @@
       TestReportDescriptors::JabraLink380c());
 
   // Check that only the blocked report is excluded.
-  EXPECT_FALSE(HidBlocklist::IsDeviceExcluded(*device));
+  EXPECT_FALSE(device->is_excluded_by_blocklist);
   EXPECT_TRUE(device->protected_input_report_ids->empty());
   EXPECT_THAT(*device->protected_output_report_ids, ElementsAre(0x05));
   EXPECT_TRUE(device->protected_feature_report_ids->empty());
diff --git a/services/device/public/mojom/hid.mojom b/services/device/public/mojom/hid.mojom
index 2a2dd09f..69846a1 100644
--- a/services/device/public/mojom/hid.mojom
+++ b/services/device/public/mojom/hid.mojom
@@ -347,6 +347,10 @@
   [MinVersion=1] array<uint8>? protected_input_report_ids@14;
   [MinVersion=1] array<uint8>? protected_output_report_ids@15;
   [MinVersion=1] array<uint8>? protected_feature_report_ids@16;
+
+  // True if the device is excluded from access by the HID blocklist. It is
+  // based solely on |vendor_id| and |product_id| information.
+  [MinVersion=3] bool is_excluded_by_blocklist@17;
 };
 
 // A client interface for receiving a notification when HID devices are
diff --git a/services/network/public/cpp/cors/cors.cc b/services/network/public/cpp/cors/cors.cc
index 4a0b703..e349353 100644
--- a/services/network/public/cpp/cors/cors.cc
+++ b/services/network/public/cpp/cors/cors.cc
@@ -11,7 +11,7 @@
 
 #include "base/containers/contains.h"
 #include "base/containers/fixed_flat_set.h"
-#include "base/metrics/histogram_macros.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "net/base/mime_util.h"
@@ -232,14 +232,10 @@
   cors::AccessCheckResult result = error_status
                                        ? cors::AccessCheckResult::kNotPermitted
                                        : cors::AccessCheckResult::kPermitted;
-  UMA_HISTOGRAM_ENUMERATION("Net.Cors.AccessCheckResult", result);
+  base::UmaHistogramEnumeration("Net.Cors.AccessCheckResult", result);
   if (!IsOriginPotentiallyTrustworthy(origin)) {
-    UMA_HISTOGRAM_ENUMERATION("Net.Cors.AccessCheckResult.NotSecureRequestor",
-                              result);
-  }
-  if (error_status) {
-    UMA_HISTOGRAM_ENUMERATION("Net.Cors.AccessCheckError",
-                              error_status->cors_error);
+    base::UmaHistogramEnumeration(
+        "Net.Cors.AccessCheckResult.NotSecureRequestor", result);
   }
   return error_status;
 }
diff --git a/services/network/public/cpp/cors/cors_unittest.cc b/services/network/public/cpp/cors/cors_unittest.cc
index 0d3a083e..4a201c8b 100644
--- a/services/network/public/cpp/cors/cors_unittest.cc
+++ b/services/network/public/cpp/cors/cors_unittest.cc
@@ -158,7 +158,6 @@
 constexpr char kAccessCheckHistogram[] = "Net.Cors.AccessCheckResult";
 constexpr char kAccessCheckHistogramNotSecure[] =
     "Net.Cors.AccessCheckResult.NotSecureRequestor";
-constexpr char kAccessCheckHistogramError[] = "Net.Cors.AccessCheckError";
 
 TEST_F(CorsTest, CheckAccessAndReportMetricsForPermittedSecureOrigin) {
   base::HistogramTester histogram_tester;
@@ -172,7 +171,6 @@
   histogram_tester.ExpectUniqueSample(kAccessCheckHistogram,
                                       AccessCheckResult::kPermitted, 1);
   histogram_tester.ExpectTotalCount(kAccessCheckHistogramNotSecure, 0);
-  histogram_tester.ExpectTotalCount(kAccessCheckHistogramError, 0);
 }
 
 TEST_F(CorsTest, CheckAccessAndReportMetricsForPermittedNotSecureOrigin) {
@@ -188,7 +186,6 @@
                                       AccessCheckResult::kPermitted, 1);
   histogram_tester.ExpectUniqueSample(kAccessCheckHistogramNotSecure,
                                       AccessCheckResult::kPermitted, 1);
-  histogram_tester.ExpectTotalCount(kAccessCheckHistogramError, 0);
 }
 
 TEST_F(CorsTest, CheckAccessAndReportMetricsForNotPermittedSecureOrigin) {
@@ -203,9 +200,6 @@
   histogram_tester.ExpectUniqueSample(kAccessCheckHistogram,
                                       AccessCheckResult::kNotPermitted, 1);
   histogram_tester.ExpectTotalCount(kAccessCheckHistogramNotSecure, 0);
-  histogram_tester.ExpectUniqueSample(
-      kAccessCheckHistogramError, mojom::CorsError::kMissingAllowOriginHeader,
-      1);
 }
 
 TEST_F(CorsTest, SafelistedMethod) {
diff --git a/services/viz/public/cpp/compositing/mojom_traits_unittest.cc b/services/viz/public/cpp/compositing/mojom_traits_unittest.cc
index 0c36ff3..899ac9d4 100644
--- a/services/viz/public/cpp/compositing/mojom_traits_unittest.cc
+++ b/services/viz/public/cpp/compositing/mojom_traits_unittest.cc
@@ -1136,7 +1136,8 @@
       gpu::CommandBufferId::FromUnsafeValue(0xdeadbeef));
   const uint64_t release_count = 0xdeadbeefdeadL;
   const uint32_t texture_target = 1337;
-  const bool read_lock_fences_enabled = true;
+  const TransferableResource::SynchronizationType sync_type =
+      TransferableResource::SynchronizationType::kGpuCommandsCompleted;
   const bool is_software = false;
   const bool is_overlay_candidate = true;
 
@@ -1152,7 +1153,7 @@
   input.filter = filter;
   input.size = size;
   input.mailbox_holder = mailbox_holder;
-  input.read_lock_fences_enabled = read_lock_fences_enabled;
+  input.synchronization_type = sync_type;
   input.is_software = is_software;
   input.is_overlay_candidate = is_overlay_candidate;
 
@@ -1168,7 +1169,7 @@
   EXPECT_EQ(mailbox_holder.sync_token, output.mailbox_holder.sync_token);
   EXPECT_EQ(mailbox_holder.texture_target,
             output.mailbox_holder.texture_target);
-  EXPECT_EQ(read_lock_fences_enabled, output.read_lock_fences_enabled);
+  EXPECT_EQ(sync_type, output.synchronization_type);
   EXPECT_EQ(is_software, output.is_software);
   EXPECT_EQ(is_overlay_candidate, output.is_overlay_candidate);
 }
diff --git a/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.cc b/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.cc
index 40a15ae..ea12da0e 100644
--- a/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.cc
+++ b/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.cc
@@ -16,6 +16,38 @@
 namespace mojo {
 
 // static
+viz::mojom::SynchronizationType
+EnumTraits<viz::mojom::SynchronizationType,
+           viz::TransferableResource::SynchronizationType>::
+    ToMojom(viz::TransferableResource::SynchronizationType type) {
+  switch (type) {
+    case viz::TransferableResource::SynchronizationType::kSyncToken:
+      return viz::mojom::SynchronizationType::kSyncToken;
+    case viz::TransferableResource::SynchronizationType::kGpuCommandsCompleted:
+      return viz::mojom::SynchronizationType::kGpuCommandsCompleted;
+  }
+  NOTREACHED();
+  return viz::mojom::SynchronizationType::kSyncToken;
+}
+
+// static
+bool EnumTraits<viz::mojom::SynchronizationType,
+                viz::TransferableResource::SynchronizationType>::
+    FromMojom(viz::mojom::SynchronizationType input,
+              viz::TransferableResource::SynchronizationType* out) {
+  switch (input) {
+    case viz::mojom::SynchronizationType::kSyncToken:
+      *out = viz::TransferableResource::SynchronizationType::kSyncToken;
+      return true;
+    case viz::mojom::SynchronizationType::kGpuCommandsCompleted:
+      *out =
+          viz::TransferableResource::SynchronizationType::kGpuCommandsCompleted;
+      return true;
+  }
+  return false;
+}
+
+// static
 bool StructTraits<viz::mojom::TransferableResourceDataView,
                   viz::TransferableResource>::
     Read(viz::mojom::TransferableResourceDataView data,
@@ -25,12 +57,12 @@
       !data.ReadMailboxHolder(&out->mailbox_holder) ||
       !data.ReadColorSpace(&out->color_space) ||
       !data.ReadHdrMetadata(&out->hdr_metadata) ||
-      !data.ReadYcbcrInfo(&out->ycbcr_info) || !data.ReadId(&id)) {
+      !data.ReadYcbcrInfo(&out->ycbcr_info) || !data.ReadId(&id) ||
+      !data.ReadSynchronizationType(&out->synchronization_type)) {
     return false;
   }
   out->id = id;
   out->filter = data.filter();
-  out->read_lock_fences_enabled = data.read_lock_fences_enabled();
   out->is_software = data.is_software();
   out->is_overlay_candidate = data.is_overlay_candidate();
 
diff --git a/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.h b/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.h
index ff137ab..53db0661 100644
--- a/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.h
+++ b/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.h
@@ -19,6 +19,16 @@
 namespace mojo {
 
 template <>
+struct EnumTraits<viz::mojom::SynchronizationType,
+                  viz::TransferableResource::SynchronizationType> {
+  static viz::mojom::SynchronizationType ToMojom(
+      viz::TransferableResource::SynchronizationType type);
+
+  static bool FromMojom(viz::mojom::SynchronizationType input,
+                        viz::TransferableResource::SynchronizationType* out);
+};
+
+template <>
 struct StructTraits<viz::mojom::TransferableResourceDataView,
                     viz::TransferableResource> {
   static const viz::ResourceId& id(const viz::TransferableResource& resource) {
@@ -42,9 +52,9 @@
     return resource.mailbox_holder;
   }
 
-  static bool read_lock_fences_enabled(
+  static viz::TransferableResource::SynchronizationType synchronization_type(
       const viz::TransferableResource& resource) {
-    return resource.read_lock_fences_enabled;
+    return resource.synchronization_type;
   }
 
   static bool is_software(const viz::TransferableResource& resource) {
diff --git a/services/viz/public/mojom/compositing/transferable_resource.mojom b/services/viz/public/mojom/compositing/transferable_resource.mojom
index 6d95a59..b4c970b08 100644
--- a/services/viz/public/mojom/compositing/transferable_resource.mojom
+++ b/services/viz/public/mojom/compositing/transferable_resource.mojom
@@ -13,6 +13,13 @@
 import "ui/gfx/mojom/color_space.mojom";
 import "ui/gfx/mojom/hdr_metadata.mojom";
 
+// See viz::TransferableResource::SynchronizationType in
+// components/viz/common/resources/transferable_resource.h
+enum SynchronizationType {
+  kSyncToken,
+  kGpuCommandsCompleted,
+};
+
 // See components/viz/common/resources/transferable_resource.h.
 struct TransferableResource {
   ResourceId id;
@@ -20,7 +27,7 @@
   uint32 filter;
   gfx.mojom.Size size;
   gpu.mojom.MailboxHolder mailbox_holder;
-  bool read_lock_fences_enabled;
+  SynchronizationType synchronization_type;
   bool is_software;
   bool is_overlay_candidate;
   bool is_backed_by_surface_texture;
diff --git a/testing/buildbot/chrome.json b/testing/buildbot/chrome.json
index f2691de5..badceb4a5 100644
--- a/testing/buildbot/chrome.json
+++ b/testing/buildbot/chrome.json
@@ -175,10 +175,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -213,10 +209,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -255,10 +247,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -293,10 +281,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -412,10 +396,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -491,10 +471,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -529,10 +505,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -567,10 +539,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -605,10 +573,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -643,10 +607,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -684,10 +644,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -722,10 +678,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -760,10 +712,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -802,10 +750,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -856,10 +800,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -897,10 +837,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -935,10 +871,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -973,10 +905,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1015,10 +943,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1053,10 +977,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1091,10 +1011,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1145,10 +1061,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1291,10 +1203,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1385,10 +1293,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1550,10 +1454,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1586,10 +1486,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2200,10 +2096,6 @@
         "cros_board": "hana",
         "cros_img": "hana-release/R104-14844.0.0",
         "name": "ozone_unittests HANA_RELEASE_LKGM",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {},
         "test": "ozone_unittests",
         "test_id_prefix": "ninja://ui/ozone:ozone_unittests/",
@@ -2217,10 +2109,6 @@
         "cros_board": "hana",
         "cros_img": "hana-release/R103-14816.17.0",
         "name": "ozone_unittests HANA_RELEASE_DEV",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {},
         "test": "ozone_unittests",
         "test_id_prefix": "ninja://ui/ozone:ozone_unittests/",
@@ -2234,10 +2122,6 @@
         "cros_board": "hana",
         "cros_img": "hana-release/R103-14816.25.0",
         "name": "ozone_unittests HANA_RELEASE_BETA",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {},
         "test": "ozone_unittests",
         "test_id_prefix": "ninja://ui/ozone:ozone_unittests/",
@@ -2251,10 +2135,6 @@
         "cros_board": "hana",
         "cros_img": "hana-release/R102-14695.85.0",
         "name": "ozone_unittests HANA_RELEASE_STABLE",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {},
         "test": "ozone_unittests",
         "test_id_prefix": "ninja://ui/ozone:ozone_unittests/",
@@ -2268,10 +2148,6 @@
         "cros_board": "jacuzzi",
         "cros_img": "jacuzzi-release/R104-14844.0.0",
         "name": "ozone_unittests JACUZZI_RELEASE_LKGM",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {},
         "test": "ozone_unittests",
         "test_id_prefix": "ninja://ui/ozone:ozone_unittests/",
@@ -2285,10 +2161,6 @@
         "cros_board": "jacuzzi",
         "cros_img": "jacuzzi-release/R103-14816.17.0",
         "name": "ozone_unittests JACUZZI_RELEASE_DEV",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {},
         "test": "ozone_unittests",
         "test_id_prefix": "ninja://ui/ozone:ozone_unittests/",
@@ -2302,10 +2174,6 @@
         "cros_board": "jacuzzi",
         "cros_img": "jacuzzi-release/R103-14816.25.0",
         "name": "ozone_unittests JACUZZI_RELEASE_BETA",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {},
         "test": "ozone_unittests",
         "test_id_prefix": "ninja://ui/ozone:ozone_unittests/",
@@ -2319,10 +2187,6 @@
         "cros_board": "hana",
         "cros_img": "hana-release/R104-14844.0.0",
         "name": "viz_unittests HANA_RELEASE_LKGM",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {},
         "test": "viz_unittests",
         "test_id_prefix": "ninja://components/viz:viz_unittests/",
@@ -2336,10 +2200,6 @@
         "cros_board": "hana",
         "cros_img": "hana-release/R103-14816.17.0",
         "name": "viz_unittests HANA_RELEASE_DEV",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {},
         "test": "viz_unittests",
         "test_id_prefix": "ninja://components/viz:viz_unittests/",
@@ -2353,10 +2213,6 @@
         "cros_board": "hana",
         "cros_img": "hana-release/R103-14816.25.0",
         "name": "viz_unittests HANA_RELEASE_BETA",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {},
         "test": "viz_unittests",
         "test_id_prefix": "ninja://components/viz:viz_unittests/",
@@ -2370,10 +2226,6 @@
         "cros_board": "hana",
         "cros_img": "hana-release/R102-14695.85.0",
         "name": "viz_unittests HANA_RELEASE_STABLE",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {},
         "test": "viz_unittests",
         "test_id_prefix": "ninja://components/viz:viz_unittests/",
@@ -2387,10 +2239,6 @@
         "cros_board": "jacuzzi",
         "cros_img": "jacuzzi-release/R104-14844.0.0",
         "name": "viz_unittests JACUZZI_RELEASE_LKGM",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {},
         "test": "viz_unittests",
         "test_id_prefix": "ninja://components/viz:viz_unittests/",
@@ -2404,10 +2252,6 @@
         "cros_board": "jacuzzi",
         "cros_img": "jacuzzi-release/R103-14816.17.0",
         "name": "viz_unittests JACUZZI_RELEASE_DEV",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {},
         "test": "viz_unittests",
         "test_id_prefix": "ninja://components/viz:viz_unittests/",
@@ -2421,10 +2265,6 @@
         "cros_board": "jacuzzi",
         "cros_img": "jacuzzi-release/R103-14816.25.0",
         "name": "viz_unittests JACUZZI_RELEASE_BETA",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {},
         "test": "viz_unittests",
         "test_id_prefix": "ninja://components/viz:viz_unittests/",
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index 406a8f6e..7c7daef 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -8274,7 +8274,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M102",
-              "revision": "version:102.0.5005.91"
+              "revision": "version:102.0.5005.92"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -8325,15 +8325,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
-          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
-          "--client-outdir",
-          "../../weblayer_instrumentation_test_M103/out/Release",
           "--implementation-outdir",
           ".",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--webview-apk-path=apks/SystemWebView.apk",
+          "--client-outdir",
+          "../../weblayer_instrumentation_test_M103/out/Release",
           "--client-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -8359,7 +8359,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M103",
-              "revision": "version:103.0.5060.32"
+              "revision": "version:103.0.5060.33"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -8784,7 +8784,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M102",
-              "revision": "version:102.0.5005.91"
+              "revision": "version:102.0.5005.92"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -8835,15 +8835,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
-          "--webview-apk-path=apks/AOSP_SystemWebView.apk",
           "--test-runner-outdir",
           ".",
           "--client-outdir",
           ".",
-          "--implementation-outdir",
-          "../../weblayer_instrumentation_test_M103/out/Release",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--webview-apk-path=apks/AOSP_SystemWebView.apk",
+          "--implementation-outdir",
+          "../../weblayer_instrumentation_test_M103/out/Release",
           "--impl-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -8869,7 +8869,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M103",
-              "revision": "version:103.0.5060.32"
+              "revision": "version:103.0.5060.33"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 3394c5c..9d2f18b 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -46248,7 +46248,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M102",
-              "revision": "version:102.0.5005.91"
+              "revision": "version:102.0.5005.92"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -46299,15 +46299,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
-          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
-          "--client-outdir",
-          "../../weblayer_instrumentation_test_M103/out/Release",
           "--implementation-outdir",
           ".",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--webview-apk-path=apks/SystemWebView.apk",
+          "--client-outdir",
+          "../../weblayer_instrumentation_test_M103/out/Release",
           "--client-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -46333,7 +46333,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M103",
-              "revision": "version:103.0.5060.32"
+              "revision": "version:103.0.5060.33"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -46758,7 +46758,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M102",
-              "revision": "version:102.0.5005.91"
+              "revision": "version:102.0.5005.92"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -46809,15 +46809,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
-          "--webview-apk-path=apks/AOSP_SystemWebView.apk",
           "--test-runner-outdir",
           ".",
           "--client-outdir",
           ".",
-          "--implementation-outdir",
-          "../../weblayer_instrumentation_test_M103/out/Release",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--webview-apk-path=apks/AOSP_SystemWebView.apk",
+          "--implementation-outdir",
+          "../../weblayer_instrumentation_test_M103/out/Release",
           "--impl-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -46843,7 +46843,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M103",
-              "revision": "version:103.0.5060.32"
+              "revision": "version:103.0.5060.33"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -47272,7 +47272,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M102",
-              "revision": "version:102.0.5005.91"
+              "revision": "version:102.0.5005.92"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -47323,15 +47323,15 @@
       {
         "args": [
           "--additional-apk=apks/ChromePublic.apk",
-          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
-          "--client-outdir",
-          "../../weblayer_instrumentation_test_M103/out/Release",
           "--implementation-outdir",
           ".",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--webview-apk-path=apks/SystemWebView.apk",
+          "--client-outdir",
+          "../../weblayer_instrumentation_test_M103/out/Release",
           "--client-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -47357,7 +47357,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M103",
-              "revision": "version:103.0.5060.32"
+              "revision": "version:103.0.5060.33"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -47782,7 +47782,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M102",
-              "revision": "version:102.0.5005.91"
+              "revision": "version:102.0.5005.92"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -47833,15 +47833,15 @@
       {
         "args": [
           "--additional-apk=apks/ChromePublic.apk",
-          "--webview-apk-path=apks/AOSP_SystemWebView.apk",
           "--test-runner-outdir",
           ".",
           "--client-outdir",
           ".",
-          "--implementation-outdir",
-          "../../weblayer_instrumentation_test_M103/out/Release",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--webview-apk-path=apks/AOSP_SystemWebView.apk",
+          "--implementation-outdir",
+          "../../weblayer_instrumentation_test_M103/out/Release",
           "--impl-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -47867,7 +47867,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M103",
-              "revision": "version:103.0.5060.32"
+              "revision": "version:103.0.5060.33"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -48364,7 +48364,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M102",
-              "revision": "version:102.0.5005.91"
+              "revision": "version:102.0.5005.92"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -48415,15 +48415,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
-          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
-          "--client-outdir",
-          "../../weblayer_instrumentation_test_M103/out/Release",
           "--implementation-outdir",
           ".",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--webview-apk-path=apks/SystemWebView.apk",
+          "--client-outdir",
+          "../../weblayer_instrumentation_test_M103/out/Release",
           "--client-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -48449,7 +48449,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M103",
-              "revision": "version:103.0.5060.32"
+              "revision": "version:103.0.5060.33"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -48874,7 +48874,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M102",
-              "revision": "version:102.0.5005.91"
+              "revision": "version:102.0.5005.92"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -48925,15 +48925,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
-          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
           "--client-outdir",
           ".",
-          "--implementation-outdir",
-          "../../weblayer_instrumentation_test_M103/out/Release",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--webview-apk-path=apks/SystemWebView.apk",
+          "--implementation-outdir",
+          "../../weblayer_instrumentation_test_M103/out/Release",
           "--impl-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -48959,7 +48959,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M103",
-              "revision": "version:103.0.5060.32"
+              "revision": "version:103.0.5060.33"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -49456,7 +49456,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M102",
-              "revision": "version:102.0.5005.91"
+              "revision": "version:102.0.5005.92"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -49507,15 +49507,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
-          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
-          "--client-outdir",
-          "../../weblayer_instrumentation_test_M103/out/Release",
           "--implementation-outdir",
           ".",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--webview-apk-path=apks/SystemWebView.apk",
+          "--client-outdir",
+          "../../weblayer_instrumentation_test_M103/out/Release",
           "--client-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -49541,7 +49541,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M103",
-              "revision": "version:103.0.5060.32"
+              "revision": "version:103.0.5060.33"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -49966,7 +49966,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M102",
-              "revision": "version:102.0.5005.91"
+              "revision": "version:102.0.5005.92"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -50017,15 +50017,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
-          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
           "--client-outdir",
           ".",
-          "--implementation-outdir",
-          "../../weblayer_instrumentation_test_M103/out/Release",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--webview-apk-path=apks/SystemWebView.apk",
+          "--implementation-outdir",
+          "../../weblayer_instrumentation_test_M103/out/Release",
           "--impl-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -50051,7 +50051,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M103",
-              "revision": "version:103.0.5060.32"
+              "revision": "version:103.0.5060.33"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 4354317..594dc58 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -66,10 +66,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -103,10 +99,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -144,10 +136,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -181,10 +169,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -299,10 +283,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -376,10 +356,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -413,10 +389,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -450,10 +422,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -487,10 +455,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -524,10 +488,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -564,10 +524,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -601,10 +557,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -638,10 +590,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -679,10 +627,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -733,10 +677,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -770,10 +710,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -807,10 +743,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -844,10 +776,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -885,10 +813,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -922,10 +846,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -959,10 +879,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1012,10 +928,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1274,10 +1186,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1383,10 +1291,6 @@
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
         "name": "base_unittests amd64-generic",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1412,10 +1316,6 @@
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
         "name": "cc_unittests amd64-generic",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1441,10 +1341,6 @@
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
         "name": "cc_unittests eve",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1534,10 +1430,6 @@
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
         "name": "ozone_unittests amd64-generic",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1563,10 +1455,6 @@
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
         "name": "ozone_unittests eve",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 0401d1e..9d4ca2b0 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -17434,10 +17434,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17471,10 +17467,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17512,10 +17504,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17549,10 +17537,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17665,10 +17649,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17742,10 +17722,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17779,10 +17755,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17816,10 +17788,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17853,10 +17821,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17890,10 +17854,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17930,10 +17890,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17967,10 +17923,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18004,10 +17956,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18045,10 +17993,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -18098,10 +18042,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18135,10 +18075,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18172,10 +18108,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18209,10 +18141,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18250,10 +18178,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18287,10 +18211,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18324,10 +18244,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18377,10 +18293,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18675,10 +18587,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18712,10 +18620,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18753,10 +18657,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18790,10 +18690,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18906,10 +18802,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18983,10 +18875,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -19020,10 +18908,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -19057,10 +18941,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -19094,10 +18974,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -19131,10 +19007,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -19171,10 +19043,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -19208,10 +19076,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -19245,10 +19109,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -19286,10 +19146,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -19339,10 +19195,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -19376,10 +19228,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -19413,10 +19261,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -19450,10 +19294,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -19491,10 +19331,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -19528,10 +19364,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -19565,10 +19397,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -19618,10 +19446,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -76533,10 +76357,6 @@
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
         "name": "aura_unittests amd64-generic",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -76562,10 +76382,6 @@
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
         "name": "aura_unittests eve",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -76593,10 +76409,6 @@
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
         "name": "cc_unittests amd64-generic",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -76622,10 +76434,6 @@
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
         "name": "cc_unittests eve",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -76777,10 +76585,6 @@
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
         "name": "ozone_unittests amd64-generic",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -76806,10 +76610,6 @@
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
         "name": "ozone_unittests eve",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
diff --git a/testing/buildbot/internal.chromeos.fyi.json b/testing/buildbot/internal.chromeos.fyi.json
index aa5bf20..046e57d 100644
--- a/testing/buildbot/internal.chromeos.fyi.json
+++ b/testing/buildbot/internal.chromeos.fyi.json
@@ -14,10 +14,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -52,10 +48,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -94,10 +86,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -132,10 +120,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -251,10 +235,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -330,10 +310,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -368,10 +344,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -406,10 +378,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -444,10 +412,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -482,10 +446,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -523,10 +483,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -561,10 +517,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -599,10 +551,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -641,10 +589,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
@@ -695,10 +639,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -736,10 +676,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -774,10 +710,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -812,10 +744,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -854,10 +782,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -892,10 +816,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -930,10 +850,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -984,10 +900,6 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 207b902..3b6f6a4 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -610,9 +610,9 @@
         'swarming': {
           'idempotent': False,  # https://crbug.com/923426#c27
         },
-        'resultdb': {
-          'enable': True,
-        },
+        'mixins': [
+          'has_native_resultdb_integration',
+        ],
         'experiment_percentage': 100,
       },
     },
@@ -625,9 +625,9 @@
           'io_timeout': 3600,
           'shards': 7,
         },
-        'resultdb': {
-          'enable': True,
-        },
+        'mixins': [
+          'has_native_resultdb_integration',
+        ],
       },
       'disk_usage_tast_test': {
         "args": [
@@ -640,6 +640,9 @@
         'swarming': {
           'idempotent': False,  # https://crbug.com/923426#c27
         },
+        'mixins': [
+          'has_native_resultdb_integration',
+        ],
       },
     },
 
@@ -673,6 +676,9 @@
           'idempotent': False,  # https://crbug.com/549140
           'shards': 6,
         },
+        'mixins': [
+          'has_native_resultdb_integration',
+        ],
       },
       'skia_renderer_telemetry_unittests': {
         'isolate_name': 'telemetry_unittests',
@@ -690,6 +696,9 @@
           'idempotent': False,  # https://crbug.com/549140
           'shards': 24,
         },
+        'mixins': [
+          'has_native_resultdb_integration',
+        ],
       },
       'telemetry_perf_unittests': {
         'args': [
@@ -705,9 +714,9 @@
           'idempotent': False,  # https://crbug.com/549140
           'shards': 12,
         },
-        'resultdb': {
-          'enable': True,
-        },
+        'mixins': [
+          'has_native_resultdb_integration',
+        ],
       },
       'telemetry_unittests': {
         'args': [
@@ -723,9 +732,9 @@
           'idempotent': False,  # https://crbug.com/549140
           'shards': 24,
         },
-        'resultdb': {
-          'enable': True,
-        },
+        'mixins': [
+          'has_native_resultdb_integration',
+        ],
       },
     },
 
@@ -740,9 +749,9 @@
           'idempotent': False,  # https://crbug.com/549140
           'shards': 2,
         },
-        'resultdb': {
-          'enable': True,
-        },
+        'mixins': [
+          'has_native_resultdb_integration',
+        ],
       },
       'telemetry_unittests': {
         'args': [
@@ -754,9 +763,9 @@
           'idempotent': False,  # https://crbug.com/549140
           'shards': 10,
         },
-        'resultdb': {
-          'enable': True,
-        },
+        'mixins': [
+          'has_native_resultdb_integration',
+        ],
       },
     },
 
@@ -3980,9 +3989,9 @@
         'swarming': {
           'idempotent': False,  # https://crbug.com/923426#c27
         },
-        'resultdb': {
-          'enable': True,
-        },
+        'mixins': [
+          'has_native_resultdb_integration',
+        ],
       },
     },
 
@@ -3991,9 +4000,9 @@
         'swarming': {
           'idempotent': False,  # https://crbug.com/923426#c27
         },
-        'resultdb': {
-          'enable': True,
-        },
+        'mixins': [
+          'has_native_resultdb_integration',
+        ],
       },
     },
 
@@ -4010,9 +4019,9 @@
         'swarming': {
           'idempotent': False,  # https://crbug.com/923426#c27
         },
-        'resultdb': {
-          'enable': True,
-        },
+        'mixins': [
+          'has_native_resultdb_integration',
+        ],
       },
     },
 
@@ -4023,6 +4032,9 @@
       'lacros_all_tast_tests': {
         'tast_expr': '("group:mainline" && "dep:lacros" && !informational)',
         'timeout_sec': 10800,
+        'mixins': [
+          'has_native_resultdb_integration',
+        ],
       },
       'ozone_unittests': {
         'timeout_sec': 3600,
@@ -4068,6 +4080,9 @@
       'lacros_all_tast_tests': {
         'tast_expr': '("group:mainline" && "dep:lacros" && !informational)',
         'timeout_sec': 10800,
+        'mixins': [
+          'has_native_resultdb_integration',
+        ],
       },
     },
 
@@ -4076,9 +4091,9 @@
         'swarming': {
           'idempotent': False,  # https://crbug.com/923426#c27
         },
-        'resultdb': {
-          'enable': True,
-        },
+        'mixins': [
+          'has_native_resultdb_integration',
+        ],
         'experiment_percentage': 100,
       },
     },
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index cae8886f..377c7c57 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -462,16 +462,16 @@
   },
   'WEBLAYER_10_AND_M_IMPL_SKEW_TESTS_NTH_MILESTONE': {
     'args': [
-      '--webview-apk-path=apks/AOSP_SystemWebView.apk',
       '--test-runner-outdir',
       '.',
       '--client-outdir',
       '.',
-      '--implementation-outdir',
-      '../../weblayer_instrumentation_test_M103/out/Release',
       '--test-expectations',
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
-      '--impl-version=103',
+      '--webview-apk-path=apks/AOSP_SystemWebView.apk',
+      '--implementation-outdir',
+      '../../weblayer_instrumentation_test_M103/out/Release',
+      '--impl-version=103'
     ],
     'identifier': 'with_impl_from_103',
     'swarming': {
@@ -479,10 +479,10 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M103',
-          'revision': 'version:103.0.5060.32',
+          'revision': 'version:103.0.5060.33'
         }
-      ],
-    },
+      ]
+    }
   },
   'WEBLAYER_10_AND_M_IMPL_SKEW_TESTS_NTH_MINUS_ONE_MILESTONE': {
     'args': [
@@ -503,7 +503,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M102',
-          'revision': 'version:102.0.5005.91'
+          'revision': 'version:102.0.5005.92'
         }
       ]
     }
@@ -606,16 +606,16 @@
   },
   'WEBLAYER_IMPL_SKEW_TESTS_NTH_MILESTONE': {
     'args': [
-      '--webview-apk-path=apks/SystemWebView.apk',
       '--test-runner-outdir',
       '.',
       '--client-outdir',
       '.',
-      '--implementation-outdir',
-      '../../weblayer_instrumentation_test_M103/out/Release',
       '--test-expectations',
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
-      '--impl-version=103',
+      '--webview-apk-path=apks/SystemWebView.apk',
+      '--implementation-outdir',
+      '../../weblayer_instrumentation_test_M103/out/Release',
+      '--impl-version=103'
     ],
     'identifier': 'with_impl_from_103',
     'swarming': {
@@ -623,10 +623,10 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M103',
-          'revision': 'version:103.0.5060.32',
+          'revision': 'version:103.0.5060.33'
         }
-      ],
-    },
+      ]
+    }
   },
   'WEBLAYER_IMPL_SKEW_TESTS_NTH_MINUS_ONE_MILESTONE': {
     'args': [
@@ -647,7 +647,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M102',
-          'revision': 'version:102.0.5005.91'
+          'revision': 'version:102.0.5005.92'
         }
       ]
     }
@@ -750,16 +750,16 @@
   },
   'WEBLAYER_CLIENT_SKEW_TESTS_NTH_MILESTONE': {
     'args': [
-      '--webview-apk-path=apks/SystemWebView.apk',
       '--test-runner-outdir',
       '.',
-      '--client-outdir',
-      '../../weblayer_instrumentation_test_M103/out/Release',
       '--implementation-outdir',
       '.',
       '--test-expectations',
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
-      '--client-version=103',
+      '--webview-apk-path=apks/SystemWebView.apk',
+      '--client-outdir',
+      '../../weblayer_instrumentation_test_M103/out/Release',
+      '--client-version=103'
     ],
     'identifier': 'with_client_from_103',
     'swarming': {
@@ -767,10 +767,10 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M103',
-          'revision': 'version:103.0.5060.32',
+          'revision': 'version:103.0.5060.33'
         }
-      ],
-    },
+      ]
+    }
   },
   'WEBLAYER_CLIENT_SKEW_TESTS_NTH_MINUS_ONE_MILESTONE': {
     'args': [
@@ -791,7 +791,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M102',
-          'revision': 'version:102.0.5005.91'
+          'revision': 'version:102.0.5005.92'
         }
       ]
     }
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 68e2a04..0f239809 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -27,9 +27,6 @@
         'additional_compile_targets': [
           'chromiumos_preflight',
         ],
-        'mixins': [
-          'has_native_resultdb_integration',
-        ],
         'test_suites': {
           'gtest_tests': 'chromeos_browser_integration_tests',
         },
@@ -64,7 +61,6 @@
         },
         'mixins': [
           'chromeos-betty',
-          'has_native_resultdb_integration',
         ],
       },
       'chromeos-betty-pi-arc-chrome': {
@@ -73,7 +69,6 @@
         ],
         'mixins': [
           'chromeos-betty',
-          'has_native_resultdb_integration',
         ],
         'test_suites': {
           'gtest_tests': 'chromeos_vm_gtests',
@@ -84,9 +79,6 @@
         'additional_compile_targets': [
           'chromiumos_preflight',
         ],
-        'mixins': [
-          'has_native_resultdb_integration',
-        ],
         'test_suites': {
           'gtest_tests': 'chromeos_device_gtests',
         },
@@ -105,9 +97,6 @@
         'additional_compile_targets': [
           'chromiumos_preflight',
         ],
-        'mixins': [
-          'has_native_resultdb_integration',
-        ],
         'test_suites': {
           'gtest_tests': 'chromeos_device_gtests',
           'isolated_scripts': 'chromeos_remote_device_isolated_tests',
@@ -127,9 +116,6 @@
         'additional_compile_targets': [
           'chromiumos_preflight',
         ],
-        'mixins': [
-          'has_native_resultdb_integration',
-        ],
         'test_suites': {
           'gtest_tests': 'chromeos_device_only_gtests',
         },
@@ -148,9 +134,6 @@
         'additional_compile_targets': [
           'chromiumos_preflight',
         ],
-        'mixins': [
-          'has_native_resultdb_integration',
-        ],
         'test_suites': {
           'gtest_tests': 'chromeos_device_gtests',
           'isolated_scripts': 'chromeos_remote_device_isolated_tests',
@@ -170,9 +153,6 @@
         'additional_compile_targets': [
           'chromiumos_preflight',
         ],
-        'mixins': [
-          'has_native_resultdb_integration',
-        ],
         # TODO(crbug.com/1293222): Restore after octopus capacity has been
         # returned.
         #'test_suites': {
@@ -195,7 +175,6 @@
         ],
         'mixins': [
           'chromeos-reven',
-          'has_native_resultdb_integration',
         ],
         'test_suites': {
           'gtest_tests': 'chromeos_browser_integration_tests',
@@ -211,7 +190,6 @@
         ],
         'mixins': [
           'chrome-swarming-pool',
-          'has_native_resultdb_integration',
         ],
         'test_suites': {
           'gtest_tests': 'lacros_device_or_vm_tast_tests',
@@ -233,7 +211,6 @@
         ],
         'mixins': [
           'chrome-swarming-pool',
-          'has_native_resultdb_integration',
         ],
         'test_suites': {
           'skylab_tests': 'lacros_skylab_tests_amd64_generic',
@@ -268,7 +245,6 @@
         ],
         'mixins': [
           'chrome-swarming-pool',
-          'has_native_resultdb_integration',
         ],
         'test_suites': {
           'skylab_tests': 'lacros_skylab_arm',
@@ -1542,7 +1518,6 @@
         'browser_config': 'cros-chrome',
         'mixins': [
           'chromeos-amd64-generic',
-          'has_native_resultdb_integration',
         ],
         'os_type': 'chromeos',
         'test_suites': {
@@ -1572,7 +1547,6 @@
         ],
         'mixins': [
           'chromeos-kevin',
-          'has_native_resultdb_integration',
         ],
         'test_suites': {
           'gtest_tests': 'chromeos_device_gtests',
@@ -1590,9 +1564,6 @@
           'chrome',
           'browser_tests',
         ],
-        'mixins': [
-          'has_native_resultdb_integration',
-        ],
         'test_suites': {
           'gtest_tests': 'lacros_device_or_vm_tests',
         },
@@ -1602,9 +1573,6 @@
         'additional_compile_targets': [
           'chrome',
         ],
-        'mixins': [
-          'has_native_resultdb_integration',
-        ],
         'os_type': 'chromeos'
       },
       'linux-ash-chromium-generator-rel': {
@@ -3041,7 +3009,6 @@
         'browser_config': 'cros-chrome',
         'mixins': [
           'chromeos-amd64-generic',
-          'has_native_resultdb_integration',
         ],
         'os_type': 'chromeos',
         'test_suites': {
@@ -3068,7 +3035,6 @@
         'browser_config': 'cros-chrome',
         'mixins': [
           'chromeos-amd64-generic',
-          'has_native_resultdb_integration',
         ],
         'os_type': 'chromeos',
         'test_suites': {
@@ -3406,9 +3372,6 @@
         'additional_compile_targets': [
           'chrome',
         ],
-        'mixins': [
-          'has_native_resultdb_integration',
-        ],
         'test_suites': {
           'gtest_tests': 'lacros_device_or_vm_tests_fyi',
         },
@@ -6301,7 +6264,6 @@
         ],
         'mixins': [
           'chromeos-betty',
-          'has_native_resultdb_integration',
         ],
         'test_suites': {
           'gtest_tests': 'chromeos_vm_gtests',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 72c2e0d9..4a48cfa 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -6852,8 +6852,8 @@
                 {
                     "name": "Enabled",
                     "params": {
-                        "enable_quic": "true",
-                        "quic_version": "h3,h3-29,h3-Q050",
+                        "channel": "F",
+                        "epoch": "30000000",
                         "retransmittable_on_wire_timeout_milliseconds": "200"
                     },
                     "enable_features": [
diff --git a/third_party/blink/public/platform/web_media_player.h b/third_party/blink/public/platform/web_media_player.h
index ac264e3..b72b16a92 100644
--- a/third_party/blink/public/platform/web_media_player.h
+++ b/third_party/blink/public/platform/web_media_player.h
@@ -260,7 +260,13 @@
   // to upload or convert it. Note: This may kick off a process to update the
   // current frame for a future call in some cases. Returns nullptr if no frame
   // is available.
-  virtual scoped_refptr<media::VideoFrame> GetCurrentFrame() = 0;
+  virtual scoped_refptr<media::VideoFrame> GetCurrentFrameThenUpdate() = 0;
+
+  // Return current video frame unique id from compositor. The query is readonly
+  // and should avoid any extra ops. Function returns absl::nullopt if current
+  // frame is invalid or fails to access current frame.
+  // TODO(crbug.com/1328005): Change the id into a 64 bit value.
+  virtual absl::optional<int> CurrentFrameId() const = 0;
 
   // Provides a PaintCanvasVideoRenderer instance owned by this WebMediaPlayer.
   // Useful for ensuring that the paint/texturing operation for current frame is
diff --git a/third_party/blink/public/web/modules/mediastream/webmediaplayer_ms.h b/third_party/blink/public/web/modules/mediastream/webmediaplayer_ms.h
index 7b42a142..e67725f 100644
--- a/third_party/blink/public/web/modules/mediastream/webmediaplayer_ms.h
+++ b/third_party/blink/public/web/modules/mediastream/webmediaplayer_ms.h
@@ -127,7 +127,8 @@
   void Paint(cc::PaintCanvas* canvas,
              const gfx::Rect& rect,
              cc::PaintFlags& flags) override;
-  scoped_refptr<media::VideoFrame> GetCurrentFrame() override;
+  scoped_refptr<media::VideoFrame> GetCurrentFrameThenUpdate() override;
+  absl::optional<int> CurrentFrameId() const override;
   media::PaintCanvasVideoRenderer* GetPaintCanvasVideoRenderer() override;
   void ResetCanvasCache();
 
diff --git a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
index a4ab6ec..38b10e1 100644
--- a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
+++ b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
@@ -1570,7 +1570,8 @@
 
 static bool IsSVGObjectWithWidthAndHeight(const LayoutObject& layout_object) {
   DCHECK(layout_object.IsSVGChild());
-  return layout_object.IsSVGImage() || layout_object.IsSVGForeignObject() ||
+  return layout_object.IsSVGImage() ||
+         layout_object.IsSVGForeignObjectIncludingNG() ||
          (layout_object.IsSVGShape() &&
           IsA<SVGRectElement>(layout_object.GetNode()));
 }
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 29c1ac2..e2d00bd 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -1983,7 +1983,7 @@
   // codepath below.
   auto* svg_element = DynamicTo<SVGElement>(this);
   if (svg_element && GetLayoutObject() &&
-      !GetLayoutObject()->IsSVGForeignObject()) {
+      !GetLayoutObject()->IsSVGForeignObjectIncludingNG()) {
     // Get the bounding rectangle from the SVG model.
     // TODO(pdr): This should include stroke.
     if (IsA<SVGGraphicsElement>(svg_element)) {
@@ -2092,7 +2092,7 @@
   // codepath below.
   const auto* svg_element = DynamicTo<SVGElement>(this);
   if (svg_element && !element_layout_object->IsSVGRoot() &&
-      !element_layout_object->IsSVGForeignObject()) {
+      !element_layout_object->IsSVGForeignObjectIncludingNG()) {
     // Get the bounding rectangle from the SVG model.
     // TODO(pdr): ObjectBoundingBox does not include stroke and the spec is not
     // clear (see: https://github.com/w3c/svgwg/issues/339, crbug.com/529734).
diff --git a/third_party/blink/renderer/core/exported/web_media_player_impl_unittest.cc b/third_party/blink/renderer/core/exported/web_media_player_impl_unittest.cc
index fd16b64..44fa743 100644
--- a/third_party/blink/renderer/core/exported/web_media_player_impl_unittest.cc
+++ b/third_party/blink/renderer/core/exported/web_media_player_impl_unittest.cc
@@ -2284,7 +2284,7 @@
     }
 
     if (IsVideoBeingCaptured())
-      wmpi_->GetCurrentFrame();
+      wmpi_->GetCurrentFrameThenUpdate();
 
     BackgroundPlayer();
   }
diff --git a/third_party/blink/renderer/core/html/media/html_video_element.cc b/third_party/blink/renderer/core/html/media/html_video_element.cc
index 10fcbb59..6b8b2f5 100644
--- a/third_party/blink/renderer/core/html/media/html_video_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_video_element.cc
@@ -500,7 +500,7 @@
   media::PaintCanvasVideoRenderer* video_renderer = nullptr;
   scoped_refptr<media::VideoFrame> media_video_frame;
   if (auto* wmp = GetWebMediaPlayer()) {
-    media_video_frame = wmp->GetCurrentFrame();
+    media_video_frame = wmp->GetCurrentFrameThenUpdate();
     video_renderer = wmp->GetPaintCanvasVideoRenderer();
   }
 
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index 195f9df2..a5194ca 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -1632,7 +1632,7 @@
   // select elements inside that are created by user agent shadow DOM, and we
   // have (C++) code that assumes that the elements are indeed contained by the
   // text control. So just make sure this is the case.
-  if (IsA<LayoutView>(this) || IsSVGForeignObject() ||
+  if (IsA<LayoutView>(this) || IsSVGForeignObjectIncludingNG() ||
       IsTextControlIncludingNG())
     return true;
   // https://www.w3.org/TR/css-transforms-1/#containing-block-for-all-descendants
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h
index 992cb3d..5e0f84ea 100644
--- a/third_party/blink/renderer/core/layout/layout_object.h
+++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -1289,6 +1289,11 @@
     NOT_DESTROYED();
     return IsOfType(kLayoutObjectSVGForeignObject);
   }
+  bool IsSVGForeignObjectIncludingNG() const {
+    NOT_DESTROYED();
+    return IsOfType(kLayoutObjectSVGForeignObject) ||
+           IsOfType(kLayoutObjectNGSVGForeignObject);
+  }
   bool IsSVGResourceContainer() const {
     NOT_DESTROYED();
     return IsOfType(kLayoutObjectSVGResourceContainer);
@@ -1320,7 +1325,7 @@
   bool IsBlendingAllowed() const {
     NOT_DESTROYED();
     return !IsSVG() || IsSVGShape() || IsSVGImage() || IsSVGText() ||
-           IsSVGInline() || IsSVGRoot() || IsSVGForeignObject() ||
+           IsSVGInline() || IsSVGRoot() || IsSVGForeignObjectIncludingNG() ||
            IsNGSVGText() ||
            // Blending does not apply to non-renderable elements such as
            // patterns (see: https://github.com/w3c/fxtf-drafts/issues/309).
diff --git a/third_party/blink/renderer/core/layout/svg/svg_content_container.cc b/third_party/blink/renderer/core/layout/svg/svg_content_container.cc
index 3f4ecc0..306e00b 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_content_container.cc
+++ b/third_party/blink/renderer/core/layout/svg/svg_content_container.cc
@@ -156,7 +156,7 @@
   // The local-to-parent transform for <foreignObject> contains a zoom inverse,
   // so we need to apply zoom to the bounding box that we use for propagation to
   // be in the correct coordinate space.
-  if (IsA<LayoutSVGForeignObject>(object))
+  if (object.IsSVGForeignObjectIncludingNG())
     bounds.Scale(object.StyleRef().EffectiveZoom());
   return bounds;
 }
diff --git a/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc b/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
index c201db3..f3131c5 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
+++ b/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
@@ -193,7 +193,7 @@
   DCHECK_NE(ancestor, &object);
   DCHECK(object.IsSVGContainer() || object.IsSVGShape() ||
          object.IsSVGImage() || object.IsSVGText() ||
-         object.IsSVGForeignObject());
+         object.IsSVGForeignObjectIncludingNG());
   AffineTransform local_to_svg_root;
   const LayoutSVGRoot& svg_root =
       ComputeTransformToSVGRoot(object, local_to_svg_root, nullptr);
diff --git a/third_party/blink/renderer/core/paint/clip_path_clipper.cc b/third_party/blink/renderer/core/paint/clip_path_clipper.cc
index 207b850..3f01472d 100644
--- a/third_party/blink/renderer/core/paint/clip_path_clipper.cc
+++ b/third_party/blink/renderer/core/paint/clip_path_clipper.cc
@@ -61,7 +61,8 @@
 // Is the reference box (as returned by LocalReferenceBox) for |clip_path_owner|
 // zoomed with EffectiveZoom()?
 static bool UsesZoomedReferenceBox(const LayoutObject& clip_path_owner) {
-  return !clip_path_owner.IsSVGChild() || clip_path_owner.IsSVGForeignObject();
+  return !clip_path_owner.IsSVGChild() ||
+         clip_path_owner.IsSVGForeignObjectIncludingNG();
 }
 
 static bool HasCompositeClipPathAnimation(const LayoutObject& layout_object) {
diff --git a/third_party/blink/renderer/core/paint/css_mask_painter.cc b/third_party/blink/renderer/core/paint/css_mask_painter.cc
index 08f27e0..f8a95f8 100644
--- a/third_party/blink/renderer/core/paint/css_mask_painter.cc
+++ b/third_party/blink/renderer/core/paint/css_mask_painter.cc
@@ -25,14 +25,15 @@
       if (masker) {
         const gfx::RectF reference_box =
             SVGResources::ReferenceBoxForEffects(object);
-        const float reference_box_zoom =
-            object.IsSVGForeignObject() ? object.StyleRef().EffectiveZoom() : 1;
+        const float reference_box_zoom = object.IsSVGForeignObjectIncludingNG()
+                                             ? object.StyleRef().EffectiveZoom()
+                                             : 1;
         return masker->ResourceBoundingBox(reference_box, reference_box_zoom);
       }
     }
   }
 
-  if (object.IsSVGChild() && !object.IsSVGForeignObject())
+  if (object.IsSVGChild() && !object.IsSVGForeignObjectIncludingNG())
     return absl::nullopt;
 
   if (!style.HasMask())
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc
index 787bb857..5400e23 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -1494,7 +1494,7 @@
   // foreignObject; if it weren't for that case we could test z_offset
   // and then DCHECK(transform_state) inside of it.
   DCHECK(!z_offset || transform_state ||
-         hit_layer->GetLayoutObject().IsSVGForeignObject());
+         hit_layer->GetLayoutObject().IsSVGForeignObjectIncludingNG());
   if (z_offset && transform_state) {
     // This is actually computing our z, but that's OK because the hitLayer is
     // coplanar with us.
@@ -1596,7 +1596,7 @@
   // IsReplacedNormalFlowStacking() true for LayoutSVGForeignObject),
   // where the hit_test_rect has already been transformed to local coordinates.
   bool use_transform = false;
-  if (!layout_object.IsSVGForeignObject() &&
+  if (!layout_object.IsSVGForeignObjectIncludingNG() &&
       // Only a layer that can contain all descendants can become a transform
       // container. This excludes layout objects having transform nodes created
       // for animating opacity etc. or for backface-visibility:hidden.
@@ -2030,7 +2030,7 @@
 }
 
 bool PaintLayer::IsReplacedNormalFlowStacking() const {
-  return GetLayoutObject().IsSVGForeignObject();
+  return GetLayoutObject().IsSVGForeignObjectIncludingNG();
 }
 
 PaintLayer* PaintLayer::HitTestChildren(
@@ -2149,7 +2149,7 @@
         To<ShapeClipPathOperation>(clip_path_operation);
     float zoom = GetLayoutObject().StyleRef().EffectiveZoom();
     DCHECK(!GetLayoutObject().IsSVGChild() ||
-           GetLayoutObject().IsSVGForeignObject());
+           GetLayoutObject().IsSVGForeignObjectIncludingNG());
     return !clip_path->GetPath(reference_box, zoom).Contains(point);
   }
   DCHECK_EQ(clip_path_operation->GetType(), ClipPathOperation::kReference);
@@ -2307,7 +2307,7 @@
       return false;
 
     // SVG root and SVG foreign object paint atomically.
-    if (box->IsSVGRoot() || box->IsSVGForeignObject())
+    if (box->IsSVGRoot() || box->IsSVGForeignObjectIncludingNG())
       return true;
 
     // Don't create subsequence for the document element because the subsequence
diff --git a/third_party/blink/renderer/core/paint/svg_mask_painter.cc b/third_party/blink/renderer/core/paint/svg_mask_painter.cc
index 83067be..59b18f9 100644
--- a/third_party/blink/renderer/core/paint/svg_mask_painter.cc
+++ b/third_party/blink/renderer/core/paint/svg_mask_painter.cc
@@ -61,7 +61,7 @@
     content_transformation.Translate(reference_box.x(), reference_box.y());
     content_transformation.ScaleNonUniform(reference_box.width(),
                                            reference_box.height());
-  } else if (layout_object.IsSVGForeignObject()) {
+  } else if (layout_object.IsSVGForeignObjectIncludingNG()) {
     content_transformation.Scale(style.EffectiveZoom());
   }
 
diff --git a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
index ecc4d56..df3421e 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
@@ -264,7 +264,8 @@
     }
     if (layout_object_->IsSVGShape())
       return ax::mojom::blink::Role::kGraphicsSymbol;
-    if (layout_object_->IsSVGForeignObject() || IsA<SVGGElement>(node))
+    if (layout_object_->IsSVGForeignObjectIncludingNG() ||
+        IsA<SVGGElement>(node))
       return ax::mojom::blink::Role::kGroup;
     if (IsA<SVGUseElement>(node))
       return ax::mojom::blink::Role::kGraphicsObject;
@@ -514,7 +515,7 @@
   }
 
   // The SVG-AAM says the foreignObject element is normally presentational.
-  if (layout_object_->IsSVGForeignObject()) {
+  if (layout_object_->IsSVGForeignObjectIncludingNG()) {
     if (ignored_reasons)
       ignored_reasons->push_back(IgnoredReason(kAXPresentational));
     return true;
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_underlying_sink.cc b/third_party/blink/renderer/modules/file_system_access/file_system_underlying_sink.cc
index 32d35a8..4bea4d1d 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_underlying_sink.cc
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_underlying_sink.cc
@@ -123,6 +123,11 @@
           "Invalid params passed. write requires a data argument");
       return ScriptPromise();
     }
+    if (!params.data()) {
+      exception_state.ThrowTypeError(
+          "Invalid params passed. write requires a non-null data");
+      return ScriptPromise();
+    }
     return WriteData(script_state, position, params.data(), exception_state);
   }
 
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.cc b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.cc
index 675f6c7a..b418bdb 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.cc
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.cc
@@ -120,7 +120,7 @@
   if (start_capture_time_.is_null())
     start_capture_time_ = current_time;
 
-  if (auto frame = web_media_player_->GetCurrentFrame()) {
+  if (auto frame = web_media_player_->GetCurrentFrameThenUpdate()) {
     auto new_frame = media::VideoFrame::WrapVideoFrame(
         frame, frame->format(), frame->visible_rect(), frame->natural_size());
     new_frame->set_timestamp(current_time - start_capture_time_);
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source_unittest.cc b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source_unittest.cc
index b0329e5..555ff3a 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source_unittest.cc
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source_unittest.cc
@@ -93,7 +93,7 @@
     return;
   }
 
-  scoped_refptr<media::VideoFrame> GetCurrentFrame() override {
+  scoped_refptr<media::VideoFrame> GetCurrentFrameThenUpdate() override {
     // We could fill in |canvas| with a meaningful pattern in ARGB and verify
     // that is correctly captured (as I420) by HTMLVideoElementCapturerSource
     // but I don't think that'll be easy/useful/robust, so just let go here.
@@ -101,6 +101,8 @@
                             : media::VideoFrame::CreateTransparentFrame(size_);
   }
 
+  absl::optional<int> CurrentFrameId() const override { return absl::nullopt; }
+
   bool IsOpaque() const override { return is_video_opaque_; }
   bool HasAvailableVideoFrame() const override { return true; }
 
diff --git a/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms.cc b/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms.cc
index 6db854a..01f79d4 100644
--- a/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms.cc
+++ b/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms.cc
@@ -1034,12 +1034,18 @@
                         GetFrameTransformation(frame), provider.get());
 }
 
-scoped_refptr<media::VideoFrame> WebMediaPlayerMS::GetCurrentFrame() {
+scoped_refptr<media::VideoFrame> WebMediaPlayerMS::GetCurrentFrameThenUpdate() {
   DVLOG(3) << __func__;
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   return compositor_->GetCurrentFrame();
 }
 
+absl::optional<int> WebMediaPlayerMS::CurrentFrameId() const {
+  DVLOG(3) << __func__;
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  return compositor_->GetCurrentFrame()->unique_id();
+}
+
 bool WebMediaPlayerMS::WouldTaintOrigin() const {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   return false;
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame.cc b/third_party/blink/renderer/modules/webcodecs/video_frame.cc
index a8ce91f..5c8e43a1 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_frame.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_frame.cc
@@ -475,7 +475,7 @@
         break;
       case V8CanvasImageSource::ContentType::kHTMLVideoElement:
         if (auto* wmp = source->GetAsHTMLVideoElement()->GetWebMediaPlayer())
-          source_frame = wmp->GetCurrentFrame();
+          source_frame = wmp->GetCurrentFrameThenUpdate();
         break;
       default:
         NOTREACHED();
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index eb7557bd..f15f260 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -5897,7 +5897,7 @@
   media::PaintCanvasVideoRenderer* video_renderer = nullptr;
   scoped_refptr<media::VideoFrame> media_video_frame;
   if (auto* wmp = video->GetWebMediaPlayer()) {
-    media_video_frame = wmp->GetCurrentFrame();
+    media_video_frame = wmp->GetCurrentFrameThenUpdate();
     video_renderer = wmp->GetPaintCanvasVideoRenderer();
   }
 
diff --git a/third_party/blink/renderer/modules/webgl/webgl_video_texture.cc b/third_party/blink/renderer/modules/webgl/webgl_video_texture.cc
index 0781a0e..06cc64b 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_video_texture.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_video_texture.cc
@@ -85,7 +85,7 @@
   media::PaintCanvasVideoRenderer* video_renderer = nullptr;
   scoped_refptr<media::VideoFrame> media_video_frame;
   if (auto* wmp = video->GetWebMediaPlayer()) {
-    media_video_frame = wmp->GetCurrentFrame();
+    media_video_frame = wmp->GetCurrentFrameThenUpdate();
     video_renderer = wmp->GetPaintCanvasVideoRenderer();
   }
 
diff --git a/third_party/blink/renderer/modules/webgpu/dawn_enum_conversions.cc b/third_party/blink/renderer/modules/webgpu/dawn_enum_conversions.cc
index 4c63202..556396d7 100644
--- a/third_party/blink/renderer/modules/webgpu/dawn_enum_conversions.cc
+++ b/third_party/blink/renderer/modules/webgpu/dawn_enum_conversions.cc
@@ -463,6 +463,8 @@
       return WGPUFeatureName_Depth32FloatStencil8;
     case V8GPUFeatureName::Enum::kIndirectFirstInstance:
       return WGPUFeatureName_IndirectFirstInstance;
+    case V8GPUFeatureName::Enum::kChromiumExperimentalDp4A:
+      return WGPUFeatureName_ChromiumExperimentalDp4a;
   }
 }
 
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_external_texture.cc b/third_party/blink/renderer/modules/webgpu/gpu_external_texture.cc
index 0fbcb0f..e9704ed 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_external_texture.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_external_texture.cc
@@ -118,7 +118,7 @@
       }
 
       if (auto* wmp = video->GetWebMediaPlayer()) {
-        source.media_video_frame = wmp->GetCurrentFrame();
+        source.media_video_frame = wmp->GetCurrentFrameThenUpdate();
         source.video_renderer = wmp->GetPaintCanvasVideoRenderer();
       }
 
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_supported_features.idl b/third_party/blink/renderer/modules/webgpu/gpu_supported_features.idl
index 73b5883c..a6125b1 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_supported_features.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_supported_features.idl
@@ -14,7 +14,8 @@
     "depth-clamping",
     "depth24unorm-stencil8",
     "depth32float-stencil8",
-    "indirect-first-instance"
+    "indirect-first-instance",
+    "chromium-experimental-dp4a",
 };
 
 [
diff --git a/third_party/blink/renderer/modules/webusb/usb_endpoint.cc b/third_party/blink/renderer/modules/webusb/usb_endpoint.cc
index a2d0528..645a00c0 100644
--- a/third_party/blink/renderer/modules/webusb/usb_endpoint.cc
+++ b/third_party/blink/renderer/modules/webusb/usb_endpoint.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/modules/webusb/usb_endpoint.h"
 
 #include "services/device/public/mojom/usb_device.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_usb_direction.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/modules/webusb/usb_alternate_interface.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -51,9 +52,9 @@
 
 USBEndpoint* USBEndpoint::Create(const USBAlternateInterface* alternate,
                                  uint8_t endpoint_number,
-                                 const String& direction,
+                                 const V8USBDirection& direction,
                                  ExceptionState& exception_state) {
-  UsbTransferDirection mojo_direction = direction == "in"
+  UsbTransferDirection mojo_direction = direction == V8USBDirection::Enum::kIn
                                             ? UsbTransferDirection::INBOUND
                                             : UsbTransferDirection::OUTBOUND;
   const auto& endpoints = alternate->Info().endpoints;
diff --git a/third_party/blink/renderer/modules/webusb/usb_endpoint.h b/third_party/blink/renderer/modules/webusb/usb_endpoint.h
index 5e5aec7..c69d36a0 100644
--- a/third_party/blink/renderer/modules/webusb/usb_endpoint.h
+++ b/third_party/blink/renderer/modules/webusb/usb_endpoint.h
@@ -14,6 +14,7 @@
 
 class ExceptionState;
 class USBAlternateInterface;
+class V8USBDirection;
 
 class USBEndpoint : public ScriptWrappable {
   DEFINE_WRAPPERTYPEINFO();
@@ -23,7 +24,7 @@
                              wtf_size_t endpoint_index);
   static USBEndpoint* Create(const USBAlternateInterface*,
                              uint8_t endpoint_number,
-                             const String& direction,
+                             const V8USBDirection& direction,
                              ExceptionState&);
 
   USBEndpoint(const USBAlternateInterface*, wtf_size_t endpoint_index);
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource.cc b/third_party/blink/renderer/platform/graphics/canvas_resource.cc
index 3413f5e..8ef0246 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource.cc
@@ -157,7 +157,10 @@
 
   out_resource->color_space = GetColorSpace();
   out_resource->format = GetResourceFormat();
-  out_resource->read_lock_fences_enabled = NeedsReadLockFences();
+  if (NeedsReadLockFences()) {
+    out_resource->synchronization_type =
+        viz::TransferableResource::SynchronizationType::kGpuCommandsCompleted;
+  }
 
   return true;
 }
diff --git a/third_party/blink/renderer/platform/media/web_media_player_impl.cc b/third_party/blink/renderer/platform/media/web_media_player_impl.cc
index ee6dbd0..36f6583 100644
--- a/third_party/blink/renderer/platform/media/web_media_player_impl.cc
+++ b/third_party/blink/renderer/platform/media/web_media_player_impl.cc
@@ -100,7 +100,6 @@
 #include "media/base/android/media_codec_util.h"
 #endif
 
-
 namespace blink {
 namespace {
 
@@ -1469,13 +1468,27 @@
       raster_context_provider_.get());
 }
 
-scoped_refptr<media::VideoFrame> WebMediaPlayerImpl::GetCurrentFrame() {
+scoped_refptr<media::VideoFrame>
+WebMediaPlayerImpl::GetCurrentFrameThenUpdate() {
   last_frame_request_time_ = tick_clock_->NowTicks();
   video_frame_readback_count_++;
   pipeline_controller_->OnExternalVideoFrameRequest();
   return GetCurrentFrameFromCompositor();
 }
 
+absl::optional<int> WebMediaPlayerImpl::CurrentFrameId() const {
+  DCHECK(main_task_runner_->BelongsToCurrentThread());
+  TRACE_EVENT0("media", "WebMediaPlayerImpl::GetCurrentFrameID");
+
+  // We can't copy from protected frames.
+  if (cdm_context_ref_)
+    return absl::nullopt;
+
+  if (auto frame = compositor_->GetCurrentFrameOnAnyThread())
+    return frame->unique_id();
+  return absl::nullopt;
+}
+
 media::PaintCanvasVideoRenderer*
 WebMediaPlayerImpl::GetPaintCanvasVideoRenderer() {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
diff --git a/third_party/blink/renderer/platform/media/web_media_player_impl.h b/third_party/blink/renderer/platform/media/web_media_player_impl.h
index d99ec00..6aff878 100644
--- a/third_party/blink/renderer/platform/media/web_media_player_impl.h
+++ b/third_party/blink/renderer/platform/media/web_media_player_impl.h
@@ -184,7 +184,8 @@
   void Paint(cc::PaintCanvas* canvas,
              const gfx::Rect& rect,
              cc::PaintFlags& flags) override;
-  scoped_refptr<media::VideoFrame> GetCurrentFrame() override;
+  scoped_refptr<media::VideoFrame> GetCurrentFrameThenUpdate() override;
+  absl::optional<int> CurrentFrameId() const override;
   media::PaintCanvasVideoRenderer* GetPaintCanvasVideoRenderer() override;
 
   // True if the loaded media has a playable video/audio track.
diff --git a/third_party/blink/renderer/platform/testing/empty_web_media_player.cc b/third_party/blink/renderer/platform/testing/empty_web_media_player.cc
index 4897f65..dc87990f 100644
--- a/third_party/blink/renderer/platform/testing/empty_web_media_player.cc
+++ b/third_party/blink/renderer/platform/testing/empty_web_media_player.cc
@@ -37,8 +37,13 @@
   return WebString();
 }
 
-scoped_refptr<media::VideoFrame> EmptyWebMediaPlayer::GetCurrentFrame() {
+scoped_refptr<media::VideoFrame>
+EmptyWebMediaPlayer::GetCurrentFrameThenUpdate() {
   return nullptr;
 }
 
+absl::optional<int> EmptyWebMediaPlayer::CurrentFrameId() const {
+  return absl::nullopt;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/testing/empty_web_media_player.h b/third_party/blink/renderer/platform/testing/empty_web_media_player.h
index 84555ea..812dedc 100644
--- a/third_party/blink/renderer/platform/testing/empty_web_media_player.h
+++ b/third_party/blink/renderer/platform/testing/empty_web_media_player.h
@@ -68,7 +68,8 @@
   void SetPowerExperimentState(bool enabled) override {}
   void SuspendForFrameClosed() override {}
   void Paint(cc::PaintCanvas*, const gfx::Rect&, cc::PaintFlags&) override {}
-  scoped_refptr<media::VideoFrame> GetCurrentFrame() override;
+  scoped_refptr<media::VideoFrame> GetCurrentFrameThenUpdate() override;
+  absl::optional<int> CurrentFrameId() const override;
   bool HasAvailableVideoFrame() const override { return false; }
   base::WeakPtr<WebMediaPlayer> AsWeakPtr() override {
     return base::SupportsWeakPtr<EmptyWebMediaPlayer>::AsWeakPtr();
diff --git a/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/header-refresh.https.optional.sub.html b/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/header-refresh.https.optional.sub.html
index c303d871..e63ee42 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/header-refresh.https.optional.sub.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/header-refresh.https.optional.sub.html
@@ -7,6 +7,7 @@
 -->
 <html lang="en">
   <meta charset="utf-8">
+  <meta name="timeout" content="long">
   <title>HTTP headers on request for HTTP "Refresh" header</title>
   <script src="/resources/testharness.js"></script>
   <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/header-refresh.optional.sub.html b/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/header-refresh.optional.sub.html
index 56f2466..4674ada 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/header-refresh.optional.sub.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/header-refresh.optional.sub.html
@@ -7,6 +7,7 @@
 -->
 <html lang="en">
   <meta charset="utf-8">
+  <meta name="timeout" content="long">
   <title>HTTP headers on request for HTTP "Refresh" header</title>
   <script src="/resources/testharness.js"></script>
   <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/metadata/tools/templates/header-refresh.optional.sub.html b/third_party/blink/web_tests/external/wpt/fetch/metadata/tools/templates/header-refresh.optional.sub.html
index ff497b59..ec963d5 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/metadata/tools/templates/header-refresh.optional.sub.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/metadata/tools/templates/header-refresh.optional.sub.html
@@ -4,6 +4,9 @@
 -->
 <html lang="en">
   <meta charset="utf-8">
+  {%- if subtests|length > 10 %}
+  <meta name="timeout" content="long">
+  {%- endif %}
   <title>HTTP headers on request for HTTP "Refresh" header</title>
   <script src="/resources/testharness.js"></script>
   <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/fs/script-tests/FileSystemWritableFileStream-write.js b/third_party/blink/web_tests/external/wpt/fs/script-tests/FileSystemWritableFileStream-write.js
index ea4915a1..287c4ae 100644
--- a/third_party/blink/web_tests/external/wpt/fs/script-tests/FileSystemWritableFileStream-write.js
+++ b/third_party/blink/web_tests/external/wpt/fs/script-tests/FileSystemWritableFileStream-write.js
@@ -327,6 +327,15 @@
 }, 'WriteParams: write missing data param');
 
 directory_test(async (t, root) => {
+  const handle = await createEmptyFile(t, 'content.txt', root);
+  const stream = await handle.createWritable();
+
+  await promise_rejects_js(
+      t, TypeError, stream.write({type: 'write', data: null}), 'write with null data');
+
+}, 'WriteParams: write null data param');
+
+directory_test(async (t, root) => {
   const handle = await createFileWithContents(
       t, 'content.txt', 'seekable', root);
   const stream = await handle.createWritable();
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-unsafe-none-with-cross-origin.https.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-unsafe-none-with-cross-origin.https.html
index 26a273a..c776f445 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-unsafe-none-with-cross-origin.https.html
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-unsafe-none-with-cross-origin.https.html
@@ -14,7 +14,7 @@
   {
     "title": "popup with empty coop",
     "coop": "",
-    "opener": "preservedt"
+    "opener": "preserved"
   },
   {
     "title": "popup with coop unsafe-none",
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-unsafe-none-with-cross-origin.https.html.headers b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-unsafe-none-with-cross-origin.https.html.headers
new file mode 100644
index 0000000..073ce7a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-unsafe-none-with-cross-origin.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: unsafe-none
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-unsafe-none-with-same-site.https.html.headers b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-unsafe-none-with-same-site.https.html.headers
new file mode 100644
index 0000000..073ce7a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-unsafe-none-with-same-site.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: unsafe-none
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-unspecified-with-cross-origin.https.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-unspecified-with-cross-origin.https.html
index 26a273a..c776f445 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-unspecified-with-cross-origin.https.html
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-unspecified-with-cross-origin.https.html
@@ -14,7 +14,7 @@
   {
     "title": "popup with empty coop",
     "coop": "",
-    "opener": "preservedt"
+    "opener": "preserved"
   },
   {
     "title": "popup with coop unsafe-none",
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-unspecified-with-same-origin.https.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-unspecified-with-same-origin.https.html
index ca69369..7b3f4d9 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-unspecified-with-same-origin.https.html
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-unspecified-with-same-origin.https.html
@@ -14,7 +14,7 @@
   {
     "title": "popup with empty coop",
     "coop": "",
-    "opener": "preservedt"
+    "opener": "preserved"
   },
   {
     "title": "popup with coop unsafe-none",
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-unspecified-with-same-site.https.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-unspecified-with-same-site.https.html
index 7360674..7d734fa2 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-unspecified-with-same-site.https.html
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-unspecified-with-same-site.https.html
@@ -14,7 +14,7 @@
   {
     "title": "popup with empty coop",
     "coop": "",
-    "opener": "preservedt"
+    "opener": "preserved"
   },
   {
     "title": "popup with coop unsafe-none",
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-with-structured-header.https.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-with-structured-header.https.html
index 4066595b..729be3c 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-with-structured-header.https.html
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-with-structured-header.https.html
@@ -27,7 +27,7 @@
     "opener": "severed",
   }
 ].forEach(variant => {
-  popup_test(`Same-origin ${variant.title}`, SAME_ORIGIN, variant.coop, variant.same_origin_opener);
+  popup_test(`Same-origin ${variant.title}`, SAME_ORIGIN, variant.coop, variant.opener);
 });
 
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/resources/popup-test.js b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/resources/popup-test.js
index 4bf38a3a..3da5ca1 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/resources/popup-test.js
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/resources/popup-test.js
@@ -77,6 +77,8 @@
                      'Popup has nulled opener?');
         break;
       }
+      default:
+        assert_unreached(true, "Unrecognized opener relationship: " + expected_opener_state);
     }
   }, description);
 }
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/fenced-frame/stopLoading-fenced-frame.https.js b/third_party/blink/web_tests/http/tests/inspector-protocol/fenced-frame/stopLoading-fenced-frame.https.js
new file mode 100644
index 0000000..8fbf8f5
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/fenced-frame/stopLoading-fenced-frame.https.js
@@ -0,0 +1,34 @@
+(async function(testRunner) {
+  const {session, dp} = await testRunner.startURL(
+      'resources/page-with-fenced-frame.php',
+      'Tests that Page.stopLoading() in a fenced frame returns an error.');
+  await dp.Page.enable();
+  await dp.Runtime.enable();
+
+  dp.Target.setAutoAttach(
+      {autoAttach: true, waitForDebuggerOnStart: false, flatten: true});
+  let {sessionId} = (await dp.Target.onceAttachedToTarget()).params;
+
+  let childSession = session.createChild(sessionId);
+  let ffdp = childSession.protocol;
+
+  // Wait for FF to finish loading.
+  await ffdp.Page.enable();
+  ffdp.Page.setLifecycleEventsEnabled({enabled: true});
+  await ffdp.Page.onceLifecycleEvent(event => event.params.name === 'load');
+
+  await ffdp.Network.setRequestInterception({patterns: [{}]});
+  const navigatePromiseForFF = ffdp.Page.navigate(
+      {url: testRunner.url('../resources/inspector-protocol-page.html')});
+  const result = await ffdp.Page.stopLoading();
+  testRunner.log(
+      'Page.stopLoading() from a fenced frame:\n' +
+      (result.error ? 'PASS: ' + result.error.message : 'FAIL: no error'));
+
+  // Page.stopLoading() from a top level page cancels all navigation in the
+  // page.
+  dp.Page.stopLoading();
+  await navigatePromiseForFF;
+  testRunner.log('navigation finished');
+  testRunner.completeTest();
+})
diff --git a/third_party/blink/web_tests/platform/generic/http/tests/inspector-protocol/fenced-frame/stopLoading-fenced-frame.https-expected.txt b/third_party/blink/web_tests/platform/generic/http/tests/inspector-protocol/fenced-frame/stopLoading-fenced-frame.https-expected.txt
new file mode 100644
index 0000000..541ecf5
--- /dev/null
+++ b/third_party/blink/web_tests/platform/generic/http/tests/inspector-protocol/fenced-frame/stopLoading-fenced-frame.https-expected.txt
@@ -0,0 +1,5 @@
+Tests that Page.stopLoading() in a fenced frame returns an error.
+Page.stopLoading() from a fenced frame:
+PASS: Command can only be executed on top-level targets
+navigation finished
+
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/cts.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/cts.https.html
index 83cae8a..0dee2bd 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/cts.https.html
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/cts.https.html
@@ -2588,6 +2588,7 @@
 <meta name=variant content='?q=webgpu:api,validation,resource_usages,buffer,in_pass_encoder:subresources,buffer_usage_in_one_compute_pass_with_one_dispatch:*'>
 <meta name=variant content='?q=webgpu:api,validation,resource_usages,buffer,in_pass_encoder:subresources,buffer_usage_in_compute_pass_with_two_dispatches:*'>
 <meta name=variant content='?q=webgpu:api,validation,resource_usages,buffer,in_pass_encoder:subresources,buffer_usage_in_one_render_pass_with_no_draw:*'>
+<meta name=variant content='?q=webgpu:api,validation,resource_usages,buffer,in_pass_encoder:subresources,buffer_usage_in_one_render_pass_with_one_draw:*'>
 <meta name=variant content='?q=webgpu:api,validation,resource_usages,texture,in_pass_encoder:subresources_and_binding_types_combination_for_color:*'>
 <meta name=variant content='?q=webgpu:api,validation,resource_usages,texture,in_pass_encoder:subresources_and_binding_types_combination_for_aspect:compute=false;binding0InBundle=false;*'>
 <meta name=variant content='?q=webgpu:api,validation,resource_usages,texture,in_pass_encoder:subresources_and_binding_types_combination_for_aspect:compute=false;binding0InBundle=true;*'>
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index 1e5042d..27ad761 100644
--- a/third_party/freetype/README.chromium
+++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@
 Name: FreeType
 URL: http://www.freetype.org/
-Version: VER-2-12-1-9-gb98dd169a
-Revision: b98dd169a1823485e35b3007ce707a6712dcd525
+Version: VER-2-12-1-12-gd68579812
+Revision: d6857981239ea5f6e95cb4eb4402307f3527760a
 CPEPrefix: cpe:/a:freetype:freetype:2.11.1
 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent
          JPEG Group) licenses"
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 6e3753fe..47b353a 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -57917,7 +57917,6 @@
   <int value="26945819" label="EnhancedDeskAnimations:disabled"/>
   <int value="27507364" label="apps-keep-chrome-alive"/>
   <int value="29212695" label="OfflineIndicator:enabled"/>
-  <int value="31693434" label="ExtendedOpenVpnSettings:enabled"/>
   <int value="31776417" label="EnableIkev2Vpn:disabled"/>
   <int value="31848187" label="ViewsTaskManager:disabled"/>
   <int value="32057053" label="EnterpriseReportingInBrowser:disabled"/>
@@ -59962,7 +59961,6 @@
   <int value="1379571437" label="ExoPointerLock:disabled"/>
   <int value="1379944457" label="EnableMessagesWebPush:disabled"/>
   <int value="1380367827" label="AllowDisableTouchpadHapticFeedback:enabled"/>
-  <int value="1381267110" label="ExtendedOpenVpnSettings:disabled"/>
   <int value="1381746642" label="enable-automatic-password-saving"/>
   <int value="1381817717" label="EduCoexistence:enabled"/>
   <int value="1382107019" label="LevelDBPerformRewrite:disabled"/>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index 193fb374..1b0f4ae 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -2638,6 +2638,25 @@
   </summary>
 </histogram>
 
+<histogram name="Ash.MojoServiceManager.BootstrapRetryTimes" units="count"
+    expires_after="2023-05-27">
+  <owner>chungsheng@google.com</owner>
+  <owner>chromeos-mojo-service-manager@google.com</owner>
+  <summary>
+    The retry times when try to bootstrap to mojo service manager.
+  </summary>
+</histogram>
+
+<histogram name="Ash.MojoServiceManager.IsConnectionLost" enum="BooleanShown"
+    expires_after="2023-05-27">
+  <owner>chungsheng@google.com</owner>
+  <owner>chromeos-mojo-service-manager@google.com</owner>
+  <summary>
+    Whether the connection to mojo service manager is lost before during ash
+    running.
+  </summary>
+</histogram>
+
 <histogram
     name="Ash.NavigationWidget.AnimationSmoothness{HotseatTransitionType}"
     units="%" expires_after="2023-04-20">
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml
index 2132e51..4ed61f443 100644
--- a/tools/metrics/histograms/metadata/net/histograms.xml
+++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -391,19 +391,8 @@
   </summary>
 </histogram>
 
-<histogram name="Net.Cors.AccessCheckError" enum="CorsAccessCheckError"
-    expires_after="2022-07-11">
-  <owner>toyoshim@chromium.org</owner>
-  <owner>yhirano@chromium.org</owner>
-  <summary>
-    The distribution of CORS error types on the original network requests. This
-    reports whenever CORS checks detect an error on the original network
-    requests.
-  </summary>
-</histogram>
-
 <histogram name="Net.Cors.AccessCheckResult" enum="CorsAccessCheckResult"
-    expires_after="M102">
+    expires_after="2022-09-18">
   <owner>toyoshim@chromium.org</owner>
   <owner>yhirano@chromium.org</owner>
   <summary>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 7b8ab45..f716cfb 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,8 +5,8 @@
             "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux_arm64/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell"
         },
         "win": {
-            "hash": "48d476a0da2cefa69550955343c77d866c644db8",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/67e7a1bc3cef3d387f3387c4f156f8dd7caf58db/trace_processor_shell.exe"
+            "hash": "94b8f2a9f63756da5d4c02b61fc7713a34bb11eb",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/989b580fdb73a90d3c659b3b4ff2bcdfa7039d55/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "58893933be305d3bfe0a72ebebcacde2ac3ca893",
diff --git a/ui/android/BUILD.gn b/ui/android/BUILD.gn
index 38cacc0..5dda04f9 100644
--- a/ui/android/BUILD.gn
+++ b/ui/android/BUILD.gn
@@ -273,6 +273,7 @@
     "java/src/org/chromium/ui/display/DisplayUtil.java",
     "java/src/org/chromium/ui/display/PhysicalDisplayAndroid.java",
     "java/src/org/chromium/ui/display/VirtualDisplayAndroid.java",
+    "java/src/org/chromium/ui/dragdrop/DragAndDropBrowserDelegate.java",
     "java/src/org/chromium/ui/dragdrop/DragAndDropDelegate.java",
     "java/src/org/chromium/ui/dragdrop/DragAndDropDelegateImpl.java",
     "java/src/org/chromium/ui/dragdrop/DragStateTracker.java",
diff --git a/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropBrowserDelegate.java b/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropBrowserDelegate.java
new file mode 100644
index 0000000..a53e79ee1
--- /dev/null
+++ b/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropBrowserDelegate.java
@@ -0,0 +1,19 @@
+// 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.ui.dragdrop;
+
+import android.view.DragAndDropPermissions;
+import android.view.DragEvent;
+
+/**
+ * Delegate for browser related functions used by Drag and Drop.
+ */
+public interface DragAndDropBrowserDelegate {
+    /** Get whether to support the image drop into Chrome */
+    boolean getSupportDropInChrome();
+
+    /** Request DragAndDropPermissions. */
+    DragAndDropPermissions getDragAndDropPermissions(DragEvent dropEvent);
+}
diff --git a/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropDelegate.java b/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropDelegate.java
index 7c8813be..762c981 100644
--- a/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropDelegate.java
+++ b/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropDelegate.java
@@ -8,12 +8,16 @@
 import android.view.View;
 
 /**
- * Delegate to re-route the call to {@link #startDragAndDrop(Bitmap, DropDataAndroid).}
+ * Delegate to perform drag and drop operations, for example re-routing the call to {@link
+ * #startDragAndDrop(Bitmap, DropDataAndroid).}
  */
 public interface DragAndDropDelegate {
     /** @see View#startDragAndDrop */
     boolean startDragAndDrop(View containerView, Bitmap shadowImage, DropDataAndroid dropData);
 
-    /** Enable or disable the data handling for drop in Chrome */
-    default void enableDropInChrome(boolean dropInChrome) {}
+    /**
+     * Set the {@link DragAndDropBrowserDelegate} that will be used to get DragAndDropPermissions.
+     * @param delegate The {@link DragAndDropBrowserDelegate} that will be used by this class.
+     */
+    default void setDragAndDropBrowserDelegate(DragAndDropBrowserDelegate delegate) {}
 }
diff --git a/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropDelegateImpl.java b/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropDelegateImpl.java
index acbf504..64e3889 100644
--- a/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropDelegateImpl.java
+++ b/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropDelegateImpl.java
@@ -12,11 +12,13 @@
 import android.graphics.drawable.Drawable;
 import android.media.ThumbnailUtils;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Build.VERSION;
 import android.os.Build.VERSION_CODES;
 import android.os.SystemClock;
 import android.text.TextUtils;
 import android.util.Pair;
+import android.view.DragAndDropPermissions;
 import android.view.DragEvent;
 import android.view.View;
 import android.view.View.DragShadowBuilder;
@@ -26,6 +28,7 @@
 
 import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.VisibleForTesting;
 import androidx.appcompat.content.res.AppCompatResources;
@@ -82,6 +85,8 @@
 
     private long mDragStartSystemElapsedTime;
 
+    private @Nullable DragAndDropBrowserDelegate mDragAndDropBrowserDelegate;
+
     // Implements ViewAndroidDelegate.DragAndDropDelegate
     /**
      * Wrapper to call {@link android.view.View#startDragAndDrop}.
@@ -115,8 +120,8 @@
     }
 
     @Override
-    public void enableDropInChrome(boolean dropInChrome) {
-        mDropInChrome = dropInChrome;
+    public void setDragAndDropBrowserDelegate(DragAndDropBrowserDelegate delegate) {
+        mDragAndDropBrowserDelegate = delegate;
     }
 
     // Implements DragStateTracker
@@ -143,8 +148,14 @@
     // Implements View.OnDragListener
     @Override
     public boolean onDrag(View view, DragEvent dragEvent) {
-        // Only tracks drag event that started from the #startDragAndDrop.
-        if (!mIsDragStarted) return false;
+        if (!mIsDragStarted) {
+            if (mDragAndDropBrowserDelegate != null
+                    && mDragAndDropBrowserDelegate.getSupportDropInChrome()
+                    && dragEvent.getAction() == DragEvent.ACTION_DROP) {
+                onDropFromOutside(dragEvent);
+            }
+            return false;
+        }
 
         switch (dragEvent.getAction()) {
             case DragEvent.ACTION_DRAG_STARTED:
@@ -329,6 +340,21 @@
                 "Android.DragDrop.FromWebContent.DropInWebContent.Duration", dropDuration);
     }
 
+    private void onDropFromOutside(DragEvent dropEvent) {
+        if (mDragAndDropBrowserDelegate == null) {
+            return;
+        }
+        DragAndDropPermissions dragAndDropPermissions =
+                mDragAndDropBrowserDelegate.getDragAndDropPermissions(dropEvent);
+        if (dragAndDropPermissions == null) {
+            return;
+        }
+        // TODO(shuyng): Read image data in background thread.
+        if (VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            dragAndDropPermissions.release();
+        }
+    }
+
     private void onDragEnd(DragEvent dragEndEvent) {
         boolean dragResult = dragEndEvent.getResult();
 
diff --git a/ui/base/models/dialog_model_field.cc b/ui/base/models/dialog_model_field.cc
index 79fa7a9..96eb078 100644
--- a/ui/base/models/dialog_model_field.cc
+++ b/ui/base/models/dialog_model_field.cc
@@ -287,7 +287,11 @@
     : DialogModelField(pass_key, model, kTextfield, id, params.accelerators_),
       label_(label),
       accessible_name_(params.accessible_name_),
-      text_(std::move(text)) {}
+      text_(std::move(text)) {
+  // Textfields need either an accessible name or label or the screenreader will
+  // not be able to announce anything sensible.
+  DCHECK(!label_.empty() || !accessible_name_.empty());
+}
 
 DialogModelTextfield::~DialogModelTextfield() = default;
 
diff --git a/ui/chromeos/strings/network_element_localized_strings_provider.cc b/ui/chromeos/strings/network_element_localized_strings_provider.cc
index bcdb0b0..593e218 100644
--- a/ui/chromeos/strings/network_element_localized_strings_provider.cc
+++ b/ui/chromeos/strings/network_element_localized_strings_provider.cc
@@ -428,8 +428,6 @@
                           chromeos::features::ShouldUseAttachApn());
   html_source->AddBoolean("esimPolicyEnabled",
                           chromeos::features::IsESimPolicyEnabled());
-  html_source->AddBoolean("extendedOpenVpnSettingsEnabled",
-                          ash::features::IsExtendedOpenVpnSettingsEnabled());
 }
 
 void AddConfigLocalizedStrings(content::WebUIDataSource* html_source) {
diff --git a/ui/chromeos/styles/cros_colors.json5 b/ui/chromeos/styles/cros_colors.json5
index afbe82ac..9650c43 100644
--- a/ui/chromeos/styles/cros_colors.json5
+++ b/ui/chromeos/styles/cros_colors.json5
@@ -124,7 +124,6 @@
     text_highlight_color: {
       light: "rgba($google_blue_600_rgb, 0.3)",
       dark: "rgba($google_blue_400_rgb, 0.3)",
-      generate_per_mode: true,
     },
 
     /*
@@ -215,7 +214,6 @@
       light: "$google_blue_50",
       dark: "rgba($google_blue_300_rgb, 0.3)",
       debug: "rgba($google_red_300_rgb, 0.3)",
-      generate_per_mode: true,
     },
     highlight_color_error: {
       light: "$google_red_50",
diff --git a/ui/file_manager/file_manager/common/js/filtered_volume_manager.js b/ui/file_manager/file_manager/common/js/filtered_volume_manager.js
index 8adb972..9a288df 100644
--- a/ui/file_manager/file_manager/common/js/filtered_volume_manager.js
+++ b/ui/file_manager/file_manager/common/js/filtered_volume_manager.js
@@ -129,6 +129,15 @@
   }
 
   /**
+   * Gets 'fusebox-only' filter state: true if enabled, false if disabled. This
+   * filter is only enabled by the SelectFileAsh (Lacros) file picker.
+   * @return {boolean}
+   */
+  get isFuseBoxOnlyFilterEnabled() {
+    return this.isFuseBoxOnly_;
+  }
+
+  /**
    * Checks if a volume type is allowed.
    *
    * Note that even if a volume type is allowed, a volume of that type might be
diff --git a/ui/file_manager/file_manager/common/js/filtered_volume_manager_unittest.m.js b/ui/file_manager/file_manager/common/js/filtered_volume_manager_unittest.m.js
index 02bc3a1..6887ad3 100644
--- a/ui/file_manager/file_manager/common/js/filtered_volume_manager_unittest.m.js
+++ b/ui/file_manager/file_manager/common/js/filtered_volume_manager_unittest.m.js
@@ -88,6 +88,9 @@
       AllowedPaths.ANY_PATH_OR_URL, false, Promise.resolve(volumeManager), []);
 
   filteredVolumeManager.ensureInitialized(() => {
+    // Check: isFuseBoxOnlyFilterEnabled getter should return false.
+    assertFalse(filteredVolumeManager.isFuseBoxOnlyFilterEnabled);
+
     // Check: filteredVolumeManager.volumeInfoList should have 4 volumes.
     assertEquals(4, filteredVolumeManager.volumeInfoList.length);
 
@@ -171,6 +174,9 @@
       ['fusebox-only']);
 
   filteredVolumeManager.ensureInitialized(() => {
+    // Check: isFuseBoxOnlyFilterEnabled getter should return true.
+    assertTrue(filteredVolumeManager.isFuseBoxOnlyFilterEnabled);
+
     // Check: filteredVolumeManager.volumeInfoList should have 3 volumes.
     assertEquals(3, filteredVolumeManager.volumeInfoList.length);
 
diff --git a/ui/gl/delegated_ink_point_renderer_gpu_unittest.cc b/ui/gl/delegated_ink_point_renderer_gpu_unittest.cc
index 12d4fe0..a1eaa516 100644
--- a/ui/gl/delegated_ink_point_renderer_gpu_unittest.cc
+++ b/ui/gl/delegated_ink_point_renderer_gpu_unittest.cc
@@ -97,8 +97,8 @@
  protected:
   void SetUp() override {
     // Without this, the following check always fails.
-    display_ = gl::init::InitializeGLNoExtensionsOneOff(/*init_bindings=*/true,
-                                                        /*system_device_id=*/0);
+    gl::init::InitializeGLNoExtensionsOneOff(/*init_bindings=*/true,
+                                             /*system_device_id=*/0);
     if (!gl::DirectCompositionSurfaceWin::GetDirectCompositionDevice()) {
       LOG(WARNING)
           << "GL implementation not using DirectComposition, skipping test.";
@@ -124,7 +124,7 @@
     context_ = nullptr;
     if (surface_)
       DestroySurface(std::move(surface_));
-    gl::init::ShutdownGL(display_, false);
+    gl::init::ShutdownGL(false);
   }
 
  private:
@@ -164,7 +164,6 @@
   HWND parent_window_;
   scoped_refptr<DirectCompositionSurfaceWin> surface_;
   scoped_refptr<GLContext> context_;
-  GLDisplay* display_ = nullptr;
 
   // Used as a reference when making DelegatedInkMetadatas based on previously
   // sent points.
diff --git a/ui/gl/direct_composition_surface_win.cc b/ui/gl/direct_composition_surface_win.cc
index 480c380..6c524088 100644
--- a/ui/gl/direct_composition_surface_win.cc
+++ b/ui/gl/direct_composition_surface_win.cc
@@ -410,7 +410,7 @@
 }
 
 // static
-void DirectCompositionSurfaceWin::InitializeOneOff(GLDisplayEGL* display) {
+void DirectCompositionSurfaceWin::InitializeOneOff() {
   DCHECK(!g_dcomp_device);
 
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -431,7 +431,7 @@
 
   // EGL_KHR_no_config_context surface compatibility is required to be able to
   // MakeCurrent with the default pbuffer surface.
-  if (!display->IsEGLNoConfigContextSupported()) {
+  if (!GLSurfaceEGL::GetGLDisplayEGL()->IsEGLNoConfigContextSupported()) {
     DLOG(ERROR) << "EGL_KHR_no_config_context not supported";
     return;
   }
diff --git a/ui/gl/direct_composition_surface_win.h b/ui/gl/direct_composition_surface_win.h
index 0e2a094..beb4172 100644
--- a/ui/gl/direct_composition_surface_win.h
+++ b/ui/gl/direct_composition_surface_win.h
@@ -60,7 +60,7 @@
   DirectCompositionSurfaceWin& operator=(const DirectCompositionSurfaceWin&) =
       delete;
 
-  static void InitializeOneOff(GLDisplayEGL* display);
+  static void InitializeOneOff();
   static void ShutdownOneOff();
 
   static const Microsoft::WRL::ComPtr<IDCompositionDevice2>&
diff --git a/ui/gl/direct_composition_surface_win_unittest.cc b/ui/gl/direct_composition_surface_win_unittest.cc
index a7b6ec9..67ede44 100644
--- a/ui/gl/direct_composition_surface_win_unittest.cc
+++ b/ui/gl/direct_composition_surface_win_unittest.cc
@@ -123,8 +123,8 @@
     fake_power_monitor_source_.SetOnBatteryPower(true);
 
     // Without this, the following check always fails.
-    display_ = gl::init::InitializeGLNoExtensionsOneOff(
-        /*init_bindings=*/true, /*system_device_id=*/0);
+    gl::init::InitializeGLNoExtensionsOneOff(/*init_bindings=*/true,
+                                             /*system_device_id=*/0);
     if (!DirectCompositionSurfaceWin::GetDirectCompositionDevice()) {
       LOG(WARNING) << "DirectComposition not supported, skipping test.";
       return;
@@ -142,7 +142,7 @@
     context_ = nullptr;
     if (surface_)
       DestroySurface(std::move(surface_));
-    gl::init::ShutdownGL(display_, false);
+    gl::init::ShutdownGL(false);
   }
 
   scoped_refptr<DirectCompositionSurfaceWin>
@@ -176,7 +176,6 @@
   scoped_refptr<DirectCompositionSurfaceWin> surface_;
   scoped_refptr<GLContext> context_;
   base::test::ScopedPowerMonitorTestSource fake_power_monitor_source_;
-  GLDisplay* display_ = nullptr;
 };
 
 TEST_F(DirectCompositionSurfaceTest, TestMakeCurrent) {
diff --git a/ui/gl/egl_api_unittest.cc b/ui/gl/egl_api_unittest.cc
index d6b8588..ffd94d0 100644
--- a/ui/gl/egl_api_unittest.cc
+++ b/ui/gl/egl_api_unittest.cc
@@ -18,7 +18,6 @@
   void SetUp() override {
     fake_client_extension_string_ = "";
     fake_extension_string_ = "";
-    display_ = nullptr;
 
     g_driver_egl.fn.eglInitializeFn = &FakeInitialize;
     g_driver_egl.fn.eglTerminateFn = &FakeTerminate;
@@ -36,7 +35,7 @@
   }
 
   void TearDown() override {
-    init::ShutdownGL(display_, false);
+    init::ShutdownGL(false);
     api_.reset(nullptr);
 
     fake_client_extension_string_ = "";
@@ -51,8 +50,8 @@
       SetDisabledExtensionsEGL(disabled_extensions);
     }
     g_driver_egl.InitializeClientExtensionBindings();
-    display_ = GLSurfaceEGL::InitializeDisplay(
-        EGLDisplayPlatform(EGL_DEFAULT_DISPLAY), /*system_device_id=*/0);
+    GLSurfaceEGL::InitializeDisplay(EGLDisplayPlatform(EGL_DEFAULT_DISPLAY),
+                                    /*system_device_id=*/0);
     g_driver_egl.InitializeExtensionBindings();
   }
 
@@ -109,7 +108,6 @@
   static const char* fake_extension_string_;
   static const char* fake_client_extension_string_;
 
-  GLDisplay* display_ = nullptr;
   std::unique_ptr<RealEGLApi> api_;
 };
 
diff --git a/ui/gl/gl_egl_api_implementation.cc b/ui/gl/gl_egl_api_implementation.cc
index 0261916c..20300b21 100644
--- a/ui/gl/gl_egl_api_implementation.cc
+++ b/ui/gl/gl_egl_api_implementation.cc
@@ -134,8 +134,8 @@
   g_current_egl_context->SetDisabledExtensions(disabled_extensions);
 }
 
-bool InitializeExtensionSettingsOneOffEGL(GLDisplayEGL* display) {
-  return GLSurfaceEGL::InitializeExtensionSettingsOneOff(display);
+bool InitializeExtensionSettingsOneOffEGL() {
+  return GLSurfaceEGL::InitializeExtensionSettingsOneOff();
 }
 
 }  // namespace gl
diff --git a/ui/gl/gl_egl_api_implementation.h b/ui/gl/gl_egl_api_implementation.h
index 9dace80..e11d0dd 100644
--- a/ui/gl/gl_egl_api_implementation.h
+++ b/ui/gl/gl_egl_api_implementation.h
@@ -11,7 +11,6 @@
 
 #include "base/memory/raw_ptr.h"
 #include "ui/gl/gl_bindings.h"
-#include "ui/gl/gl_display.h"
 #include "ui/gl/gl_export.h"
 
 namespace gl {
@@ -22,7 +21,7 @@
 GL_EXPORT void ClearBindingsEGL();
 GL_EXPORT bool GetGLWindowSystemBindingInfoEGL(GLWindowSystemBindingInfo* info);
 GL_EXPORT void SetDisabledExtensionsEGL(const std::string& disabled_extensions);
-GL_EXPORT bool InitializeExtensionSettingsOneOffEGL(GLDisplayEGL* display);
+GL_EXPORT bool InitializeExtensionSettingsOneOffEGL();
 
 class GL_EXPORT EGLApiBase : public EGLApi {
  public:
diff --git a/ui/gl/gl_surface_egl.cc b/ui/gl/gl_surface_egl.cc
index de30d9b4..d3df5378 100644
--- a/ui/gl/gl_surface_egl.cc
+++ b/ui/gl/gl_surface_egl.cc
@@ -185,6 +185,8 @@
 
 namespace gl {
 
+bool GLSurfaceEGL::initialized_ = false;
+
 namespace {
 
 class EGLGpuSwitchingObserver;
@@ -992,39 +994,35 @@
 }
 
 // static
-GLDisplayEGL* GLSurfaceEGL::InitializeOneOff(EGLDisplayPlatform native_display,
-                                             uint64_t system_device_id) {
-  GLDisplayEGL* display =
-      GLDisplayManagerEGL::GetInstance()->GetDisplay(system_device_id);
-  if (display->GetDisplay() == EGL_NO_DISPLAY) {
-    // Must be called before InitializeDisplay().
-    g_driver_egl.InitializeClientExtensionBindings();
+bool GLSurfaceEGL::InitializeOneOff(EGLDisplayPlatform native_display,
+                                    uint64_t system_device_id) {
+  if (initialized_)
+    return true;
 
-    display = InitializeDisplay(native_display, system_device_id);
-    if (display->GetDisplay() == EGL_NO_DISPLAY)
-      return nullptr;
+  // Must be called before InitializeDisplay().
+  g_driver_egl.InitializeClientExtensionBindings();
 
-    // Must be called after InitializeDisplay().
-    g_driver_egl.InitializeExtensionBindings();
+  GLDisplayEGL* display = InitializeDisplay(native_display, system_device_id);
+  if (display->GetDisplay() == EGL_NO_DISPLAY)
+    return false;
 
-    InitializeOneOffCommon(display);
-  }
-  return display;
+  // Must be called after InitializeDisplay().
+  g_driver_egl.InitializeExtensionBindings();
+
+  return InitializeOneOffCommon(display);
 }
 
 // static
-GLDisplayEGL* GLSurfaceEGL::InitializeOneOffForTesting() {
+bool GLSurfaceEGL::InitializeOneOffForTesting() {
   g_driver_egl.InitializeClientExtensionBindings();
-  GLDisplayEGL* display =
-      GLDisplayManagerEGL::GetInstance()->GetDisplay(GpuPreference::kDefault);
+  GLDisplayEGL* display = GetGLDisplayEGL();
   display->SetDisplay(eglGetCurrentDisplay());
   g_driver_egl.InitializeExtensionBindings();
-  InitializeOneOffCommon(display);
-  return display;
+  return InitializeOneOffCommon(display);
 }
 
 // static
-void GLSurfaceEGL::InitializeOneOffCommon(GLDisplayEGL* display) {
+bool GLSurfaceEGL::InitializeOneOffCommon(GLDisplayEGL* display) {
   display->egl_client_extensions =
       eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
   display->egl_extensions =
@@ -1163,25 +1161,27 @@
     ui::GpuSwitchingManager::GetInstance()->AddObserver(
         g_egl_gpu_switching_observer);
   }
+
+  initialized_ = true;
+  return true;
 }
 
 // static
-bool GLSurfaceEGL::InitializeExtensionSettingsOneOff(GLDisplayEGL* display) {
-  DCHECK(display);
-  if (display->GetDisplay() == EGL_NO_DISPLAY)
+bool GLSurfaceEGL::InitializeExtensionSettingsOneOff() {
+  if (!initialized_)
     return false;
   g_driver_egl.UpdateConditionalExtensionBindings();
-  display->egl_client_extensions =
+  GetGLDisplayEGL()->egl_client_extensions =
       eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
-  display->egl_extensions =
-      eglQueryString(display->GetDisplay(), EGL_EXTENSIONS);
+  GetGLDisplayEGL()->egl_extensions =
+      eglQueryString(GetGLDisplayEGL()->GetDisplay(), EGL_EXTENSIONS);
 
   return true;
 }
 
 // static
-void GLSurfaceEGL::ShutdownOneOff(GLDisplayEGL* display) {
-  if (!display || display->GetDisplay() == EGL_NO_DISPLAY) {
+void GLSurfaceEGL::ShutdownOneOff() {
+  if (!initialized_) {
     return;
   }
 
@@ -1191,10 +1191,13 @@
     delete g_egl_gpu_switching_observer;
     g_egl_gpu_switching_observer = nullptr;
   }
+  GLDisplayEGL* display = GetGLDisplayEGL();
   angle::ResetPlatform(display->GetDisplay());
-  DCHECK(g_driver_egl.fn.eglTerminateFn);
-  eglTerminate(display->GetDisplay());
-  display->SetDisplay(EGL_NO_DISPLAY);
+  if (display->GetDisplay() != EGL_NO_DISPLAY) {
+    DCHECK(g_driver_egl.fn.eglTerminateFn);
+    eglTerminate(display->GetDisplay());
+    display->SetDisplay(EGL_NO_DISPLAY);
+  }
 
   display->egl_client_extensions = nullptr;
   display->egl_extensions = nullptr;
@@ -1211,6 +1214,8 @@
   display->egl_display_texture_share_group_supported = false;
   display->egl_create_context_client_arrays_supported = false;
   display->egl_angle_feature_control_supported = false;
+
+  initialized_ = false;
 }
 
 GLSurfaceEGL::~GLSurfaceEGL() = default;
@@ -1220,8 +1225,7 @@
 // static
 GLDisplayEGL* GLSurfaceEGL::InitializeDisplay(EGLDisplayPlatform native_display,
                                               uint64_t system_device_id) {
-  GLDisplayEGL* gl_display =
-      GLDisplayManagerEGL::GetInstance()->GetDisplay(system_device_id);
+  GLDisplayEGL* gl_display = GetGLDisplayEGL();
   if (gl_display->GetDisplay() != EGL_NO_DISPLAY) {
     return gl_display;
   }
@@ -1308,17 +1312,17 @@
 
   for (size_t disp_index = 0; disp_index < init_displays.size(); ++disp_index) {
     DisplayType display_type = init_displays[disp_index];
-    EGLDisplay egl_display = GetDisplayFromType(
+    EGLDisplay display = GetDisplayFromType(
         display_type, gl_display, enabled_angle_features,
         disabled_angle_features, disable_all_angle_features, system_device_id);
-    if (egl_display == EGL_NO_DISPLAY) {
+    if (display == EGL_NO_DISPLAY) {
       LOG(ERROR) << "EGL display query failed with error "
                  << GetLastEGLErrorString();
     }
 
     // Init ANGLE platform now that we have the global display.
     if (supports_angle) {
-      if (!angle::InitializePlatform(egl_display)) {
+      if (!angle::InitializePlatform(display)) {
         LOG(ERROR) << "ANGLE Platform initialization failed.";
       }
 
@@ -1334,7 +1338,7 @@
                           ->MaybeGetScopedDisplayUnsetForVulkan();
     }
 
-    if (!eglInitialize(egl_display, nullptr, nullptr)) {
+    if (!eglInitialize(display, nullptr, nullptr)) {
       bool is_last = disp_index == init_displays.size() - 1;
 
       LOG(ERROR) << "eglInitialize " << DisplayTypeString(display_type)
@@ -1357,7 +1361,7 @@
 
     UMA_HISTOGRAM_ENUMERATION("GPU.EGLDisplayType", display_type,
                               DISPLAY_TYPE_MAX);
-    gl_display->SetDisplay(egl_display);
+    gl_display->SetDisplay(display);
     gl_display->display_type = display_type;
     break;
   }
@@ -1388,7 +1392,7 @@
   DCHECK(!surface_);
   format_ = format;
 
-  if (display_->GetDisplay() == EGL_NO_DISPLAY) {
+  if (!display_->GetDisplay()) {
     LOG(ERROR) << "Trying to create surface with invalid display.";
     return false;
   }
diff --git a/ui/gl/gl_surface_egl.h b/ui/gl/gl_surface_egl.h
index 56d276e..e53b967 100644
--- a/ui/gl/gl_surface_egl.h
+++ b/ui/gl/gl_surface_egl.h
@@ -61,15 +61,11 @@
 
   // |system_device_id| specifies which GPU to use on a multi-GPU system.
   // If its value is 0, use the default GPU of the system.
-  // Calling this functionm a second time on the same |system_device_id|
-  // is a no-op and returns the same GLDisplayEGL.
-  // TODO(https://crbug.com/1251724): This will be called once per display
-  // when Chrome begins to support multi-gpu rendering.
-  static GLDisplayEGL* InitializeOneOff(EGLDisplayPlatform native_display,
-                                        uint64_t system_device_id);
-  static GLDisplayEGL* InitializeOneOffForTesting();
-  static bool InitializeExtensionSettingsOneOff(GLDisplayEGL* display);
-  static void ShutdownOneOff(GLDisplayEGL* display);
+  static bool InitializeOneOff(EGLDisplayPlatform native_display,
+                               uint64_t system_device_id);
+  static bool InitializeOneOffForTesting();
+  static bool InitializeExtensionSettingsOneOff();
+  static void ShutdownOneOff();
   // |system_device_id| specifies which GPU to use on a multi-GPU system.
   // If its value is 0, use the default GPU of the system.
   static GLDisplayEGL* InitializeDisplay(EGLDisplayPlatform native_display,
@@ -83,7 +79,8 @@
   GLDisplayEGL* display_ = nullptr;
 
  private:
-  static void InitializeOneOffCommon(GLDisplayEGL* display);
+  static bool InitializeOneOffCommon(GLDisplayEGL* display);
+  static bool initialized_;
 };
 
 // Encapsulates an EGL surface bound to a view.
diff --git a/ui/gl/gl_surface_egl_unittest.cc b/ui/gl/gl_surface_egl_unittest.cc
index c27bef3..dabd89c 100644
--- a/ui/gl/gl_surface_egl_unittest.cc
+++ b/ui/gl/gl_surface_egl_unittest.cc
@@ -32,18 +32,15 @@
  protected:
   void SetUp() override {
 #if BUILDFLAG(IS_WIN)
-    display_ = GLSurfaceTestSupport::InitializeOneOffImplementation(
+    GLSurfaceTestSupport::InitializeOneOffImplementation(
         GLImplementationParts(kGLImplementationEGLANGLE), true);
 #else
-    display_ = GLSurfaceTestSupport::InitializeOneOffImplementation(
+    GLSurfaceTestSupport::InitializeOneOffImplementation(
         GLImplementationParts(kGLImplementationEGLGLES2), true);
 #endif
   }
 
-  void TearDown() override { GLSurfaceTestSupport::ShutdownGL(display_); }
-
- private:
-  GLDisplay* display_ = nullptr;
+  void TearDown() override { gl::init::ShutdownGL(false); }
 };
 
 #if !defined(MEMORY_SANITIZER)
diff --git a/ui/gl/gpu_timing_unittest.cc b/ui/gl/gpu_timing_unittest.cc
index 096b52e5..0b33a2ee 100644
--- a/ui/gl/gpu_timing_unittest.cc
+++ b/ui/gl/gpu_timing_unittest.cc
@@ -39,8 +39,8 @@
     context_ = nullptr;
     surface_ = nullptr;
     if (setup_) {
-      MockGLInterface::SetGLInterface(nullptr);
-      GLSurfaceTestSupport::ShutdownGL(display_);
+      MockGLInterface::SetGLInterface(NULL);
+      init::ShutdownGL(false);
     }
     setup_ = false;
     cpu_time_bounded_ = false;
@@ -51,7 +51,7 @@
   void SetupGLContext(const char* gl_version, const char* gl_extensions) {
     ASSERT_FALSE(setup_) << "Cannot setup GL context twice.";
     SetGLGetProcAddressProc(MockGLInterface::GetGLProcAddress);
-    display_ = GLSurfaceTestSupport::InitializeOneOffWithMockBindings();
+    GLSurfaceTestSupport::InitializeOneOffWithMockBindings();
     gl_ = std::make_unique<::testing::StrictMock<MockGLInterface>>();
     MockGLInterface::SetGLInterface(gl_.get());
 
@@ -86,7 +86,6 @@
   scoped_refptr<GLContextStub> context_;
   scoped_refptr<GLSurfaceStub> surface_;
   GPUTimingFake gpu_timing_fake_queries_;
-  GLDisplay* display_ = nullptr;
 };
 
 TEST_F(GPUTimingTest, FakeTimerTest) {
diff --git a/ui/gl/init/gl_factory.cc b/ui/gl/init/gl_factory.cc
index 70fdfb35..01b8dd9 100644
--- a/ui/gl/init/gl_factory.cc
+++ b/ui/gl/init/gl_factory.cc
@@ -15,7 +15,6 @@
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
-#include "ui/gl/gl_display_manager.h"
 #include "ui/gl/gl_share_group.h"
 #include "ui/gl/gl_surface.h"
 #include "ui/gl/gl_utils.h"
@@ -132,8 +131,8 @@
   return GLImplementationParts(kGLImplementationNone);
 }
 
-GLDisplay* InitializeGLOneOffPlatformHelper(bool init_extensions,
-                                            uint64_t system_device_id) {
+bool InitializeGLOneOffPlatformHelper(bool init_extensions,
+                                      uint64_t system_device_id) {
   TRACE_EVENT1("gpu,startup", "gl::init::InitializeGLOneOffPlatformHelper",
                "init_extensions", init_extensions);
 
@@ -148,30 +147,26 @@
 
 }  // namespace
 
-GLDisplay* InitializeGLOneOff(uint64_t system_device_id) {
+bool InitializeGLOneOff(uint64_t system_device_id) {
   TRACE_EVENT0("gpu,startup", "gl::init::InitializeOneOff");
 
   if (!InitializeStaticGLBindingsOneOff())
-    return nullptr;
-  if (GetGLImplementation() == kGLImplementationDisabled) {
-    return GLDisplayManagerEGL::GetInstance()->GetDisplay(
-        GpuPreference::kDefault);
-  }
+    return false;
+  if (GetGLImplementation() == kGLImplementationDisabled)
+    return true;
 
   return InitializeGLOneOffPlatformHelper(true, system_device_id);
 }
 
-GLDisplay* InitializeGLNoExtensionsOneOff(bool init_bindings,
-                                          uint64_t system_device_id) {
+bool InitializeGLNoExtensionsOneOff(bool init_bindings,
+                                    uint64_t system_device_id) {
   TRACE_EVENT1("gpu,startup", "gl::init::InitializeNoExtensionsOneOff",
                "init_bindings", init_bindings);
   if (init_bindings) {
     if (!InitializeStaticGLBindingsOneOff())
-      return nullptr;
-    if (GetGLImplementation() == kGLImplementationDisabled) {
-      return GLDisplayManagerEGL::GetInstance()->GetDisplay(
-          GpuPreference::kDefault);
-    }
+      return false;
+    if (GetGLImplementation() == kGLImplementationDisabled)
+      return true;
   }
 
   return InitializeGLOneOffPlatformHelper(false, system_device_id);
@@ -201,51 +196,48 @@
 
   bool initialized = InitializeStaticGLBindings(impl);
   if (!initialized && fallback_to_software_gl) {
-    ShutdownGL(nullptr, /*due_to_fallback*/ true);
+    ShutdownGL(/*due_to_fallback*/ true);
     initialized = InitializeStaticGLBindings(GetSoftwareGLImplementation());
   }
   if (!initialized) {
-    ShutdownGL(nullptr, /*due_to_fallback*/ false);
+    ShutdownGL(/*due_to_fallback*/ false);
     return false;
   }
   return true;
 }
 
-GLDisplay* InitializeGLOneOffPlatformImplementation(
-    bool fallback_to_software_gl,
-    bool disable_gl_drawing,
-    bool init_extensions,
-    uint64_t system_device_id) {
+bool InitializeGLOneOffPlatformImplementation(bool fallback_to_software_gl,
+                                              bool disable_gl_drawing,
+                                              bool init_extensions,
+                                              uint64_t system_device_id) {
   if (IsSoftwareGLImplementation(GetGLImplementationParts()))
     fallback_to_software_gl = false;
 
-  GLDisplay* display = InitializeGLOneOffPlatform(system_device_id);
-  bool initialized = !!display;
+  bool initialized = InitializeGLOneOffPlatform(system_device_id);
   if (!initialized && fallback_to_software_gl) {
-    ShutdownGL(nullptr, /*due_to_fallback=*/true);
-    if (InitializeStaticGLBindings(GetSoftwareGLImplementation())) {
-      display = InitializeGLOneOffPlatform(system_device_id);
-      initialized = !!display;
-    }
+    ShutdownGL(/*due_to_fallback*/ true);
+    initialized = InitializeStaticGLBindings(GetSoftwareGLImplementation()) &&
+                  InitializeGLOneOffPlatform(system_device_id);
   }
   if (initialized && init_extensions) {
-    initialized = InitializeExtensionSettingsOneOffPlatform(display);
+    initialized = InitializeExtensionSettingsOneOffPlatform();
   }
 
-  if (!initialized) {
-    ShutdownGL(display, false);
-    return nullptr;
-  }
+  if (!initialized)
+    ShutdownGL(false);
 
-  DVLOG(1) << "Using " << GetGLImplementationGLName(GetGLImplementationParts())
-           << " GL implementation.";
-  if (disable_gl_drawing)
-    InitializeNullDrawGLBindings();
-  return display;
+  if (initialized) {
+    DVLOG(1) << "Using "
+             << GetGLImplementationGLName(GetGLImplementationParts())
+             << " GL implementation.";
+    if (disable_gl_drawing)
+      InitializeNullDrawGLBindings();
+  }
+  return initialized;
 }
 
-void ShutdownGL(GLDisplay* display, bool due_to_fallback) {
-  ShutdownGLPlatform(display);
+void ShutdownGL(bool due_to_fallback) {
+  ShutdownGLPlatform();
 
   UnloadGLNativeLibraries(due_to_fallback);
   SetGLImplementation(kGLImplementationNone);
diff --git a/ui/gl/init/gl_factory.h b/ui/gl/init/gl_factory.h
index 218f4d9..bf6765f 100644
--- a/ui/gl/init/gl_factory.h
+++ b/ui/gl/init/gl_factory.h
@@ -12,7 +12,6 @@
 #include "base/memory/ref_counted.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/native_widget_types.h"
-#include "ui/gl/gl_display.h"
 #include "ui/gl/gl_implementation.h"
 #include "ui/gl/gl_surface_format.h"
 #include "ui/gl/gpu_preference.h"
@@ -36,14 +35,13 @@
 // Initializes GL bindings and extension settings.
 // |system_device_id| specifies which GPU to use on a multi-GPU system.
 // If its value is 0, use the default GPU of the system.
-GL_INIT_EXPORT GLDisplay* InitializeGLOneOff(uint64_t system_device_id);
+GL_INIT_EXPORT bool InitializeGLOneOff(uint64_t system_device_id);
 
 // Initializes GL bindings without initializing extension settings.
 // |system_device_id| specifies which GPU to use on a multi-GPU system.
 // If its value is 0, use the default GPU of the system.
-GL_INIT_EXPORT GLDisplay* InitializeGLNoExtensionsOneOff(
-    bool init_bindings,
-    uint64_t system_device_id);
+GL_INIT_EXPORT bool InitializeGLNoExtensionsOneOff(bool init_bindings,
+                                                   uint64_t system_device_id);
 
 // Initializes GL bindings - load dlls and get proc address according to gl
 // command line switch.
@@ -51,8 +49,7 @@
 
 // Initialize plaiform dependent extension settings, including bindings,
 // capabilities, etc.
-GL_INIT_EXPORT bool InitializeExtensionSettingsOneOffPlatform(
-    GLDisplay* display);
+GL_INIT_EXPORT bool InitializeExtensionSettingsOneOffPlatform();
 
 // Initializes GL bindings using the provided parameters. This might be required
 // for use in tests.
@@ -65,15 +62,14 @@
 // successfully.
 // |system_device_id| specifies which GPU to use on a multi-GPU system.
 // If its value is 0, use the default GPU of the system.
-GL_INIT_EXPORT GLDisplay* InitializeGLOneOffPlatformImplementation(
+GL_INIT_EXPORT bool InitializeGLOneOffPlatformImplementation(
     bool fallback_to_software_gl,
     bool disable_gl_drawing,
     bool init_extensions,
     uint64_t system_device_id);
 
 // Clears GL bindings and resets GL implementation.
-// Calling this function a second time on the same |display| is a no-op.
-GL_INIT_EXPORT void ShutdownGL(GLDisplay* display, bool due_to_fallback);
+GL_INIT_EXPORT void ShutdownGL(bool due_to_fallback);
 
 // Return information about the GL window system binding implementation (e.g.,
 // EGL, GLX, WGL). Returns true if the information was retrieved successfully.
diff --git a/ui/gl/init/gl_factory_android.cc b/ui/gl/init/gl_factory_android.cc
index c508a04e..222e612 100644
--- a/ui/gl/init/gl_factory_android.cc
+++ b/ui/gl/init/gl_factory_android.cc
@@ -176,14 +176,13 @@
   }
 }
 
-bool InitializeExtensionSettingsOneOffPlatform(GLDisplay* display) {
+bool InitializeExtensionSettingsOneOffPlatform() {
   GLImplementation implementation = GetGLImplementation();
   DCHECK_NE(kGLImplementationNone, implementation);
   switch (implementation) {
     case kGLImplementationEGLGLES2:
     case kGLImplementationEGLANGLE:
-      return InitializeExtensionSettingsOneOffEGL(
-          static_cast<GLDisplayEGL*>(display));
+      return InitializeExtensionSettingsOneOffEGL();
     case kGLImplementationMockGL:
     case kGLImplementationStubGL:
       return true;
diff --git a/ui/gl/init/gl_factory_mac.cc b/ui/gl/init/gl_factory_mac.cc
index 4de2742..a70f8631 100644
--- a/ui/gl/init/gl_factory_mac.cc
+++ b/ui/gl/init/gl_factory_mac.cc
@@ -166,7 +166,7 @@
   // TODO(zmo): Implement this if needs arise.
 }
 
-bool InitializeExtensionSettingsOneOffPlatform(GLDisplay* display) {
+bool InitializeExtensionSettingsOneOffPlatform() {
   GLImplementation implementation = GetGLImplementation();
   DCHECK_NE(kGLImplementationNone, implementation);
   // TODO(zmo): Implement this if needs arise.
diff --git a/ui/gl/init/gl_factory_ozone.cc b/ui/gl/init/gl_factory_ozone.cc
index 57b4c97..7259e7b 100644
--- a/ui/gl/init/gl_factory_ozone.cc
+++ b/ui/gl/init/gl_factory_ozone.cc
@@ -120,9 +120,9 @@
   }
 }
 
-bool InitializeExtensionSettingsOneOffPlatform(GLDisplay* display) {
+bool InitializeExtensionSettingsOneOffPlatform() {
   if (HasGLOzone())
-    return GetGLOzone()->InitializeExtensionSettingsOneOffPlatform(display);
+    return GetGLOzone()->InitializeExtensionSettingsOneOffPlatform();
 
   switch (GetGLImplementation()) {
     case kGLImplementationMockGL:
diff --git a/ui/gl/init/gl_factory_win.cc b/ui/gl/init/gl_factory_win.cc
index f61749a..3aa35bb 100644
--- a/ui/gl/init/gl_factory_win.cc
+++ b/ui/gl/init/gl_factory_win.cc
@@ -115,13 +115,12 @@
   }
 }
 
-bool InitializeExtensionSettingsOneOffPlatform(GLDisplay* display) {
+bool InitializeExtensionSettingsOneOffPlatform() {
   GLImplementation implementation = GetGLImplementation();
   DCHECK_NE(kGLImplementationNone, implementation);
   switch (implementation) {
     case kGLImplementationEGLANGLE:
-      return InitializeExtensionSettingsOneOffEGL(
-          static_cast<GLDisplayEGL*>(display));
+      return InitializeExtensionSettingsOneOffEGL();
     case kGLImplementationMockGL:
     case kGLImplementationStubGL:
       return true;
diff --git a/ui/gl/init/gl_initializer.h b/ui/gl/init/gl_initializer.h
index 12c30d4..06445b3 100644
--- a/ui/gl/init/gl_initializer.h
+++ b/ui/gl/init/gl_initializer.h
@@ -6,7 +6,6 @@
 #define UI_GL_INIT_GL_INITIALIZER_H_
 
 #include "ui/gl/buildflags.h"
-#include "ui/gl/gl_display.h"
 #include "ui/gl/gl_implementation.h"
 
 namespace gl {
@@ -21,7 +20,7 @@
 // InitializeGLOneOffPlatformImplementation() instead.
 // |system_device_id| specifies which GPU to use on a multi-GPU system.
 // If its value is 0, use the default GPU of the system.
-GLDisplay* InitializeGLOneOffPlatform(uint64_t system_device_id);
+bool InitializeGLOneOffPlatform(uint64_t system_device_id);
 
 // Initializes a particular GL implementation.
 bool InitializeStaticGLBindings(GLImplementationParts implementation);
@@ -31,8 +30,7 @@
 #endif  // BUILDFLAG(USE_STATIC_ANGLE)
 
 // Clears GL bindings for all implementations supported by platform.
-// Calling this function a second time on the same |display| is a no-op.
-void ShutdownGLPlatform(GLDisplay* display);
+void ShutdownGLPlatform();
 
 }  // namespace init
 }  // namespace gl
diff --git a/ui/gl/init/gl_initializer_android.cc b/ui/gl/init/gl_initializer_android.cc
index 5abd2d9..d26c601 100644
--- a/ui/gl/init/gl_initializer_android.cc
+++ b/ui/gl/init/gl_initializer_android.cc
@@ -10,7 +10,6 @@
 #include "base/logging.h"
 #include "base/native_library.h"
 #include "ui/gl/gl_bindings.h"
-#include "ui/gl/gl_display_manager.h"
 #include "ui/gl/gl_egl_api_implementation.h"
 #include "ui/gl/gl_gl_api_implementation.h"
 #include "ui/gl/gl_surface_egl.h"
@@ -77,20 +76,18 @@
 
 }  // namespace
 
-GLDisplay* InitializeGLOneOffPlatform(uint64_t system_device_id) {
+bool InitializeGLOneOffPlatform(uint64_t system_device_id) {
   switch (GetGLImplementation()) {
     case kGLImplementationEGLGLES2:
-    case kGLImplementationEGLANGLE: {
-      GLDisplay* display = GLSurfaceEGL::InitializeOneOff(
-          EGLDisplayPlatform(EGL_DEFAULT_DISPLAY), system_device_id);
-      if (!display) {
+    case kGLImplementationEGLANGLE:
+      if (!GLSurfaceEGL::InitializeOneOff(
+              EGLDisplayPlatform(EGL_DEFAULT_DISPLAY), system_device_id)) {
         LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed.";
-        return nullptr;
+        return false;
       }
-      return display;
-    }
+      return true;
     default:
-      return GLDisplayManagerEGL::GetInstance()->GetDisplay(system_device_id);
+      return true;
   }
 }
 
@@ -116,8 +113,8 @@
   return false;
 }
 
-void ShutdownGLPlatform(GLDisplay* display) {
-  GLSurfaceEGL::ShutdownOneOff(static_cast<GLDisplayEGL*>(display));
+void ShutdownGLPlatform() {
+  GLSurfaceEGL::ShutdownOneOff();
   ClearBindingsEGL();
   ClearBindingsGL();
 }
diff --git a/ui/gl/init/gl_initializer_mac.cc b/ui/gl/init/gl_initializer_mac.cc
index fa9771391..b1fbd1f 100644
--- a/ui/gl/init/gl_initializer_mac.cc
+++ b/ui/gl/init/gl_initializer_mac.cc
@@ -18,7 +18,6 @@
 #include "base/threading/thread_restrictions.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context.h"
-#include "ui/gl/gl_display_manager.h"
 #include "ui/gl/gl_gl_api_implementation.h"
 #include "ui/gl/gl_implementation.h"
 #include "ui/gl/gl_surface.h"
@@ -171,29 +170,28 @@
 
 }  // namespace
 
-GLDisplay* InitializeGLOneOffPlatform(uint64_t system_device_id) {
+bool InitializeGLOneOffPlatform(uint64_t system_device_id) {
   switch (GetGLImplementation()) {
     case kGLImplementationDesktopGL:
     case kGLImplementationDesktopGLCoreProfile:
     case kGLImplementationAppleGL:
       if (!InitializeOneOffForSandbox()) {
         LOG(ERROR) << "GLSurfaceCGL::InitializeOneOff failed.";
+        return false;
       }
-      return GLDisplayManagerEGL::GetInstance()->GetDisplay(system_device_id);
+      return true;
 #if defined(USE_EGL)
     case kGLImplementationEGLGLES2:
-    case kGLImplementationEGLANGLE: {
-      GLDisplay* display = GLSurfaceEGL::InitializeOneOff(EGLDisplayPlatform(0),
-                                                          system_device_id);
-      if (!display) {
+    case kGLImplementationEGLANGLE:
+      if (!GLSurfaceEGL::InitializeOneOff(EGLDisplayPlatform(0),
+                                          system_device_id)) {
         LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed.";
-        return nullptr;
+        return false;
       }
-      return display;
-    }
+      return true;
 #endif  // defined(USE_EGL)
     default:
-      return GLDisplayManagerEGL::GetInstance()->GetDisplay(system_device_id);
+      return true;
   }
 }
 
@@ -231,10 +229,10 @@
   return false;
 }
 
-void ShutdownGLPlatform(GLDisplay* display) {
+void ShutdownGLPlatform() {
   ClearBindingsGL();
 #if defined(USE_EGL)
-  GLSurfaceEGL::ShutdownOneOff(static_cast<GLDisplayEGL*>(display));
+  GLSurfaceEGL::ShutdownOneOff();
   ClearBindingsEGL();
 #endif  // defined(USE_EGL)
 }
diff --git a/ui/gl/init/gl_initializer_ozone.cc b/ui/gl/init/gl_initializer_ozone.cc
index 36c73023..36aef21 100644
--- a/ui/gl/init/gl_initializer_ozone.cc
+++ b/ui/gl/init/gl_initializer_ozone.cc
@@ -7,7 +7,6 @@
 #include "base/check_op.h"
 #include "base/notreached.h"
 #include "ui/gl/gl_bindings.h"
-#include "ui/gl/gl_display_manager.h"
 #include "ui/gl/gl_gl_api_implementation.h"
 #include "ui/gl/gl_surface.h"
 
@@ -20,20 +19,20 @@
 namespace gl {
 namespace init {
 
-GLDisplay* InitializeGLOneOffPlatform(uint64_t system_device_id) {
+bool InitializeGLOneOffPlatform(uint64_t) {
   if (HasGLOzone()) {
     gl::GLDisplayEglUtil::SetInstance(gl::GLDisplayEglUtilOzone::GetInstance());
-    return GetGLOzone()->InitializeGLOneOffPlatform(system_device_id);
+    return GetGLOzone()->InitializeGLOneOffPlatform();
   }
 
   switch (GetGLImplementation()) {
     case kGLImplementationMockGL:
     case kGLImplementationStubGL:
-      return GLDisplayManagerEGL::GetInstance()->GetDisplay(system_device_id);
+      return true;
     default:
       NOTREACHED();
   }
-  return nullptr;
+  return false;
 }
 
 bool InitializeStaticGLBindings(GLImplementationParts implementation) {
@@ -59,9 +58,9 @@
   return false;
 }
 
-void ShutdownGLPlatform(GLDisplay* display) {
+void ShutdownGLPlatform() {
   if (HasGLOzone()) {
-    GetGLOzone()->ShutdownGL(display);
+    GetGLOzone()->ShutdownGL();
     return;
   }
 
diff --git a/ui/gl/init/gl_initializer_win.cc b/ui/gl/init/gl_initializer_win.cc
index 960065c..06798da 100644
--- a/ui/gl/init/gl_initializer_win.cc
+++ b/ui/gl/init/gl_initializer_win.cc
@@ -18,7 +18,6 @@
 #include "base/trace_event/trace_event.h"
 #include "base/win/windows_version.h"
 #include "ui/gl/gl_bindings.h"
-#include "ui/gl/gl_display_manager.h"
 #include "ui/gl/gl_egl_api_implementation.h"
 #include "ui/gl/gl_gl_api_implementation.h"
 #include "ui/gl/gl_surface_egl.h"
@@ -123,27 +122,25 @@
 
 }  // namespace
 
-GLDisplay* InitializeGLOneOffPlatform(uint64_t system_device_id) {
+bool InitializeGLOneOffPlatform(uint64_t system_device_id) {
   VSyncProviderWin::InitializeOneOff();
 
   switch (GetGLImplementation()) {
-    case kGLImplementationEGLANGLE: {
-      GLDisplayEGL* display = GLSurfaceEGL::InitializeOneOff(
-          EGLDisplayPlatform(GetDC(nullptr)), system_device_id);
-      if (!display) {
+    case kGLImplementationEGLANGLE:
+      if (!GLSurfaceEGL::InitializeOneOff(EGLDisplayPlatform(GetDC(nullptr)),
+                                          system_device_id)) {
         LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed.";
-        return nullptr;
+        return false;
       }
-      DirectCompositionSurfaceWin::InitializeOneOff(display);
-      return display;
-    }
+      DirectCompositionSurfaceWin::InitializeOneOff();
+      break;
     case kGLImplementationMockGL:
     case kGLImplementationStubGL:
       break;
     default:
       NOTREACHED();
   }
-  return GLDisplayManagerEGL::GetInstance()->GetDisplay(system_device_id);
+  return true;
 }
 
 bool InitializeStaticGLBindings(GLImplementationParts implementation) {
@@ -173,9 +170,9 @@
   return false;
 }
 
-void ShutdownGLPlatform(GLDisplay* display) {
+void ShutdownGLPlatform() {
   DirectCompositionSurfaceWin::ShutdownOneOff();
-  GLSurfaceEGL::ShutdownOneOff(static_cast<GLDisplayEGL*>(display));
+  GLSurfaceEGL::ShutdownOneOff();
   ClearBindingsEGL();
   ClearBindingsGL();
 }
diff --git a/ui/gl/test/gl_image_test_support.cc b/ui/gl/test/gl_image_test_support.cc
index 81b85cf4..c3d5bb4 100644
--- a/ui/gl/test/gl_image_test_support.cc
+++ b/ui/gl/test/gl_image_test_support.cc
@@ -33,8 +33,6 @@
 }
 }  // namespace
 
-GLDisplay* GLImageTestSupport::display_ = nullptr;
-
 // static
 void GLImageTestSupport::InitializeGL(
     absl::optional<GLImplementationParts> prefered_impl) {
@@ -52,7 +50,7 @@
       prefered_impl ? *prefered_impl : allowed_impls[0];
   DCHECK(impl.IsAllowed(allowed_impls));
 
-  display_ = GLSurfaceTestSupport::InitializeOneOffImplementation(impl, true);
+  GLSurfaceTestSupport::InitializeOneOffImplementation(impl, true);
 #if defined(USE_OZONE)
   // Make sure all the tasks posted to the current task runner by the
   // initialization functions are run before running the tests.
@@ -62,7 +60,7 @@
 
 // static
 void GLImageTestSupport::CleanupGL() {
-  GLSurfaceTestSupport::ShutdownGL(display_);
+  init::ShutdownGL(false);
 }
 
 // static
diff --git a/ui/gl/test/gl_image_test_support.h b/ui/gl/test/gl_image_test_support.h
index 393872f..e427a6b 100644
--- a/ui/gl/test/gl_image_test_support.h
+++ b/ui/gl/test/gl_image_test_support.h
@@ -9,7 +9,6 @@
 
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/gfx/buffer_types.h"
-#include "ui/gl/gl_display.h"
 #include "ui/gl/gl_implementation.h"
 
 namespace gl {
@@ -32,9 +31,6 @@
                                    gfx::BufferFormat format,
                                    const uint8_t color[4],
                                    uint8_t* data);
-
- private:
-  static GLDisplay* display_;
 };
 
 }  // namespace gl
diff --git a/ui/gl/test/gl_surface_test_support.cc b/ui/gl/test/gl_surface_test_support.cc
index 1afadab..22ee46e 100644
--- a/ui/gl/test/gl_surface_test_support.cc
+++ b/ui/gl/test/gl_surface_test_support.cc
@@ -25,8 +25,7 @@
 namespace gl {
 
 namespace {
-
-GLDisplay* InitializeOneOffHelper(bool init_extensions) {
+void InitializeOneOffHelper(bool init_extensions) {
   DCHECK_EQ(kGLImplementationNone, GetGLImplementation());
 
 #if defined(USE_OZONE)
@@ -70,70 +69,70 @@
 
   CHECK(gl::init::InitializeStaticGLBindingsImplementation(
       impl, fallback_to_software_gl));
-  GLDisplay* display = gl::init::InitializeGLOneOffPlatformImplementation(
+  CHECK(gl::init::InitializeGLOneOffPlatformImplementation(
       fallback_to_software_gl, disable_gl_drawing, init_extensions,
-      /*system_device_id=*/0);
-  CHECK(display);
-  return display;
+      /*system_device_id=*/0));
 }
 }  // namespace
 
 // static
-GLDisplay* GLSurfaceTestSupport::InitializeOneOff() {
-  return InitializeOneOffHelper(true);
+void GLSurfaceTestSupport::InitializeOneOff() {
+  InitializeOneOffHelper(true);
 }
 
 // static
-GLDisplay* GLSurfaceTestSupport::InitializeNoExtensionsOneOff() {
-  return InitializeOneOffHelper(false);
+void GLSurfaceTestSupport::InitializeNoExtensionsOneOff() {
+  InitializeOneOffHelper(false);
 }
 
 // static
-GLDisplay* GLSurfaceTestSupport::InitializeOneOffImplementation(
+void GLSurfaceTestSupport::InitializeOneOffImplementation(
     GLImplementationParts impl,
     bool fallback_to_software_gl) {
   DCHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseGL))
       << "kUseGL has not effect in tests";
 
+  // This method may be called multiple times in the same process to set up
+  // bindings in different ways.
+  init::ShutdownGL(false);
+
   bool disable_gl_drawing = false;
   bool init_extensions = true;
 
   CHECK(gl::init::InitializeStaticGLBindingsImplementation(
       impl, fallback_to_software_gl));
-  GLDisplay* display = gl::init::InitializeGLOneOffPlatformImplementation(
+  CHECK(gl::init::InitializeGLOneOffPlatformImplementation(
       fallback_to_software_gl, disable_gl_drawing, init_extensions,
-      /*system_device_id=*/0);
-  CHECK(display);
-  return display;
+      /*system_device_id=*/0));
 }
 
 // static
-GLDisplay* GLSurfaceTestSupport::InitializeOneOffWithMockBindings() {
+void GLSurfaceTestSupport::InitializeOneOffWithMockBindings() {
 #if defined(USE_OZONE)
   ui::OzonePlatform::InitParams params;
   params.single_process = true;
   ui::OzonePlatform::InitializeForGPU(params);
 #endif
 
-  return InitializeOneOffImplementation(
-      GLImplementationParts(kGLImplementationMockGL), false);
+  InitializeOneOffImplementation(GLImplementationParts(kGLImplementationMockGL),
+                                 false);
 }
 
 // static
-GLDisplay* GLSurfaceTestSupport::InitializeOneOffWithStubBindings() {
+void GLSurfaceTestSupport::InitializeOneOffWithStubBindings() {
 #if defined(USE_OZONE)
   ui::OzonePlatform::InitParams params;
   params.single_process = true;
   ui::OzonePlatform::InitializeForGPU(params);
 #endif
 
-  return InitializeOneOffImplementation(
-      GLImplementationParts(kGLImplementationStubGL), false);
+  InitializeOneOffImplementation(GLImplementationParts(kGLImplementationStubGL),
+                                 false);
 }
 
 // static
-void GLSurfaceTestSupport::ShutdownGL(GLDisplay* display) {
-  init::ShutdownGL(display, false);
+void GLSurfaceTestSupport::ShutdownGL() {
+  init::ShutdownGL(false);
 }
 
 }  // namespace gl
diff --git a/ui/gl/test/gl_surface_test_support.h b/ui/gl/test/gl_surface_test_support.h
index ac0db72f..89c662cf 100644
--- a/ui/gl/test/gl_surface_test_support.h
+++ b/ui/gl/test/gl_surface_test_support.h
@@ -5,21 +5,19 @@
 #ifndef UI_GL_TEST_GL_SURFACE_TEST_SUPPORT_H_
 #define UI_GL_TEST_GL_SURFACE_TEST_SUPPORT_H_
 
-#include "ui/gl/gl_display.h"
 #include "ui/gl/gl_implementation.h"
 
 namespace gl {
 
 class GLSurfaceTestSupport {
  public:
-  static GLDisplay* InitializeOneOff();
-  static GLDisplay* InitializeNoExtensionsOneOff();
-  static GLDisplay* InitializeOneOffImplementation(
-      GLImplementationParts impl,
-      bool fallback_to_swiftshader);
-  static GLDisplay* InitializeOneOffWithMockBindings();
-  static GLDisplay* InitializeOneOffWithStubBindings();
-  static void ShutdownGL(GLDisplay* display);
+  static void InitializeOneOff();
+  static void InitializeNoExtensionsOneOff();
+  static void InitializeOneOffImplementation(GLImplementationParts impl,
+                                             bool fallback_to_swiftshader);
+  static void InitializeOneOffWithMockBindings();
+  static void InitializeOneOffWithStubBindings();
+  static void ShutdownGL();
 };
 
 }  // namespace gl
diff --git a/ui/ozone/common/gl_ozone_egl.cc b/ui/ozone/common/gl_ozone_egl.cc
index c7e3707..2034d0a 100644
--- a/ui/ozone/common/gl_ozone_egl.cc
+++ b/ui/ozone/common/gl_ozone_egl.cc
@@ -15,15 +15,13 @@
 
 namespace ui {
 
-gl::GLDisplay* GLOzoneEGL::InitializeGLOneOffPlatform(
-    uint64_t system_device_id) {
-  gl::GLDisplay* display =
-      gl::GLSurfaceEGL::InitializeOneOff(GetNativeDisplay(), system_device_id);
-  if (!display) {
+bool GLOzoneEGL::InitializeGLOneOffPlatform() {
+  if (!gl::GLSurfaceEGL::InitializeOneOff(GetNativeDisplay(),
+                                          /*system_device_id=*/0)) {
     LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed.";
-    return nullptr;
+    return false;
   }
-  return display;
+  return true;
 }
 
 bool GLOzoneEGL::InitializeStaticGLBindings(
@@ -43,14 +41,12 @@
   gl::SetDisabledExtensionsEGL(disabled_extensions);
 }
 
-bool GLOzoneEGL::InitializeExtensionSettingsOneOffPlatform(
-    gl::GLDisplay* display) {
-  return gl::InitializeExtensionSettingsOneOffEGL(
-      static_cast<gl::GLDisplayEGL*>(display));
+bool GLOzoneEGL::InitializeExtensionSettingsOneOffPlatform() {
+  return gl::InitializeExtensionSettingsOneOffEGL();
 }
 
-void GLOzoneEGL::ShutdownGL(gl::GLDisplay* display) {
-  gl::GLSurfaceEGL::ShutdownOneOff(static_cast<gl::GLDisplayEGL*>(display));
+void GLOzoneEGL::ShutdownGL() {
+  gl::GLSurfaceEGL::ShutdownOneOff();
   gl::ClearBindingsGL();
   gl::ClearBindingsEGL();
 }
diff --git a/ui/ozone/common/gl_ozone_egl.h b/ui/ozone/common/gl_ozone_egl.h
index 29d0aa5..11b44340 100644
--- a/ui/ozone/common/gl_ozone_egl.h
+++ b/ui/ozone/common/gl_ozone_egl.h
@@ -24,14 +24,13 @@
   ~GLOzoneEGL() override {}
 
   // GLOzone:
-  gl::GLDisplay* InitializeGLOneOffPlatform(uint64_t system_device_id) override;
+  bool InitializeGLOneOffPlatform() override;
   bool InitializeStaticGLBindings(
       const gl::GLImplementationParts& implementation) override;
   void SetDisabledExtensionsPlatform(
       const std::string& disabled_extensions) override;
-  bool InitializeExtensionSettingsOneOffPlatform(
-      gl::GLDisplay* display) override;
-  void ShutdownGL(gl::GLDisplay* display) override;
+  bool InitializeExtensionSettingsOneOffPlatform() override;
+  void ShutdownGL() override;
   bool GetGLWindowSystemBindingInfo(
       const gl::GLVersionInfo& gl_info,
       gl::GLWindowSystemBindingInfo* info) override;
diff --git a/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc b/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
index e56a894..844bcbc 100644
--- a/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
+++ b/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
@@ -431,12 +431,11 @@
 }
 
 void WaylandToplevelWindow::SetBoundsInPixels(const gfx::Rect& bounds) {
-  if (!shell_toplevel_ || !screen_coordinates_enabled_) {
-    WaylandWindow::SetBoundsInPixels(bounds);
-    return;
+  WaylandWindow::SetBoundsInPixels(bounds);
+  if (shell_toplevel_ && screen_coordinates_enabled_) {
+    gfx::Rect bounds_in_dip = delegate()->ConvertRectToDIP(bounds);
+    shell_toplevel_->RequestWindowBounds(bounds_in_dip);
   }
-  gfx::Rect bounds_in_dip = delegate()->ConvertRectToDIP(bounds);
-  shell_toplevel_->RequestWindowBounds(bounds_in_dip);
 }
 
 void WaylandToplevelWindow::SetOrigin(const gfx::Point& origin) {
diff --git a/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc b/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc
index a2254c4..14d1c94 100644
--- a/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc
+++ b/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc
@@ -299,6 +299,14 @@
     DecorationMode requested_mode) {
   if (!zxdg_toplevel_decoration_ || requested_mode == decoration_mode_)
     return;
+  // TODO(crbug.com/1261321): Server side decoration decoration will not work
+  // when the screen coordinate is enabled.
+  if (SupportsScreenCoordinates() &&
+      requested_mode == DecorationMode::kServerSide) {
+    LOG(WARNING) << "Server side decoration is not supported when window "
+                    "positioning is enabled";
+    return;
+  }
 
   zxdg_toplevel_decoration_v1_set_mode(zxdg_toplevel_decoration_.get(),
                                        ToInt32(requested_mode));
@@ -383,6 +391,9 @@
     LOG(WARNING) << "Output Not found for id=" << id;
     output = connection_->wayland_output_manager()->GetPrimaryOutput();
   }
+  // `output` can be null in unit tests where it doesn't wait for output events.
+  if (!output)
+    return;
   zaura_toplevel_set_window_bounds(aura_toplevel_.get(), bounds.x(), bounds.y(),
                                    bounds.width(), bounds.height(),
                                    output->get_output());
diff --git a/ui/ozone/platform/x11/gl_ozone_glx.cc b/ui/ozone/platform/x11/gl_ozone_glx.cc
index c3c7e62..b40b3c5 100644
--- a/ui/ozone/platform/x11/gl_ozone_glx.cc
+++ b/ui/ozone/platform/x11/gl_ozone_glx.cc
@@ -8,7 +8,6 @@
 #include "build/build_config.h"
 #include "ui/gl/gl_context.h"
 #include "ui/gl/gl_context_glx.h"
-#include "ui/gl/gl_display_manager.h"
 #include "ui/gl/gl_gl_api_implementation.h"
 #include "ui/gl/gl_glx_api_implementation.h"
 #include "ui/gl/gl_surface_glx_x11.h"
@@ -25,15 +24,12 @@
 
 }  // namespace
 
-gl::GLDisplay* GLOzoneGLX::InitializeGLOneOffPlatform(
-    uint64_t system_device_id) {
-  // TODO(https://crbug.com/1251724): GLSurfaceGLX::InitializeOneOff()
-  // should take |system_device_id| and return a GLDisplayX11.
+bool GLOzoneGLX::InitializeGLOneOffPlatform() {
   if (!gl::GLSurfaceGLX::InitializeOneOff()) {
     LOG(ERROR) << "GLSurfaceGLX::InitializeOneOff failed.";
-    return nullptr;
+    return false;
   }
-  return gl::GLDisplayManagerX11::GetInstance()->GetDisplay(system_device_id);
+  return true;
 }
 
 bool GLOzoneGLX::InitializeStaticGLBindings(
@@ -77,12 +73,11 @@
   gl::SetDisabledExtensionsGLX(disabled_extensions);
 }
 
-bool GLOzoneGLX::InitializeExtensionSettingsOneOffPlatform(
-    gl::GLDisplay* display) {
+bool GLOzoneGLX::InitializeExtensionSettingsOneOffPlatform() {
   return gl::InitializeExtensionSettingsOneOffGLX();
 }
 
-void GLOzoneGLX::ShutdownGL(gl::GLDisplay* display) {
+void GLOzoneGLX::ShutdownGL() {
   gl::ClearBindingsGL();
   gl::ClearBindingsGLX();
 }
diff --git a/ui/ozone/platform/x11/gl_ozone_glx.h b/ui/ozone/platform/x11/gl_ozone_glx.h
index 1fb05ff..61d51d5e 100644
--- a/ui/ozone/platform/x11/gl_ozone_glx.h
+++ b/ui/ozone/platform/x11/gl_ozone_glx.h
@@ -19,14 +19,13 @@
 
   ~GLOzoneGLX() override {}
 
-  gl::GLDisplay* InitializeGLOneOffPlatform(uint64_t system_device_id) override;
+  bool InitializeGLOneOffPlatform() override;
   bool InitializeStaticGLBindings(
       const gl::GLImplementationParts& implementation) override;
   void SetDisabledExtensionsPlatform(
       const std::string& disabled_extensions) override;
-  bool InitializeExtensionSettingsOneOffPlatform(
-      gl::GLDisplay* display) override;
-  void ShutdownGL(gl::GLDisplay* display) override;
+  bool InitializeExtensionSettingsOneOffPlatform() override;
+  void ShutdownGL() override;
   bool GetGLWindowSystemBindingInfo(
       const gl::GLVersionInfo& gl_info,
       gl::GLWindowSystemBindingInfo* info) override;
diff --git a/ui/ozone/public/gl_ozone.h b/ui/ozone/public/gl_ozone.h
index ef4ec09e..ccfa309b 100644
--- a/ui/ozone/public/gl_ozone.h
+++ b/ui/ozone/public/gl_ozone.h
@@ -11,7 +11,6 @@
 #include "base/memory/ref_counted.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/native_widget_types.h"
-#include "ui/gl/gl_display.h"
 #include "ui/gl/gl_implementation.h"
 #include "ui/gl/gpu_preference.h"
 
@@ -38,8 +37,7 @@
       const gl::GLImplementationParts& implementation) = 0;
 
   // Performs any one off initialization for GL implementation.
-  virtual gl::GLDisplay* InitializeGLOneOffPlatform(
-      uint64_t system_device_id) = 0;
+  virtual bool InitializeGLOneOffPlatform() = 0;
 
   // Disables the specified extensions in the window system bindings,
   // e.g., GLX, EGL, etc. This is part of the GPU driver bug workarounds
@@ -50,11 +48,10 @@
   // Initializes extension related settings for window system bindings that
   // will be affected by SetDisabledExtensionsPlatform(). This function is
   // called after SetDisabledExtensionsPlatform() to finalize the bindings.
-  virtual bool InitializeExtensionSettingsOneOffPlatform(
-      gl::GLDisplay* display) = 0;
+  virtual bool InitializeExtensionSettingsOneOffPlatform() = 0;
 
   // Clears static GL bindings.
-  virtual void ShutdownGL(gl::GLDisplay* display) = 0;
+  virtual void ShutdownGL() = 0;
 
   // Returns information about the GL window system binding implementation (eg.
   // EGL, GLX, WGL). Returns true if the information was retrieved successfully.