diff --git a/BUILD.gn b/BUILD.gn
index aa2cb7b..3e422d7 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -249,7 +249,6 @@
 
   if (!is_ios && !is_fuchsia) {
     deps += [
-      "//chrome/test:telemetry_perf_unittests",
       "//chrome/test:unit_tests",
       "//components:components_browsertests",
       "//device:device_unittests",
@@ -258,7 +257,9 @@
       "//media/cast:cast_unittests",
       "//third_party/catapult/telemetry:bitmaptools($host_toolchain)",
     ]
-    if (is_android) {
+    if (!is_android) {
+      deps += [ "//chrome/test:telemetry_perf_unittests" ]
+    } else {
       import("//tools/perf/chrome_telemetry_build/android_browser_types.gni")
       foreach(_target_suffix, telemetry_android_browser_target_suffixes) {
         deps += [ "//chrome/test:telemetry_perf_unittests${_target_suffix}" ]
@@ -828,9 +829,10 @@
       "//chrome/browser/vr:vr_common_perftests",
       "//chrome/browser/vr:vr_common_unittests",
       "//chrome/browser/vr:vr_pixeltests",
-      "//tools/perf/contrib/vr_benchmarks:vr_perf_tests",
     ]
-    if (is_android) {
+    if (!is_android) {
+      deps += [ "//tools/perf/contrib/vr_benchmarks:vr_perf_tests" ]
+    } else {
       deps += [ "//chrome/browser/android/vr:vr_android_unittests" ]
       import("//tools/perf/chrome_telemetry_build/android_browser_types.gni")
       foreach(_target_suffix, telemetry_android_browser_target_suffixes) {
diff --git a/DEPS b/DEPS
index 538853f..d025384 100644
--- a/DEPS
+++ b/DEPS
@@ -222,7 +222,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '7d336c9557bd8537e922ee83b1138e4cd23fee6b',
+  'skia_revision': '3c8ae888b9d439640a8ebc461696e21c43c40a26',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -234,7 +234,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '4264138a69fb4d026a8c313bbd5e97d9c8acae53',
+  'angle_revision': '4b47e8f30f18f7b3bad04581fe2155ae900b0eea',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -273,7 +273,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': '5d27b10f4c6c8e140bd48a001b98037ac0d54118',
+  'freetype_revision': '86b9c9347f99174f4fea3e9deca5800e57a987f2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
@@ -301,7 +301,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': '4738f715b40965fdd021254b7e0acd643650501a',
+  'devtools_frontend_revision': '3393236ac77815dea1a6aa98d6841e6d3576ff95',
   # 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.
@@ -341,11 +341,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': '93a75930b1fedceba9cc79ea6b96b5d48841aea1',
+  'dawn_revision': '37140e7c62695d366c0845bddf9c8b991fda07da',
   # 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': '6f99b68e19950729c59b4f325db74c50361d3ce1',
+  'quiche_revision': 'bf2d194d095ca983af35ed1836c063ba78937d42',
   # 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.
@@ -581,7 +581,7 @@
   },
 
   'src/ios/third_party/material_components_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'e77917902f563d81affa526bf72c62e2a43baad3',
+      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '4b3e0691e973ce343b02d11c2147677e8d42ecb3',
       'condition': 'checkout_ios',
   },
 
@@ -954,7 +954,7 @@
   # Tools used when building Chrome for Chrome OS. This affects both the Simple
   # Chrome workflow, as well as the chromeos-chrome ebuild.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '8cb0c26f1b5edef8fd68211017fc891253a9bfd5',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '8f716a3827122972c3abe227f4df64c05d6f8073',
       'condition': 'checkout_chromeos',
   },
 
@@ -1653,7 +1653,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@3b466a60b26d97ac5d1ae227a6161609d343ce53',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@7088f13fe3bc8aba5f8b52f08aee7be47d1e16cd',
     'condition': 'checkout_src_internal',
   },
 
@@ -1672,7 +1672,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': '9nZk3G149odzs3UYfxp9NNNNeccCfb8UWqOl8poTJSwC',
+        'version': 'LUnLvmG9knrgOUBqbI94jaHZ5fhbJfmgMabfn1jq97sC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1683,7 +1683,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'zLyaMA4wGNqn0zmdixOgq06SE1id4oAGIv1fwJlYftkC',
+        'version': 'Y04IPCFrojzuR1Y8P5St_UVuCl2vhjT8tLGHSZiyANsC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/android_webview/docs/test-instructions.md b/android_webview/docs/test-instructions.md
index f602b37..9bb9232 100644
--- a/android_webview/docs/test-instructions.md
+++ b/android_webview/docs/test-instructions.md
@@ -149,7 +149,7 @@
 ```sh
 $ out/Default/bin/run_webview_instrumentation_test_apk \ # Any test runner
     --num_retries=0 \ # Tests normally retry-on-failure; disable for easier repo
-    --repeat=1000 \ # Repeat up to 1000 times for a failure
+    --repeat=100 \ # Repeat up to 100 times for a failure
     --break-on-failure \ # Stop repeating once we see the first failure
     -f=AwContentsTest#testClearCacheInQuickSuccession
 ```
diff --git a/android_webview/java/src/org/chromium/android_webview/common/SafeModeController.java b/android_webview/java/src/org/chromium/android_webview/common/SafeModeController.java
index 59d9f22..3789920 100644
--- a/android_webview/java/src/org/chromium/android_webview/common/SafeModeController.java
+++ b/android_webview/java/src/org/chromium/android_webview/common/SafeModeController.java
@@ -37,12 +37,25 @@
 
     private SafeModeController() {}
 
+    private static SafeModeController sInstanceForTests;
+
     private static class LazyHolder {
         static final SafeModeController INSTANCE = new SafeModeController();
     }
 
+    /**
+     * Sets the singleton instance for testing. Not thread safe, must only be called from single
+     * threaded tests.
+     * @param controller The SafeModeController object to return from getInstance(). Passing in a
+     * null value resets this.
+     */
+    @VisibleForTesting
+    public static void setInstanceForTests(SafeModeController controller) {
+        sInstanceForTests = controller;
+    }
+
     public static SafeModeController getInstance() {
-        return LazyHolder.INSTANCE;
+        return sInstanceForTests == null ? LazyHolder.INSTANCE : sInstanceForTests;
     }
 
     /**
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientOnRenderProcessGoneTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientOnRenderProcessGoneTest.java
index 7468ac89..26a0d78c 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientOnRenderProcessGoneTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientOnRenderProcessGoneTest.java
@@ -23,7 +23,6 @@
 import org.chromium.base.task.PostTask;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
@@ -101,7 +100,6 @@
     }
 
     @Test
-    @DisabledTest // http://crbug.com/689292
     @Feature({"AndroidWebView"})
     @SmallTest
     @OnlyRunIn(MULTI_PROCESS)
diff --git a/android_webview/nonembedded/java/src/org/chromium/android_webview/nonembedded/AwComponentUpdateService.java b/android_webview/nonembedded/java/src/org/chromium/android_webview/nonembedded/AwComponentUpdateService.java
index ba934d0..5595564 100644
--- a/android_webview/nonembedded/java/src/org/chromium/android_webview/nonembedded/AwComponentUpdateService.java
+++ b/android_webview/nonembedded/java/src/org/chromium/android_webview/nonembedded/AwComponentUpdateService.java
@@ -10,6 +10,8 @@
 import android.content.SharedPreferences;
 import android.os.SystemClock;
 
+import androidx.annotation.VisibleForTesting;
+
 import org.chromium.android_webview.services.ComponentUpdaterSafeModeUtils;
 import org.chromium.android_webview.services.ComponentsProviderPathUtil;
 import org.chromium.base.Callback;
@@ -114,7 +116,8 @@
      * @return {@code true} if it successfully triggers component updates or if component are
      *         already updating, {@code false} if it fails to trigger the updates.
      */
-    private boolean maybeStartUpdates() {
+    @VisibleForTesting
+    boolean maybeStartUpdates() {
         if (mIsUpdating) {
             return true;
         }
diff --git a/android_webview/nonembedded/java/src/org/chromium/android_webview/nonembedded/AwComponentUpdateServiceSafeModeTest.java b/android_webview/nonembedded/java/src/org/chromium/android_webview/nonembedded/AwComponentUpdateServiceSafeModeTest.java
new file mode 100644
index 0000000..36a7bbd7
--- /dev/null
+++ b/android_webview/nonembedded/java/src/org/chromium/android_webview/nonembedded/AwComponentUpdateServiceSafeModeTest.java
@@ -0,0 +1,80 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.android_webview.nonembedded;
+
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import org.chromium.android_webview.common.SafeModeController;
+import org.chromium.base.FileUtils;
+import org.chromium.base.PathUtils;
+import org.chromium.base.test.BaseRobolectricTestRunner;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+/** Test AwComponentUpdateService's behavior when Safe Mode Reset is applied. */
+@RunWith(BaseRobolectricTestRunner.class)
+public class AwComponentUpdateServiceSafeModeTest {
+    private static final String TEST_FILE = "testManifest.json";
+    private File mDirectory;
+    private AwComponentUpdateService mComponentUpdateService;
+
+    @Mock
+    private SafeModeController mMockSafeModeController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mComponentUpdateService = new AwComponentUpdateService();
+        PathUtils.setPrivateDataDirectorySuffix("webview", "WebView");
+        mDirectory = new File(PathUtils.getDataDirectory(), "components/cus/");
+        if (!mDirectory.exists()) {
+            Assert.assertTrue(mDirectory.mkdirs());
+        }
+
+        mMockSafeModeController = mock(SafeModeController.class);
+        SafeModeController.setInstanceForTests(mMockSafeModeController);
+    }
+
+    @After
+    public void tearDown() {
+        Assert.assertTrue("Failed to delete " + mDirectory.getAbsolutePath(),
+                FileUtils.recursivelyDeleteFile(mDirectory, null));
+        SafeModeController.setInstanceForTests(null);
+    }
+
+    @Test
+    @SmallTest
+    public void testComponentUpdaterResetDeletesDownloadedConfigs() throws IOException {
+        File cusFile = new File(mDirectory, TEST_FILE);
+        Assert.assertTrue(
+                "Failed to create test file " + cusFile.getAbsolutePath(), cusFile.createNewFile());
+
+        final String componentUpdaterResetActionId =
+                new ComponentUpdaterResetSafeModeAction().getId();
+        Set<String> actions = new HashSet<>();
+        actions.add(componentUpdaterResetActionId);
+        when(mMockSafeModeController.queryActions(anyString())).thenReturn(actions);
+
+        Assert.assertFalse(mComponentUpdateService.maybeStartUpdates());
+
+        File[] cusFiles = mDirectory.listFiles();
+        Assert.assertNull(cusFiles);
+    }
+}
diff --git a/android_webview/nonembedded/java/src/org/chromium/android_webview/nonembedded/WebViewApkApplication.java b/android_webview/nonembedded/java/src/org/chromium/android_webview/nonembedded/WebViewApkApplication.java
index 024a90b..f2f06cfb 100644
--- a/android_webview/nonembedded/java/src/org/chromium/android_webview/nonembedded/WebViewApkApplication.java
+++ b/android_webview/nonembedded/java/src/org/chromium/android_webview/nonembedded/WebViewApkApplication.java
@@ -88,8 +88,11 @@
         if (isWebViewProcess()) {
             PathUtils.setPrivateDataDirectorySuffix("webview", "WebView");
             CommandLineUtil.initCommandLine();
-            // disable using a native recorder in this process because native lib isn't loaded.
-            UmaRecorderHolder.setAllowNativeUmaRecorder(false);
+
+            // TODO(crbug.com/1182693): Do set up a native UMA recorder once we support recording
+            // metrics from native nonembedded code.
+            UmaRecorderHolder.setUpNativeUmaRecorder(false);
+
             UmaRecorderHolder.setNonNativeDelegate(new AwNonembeddedUmaRecorder());
         }
 
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn
index 806932e..9c19839 100644
--- a/android_webview/test/BUILD.gn
+++ b/android_webview/test/BUILD.gn
@@ -577,6 +577,7 @@
     "../junit/src/org/chromium/android_webview/robolectric/common/FlagOverrideHelperTest.java",
     "../junit/src/org/chromium/android_webview/robolectric/common/services/ServiceNamesTest.java",
     "../junit/src/org/chromium/android_webview/robolectric/metrics/AwNonembeddedUmaReplayerTest.java",
+    "../nonembedded/java/src/org/chromium/android_webview/nonembedded/AwComponentUpdateServiceSafeModeTest.java",
     "../nonembedded/java/src/org/chromium/android_webview/nonembedded/NetworkFetcherTaskTest.java",
   ]
 
diff --git a/ash/app_list/views/app_list_view.cc b/ash/app_list/views/app_list_view.cc
index 7251140..da5c60d 100644
--- a/ash/app_list/views/app_list_view.cc
+++ b/ash/app_list/views/app_list_view.cc
@@ -31,6 +31,8 @@
 #include "ash/public/cpp/metrics_util.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/public/cpp/wallpaper/wallpaper_types.h"
+#include "ash/shell.h"
+#include "ash/wm/work_area_insets.h"
 #include "base/bind.h"
 #include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
@@ -1753,6 +1755,16 @@
   if (!set_state_request)
     return;
 
+  // Bail out if `WorkAreaInsets::SetPersistentDeskBarHeight(int height)` causes
+  // another call to `SetState()`. Note, the persistent desks bar is created in
+  // the primary display for now.
+  if (Shell::HasInstance() &&
+      WorkAreaInsets::ForWindow(Shell::GetPrimaryRootWindow())
+          ->PersistentDeskBarHeightInChange() &&
+      app_list_state_ == new_state_override) {
+    return;
+  }
+
   MaybeCreateAccessibilityEvent(new_state_override);
 
   // Prepare state transition notifier for the new state transition.
diff --git a/ash/components/BUILD.gn b/ash/components/BUILD.gn
index f779dc1..74f2476 100644
--- a/ash/components/BUILD.gn
+++ b/ash/components/BUILD.gn
@@ -11,7 +11,6 @@
 source_set("unit_tests") {
   testonly = true
   deps = [
-    "//ash/components/account_manager:unit_tests",
     "//ash/components/audio:unit_tests",
     "//ash/components/pcie_peripheral:unit_tests",
   ]
diff --git a/ash/components/account_manager/BUILD.gn b/ash/components/account_manager/BUILD.gn
index 1c46d98..a84fea8 100644
--- a/ash/components/account_manager/BUILD.gn
+++ b/ash/components/account_manager/BUILD.gn
@@ -8,46 +8,13 @@
 
 component("account_manager") {
   sources = [
-    "access_token_fetcher.cc",
-    "access_token_fetcher.h",
-    "account_manager_ash.cc",
-    "account_manager_ash.h",
     "account_manager_factory.cc",
     "account_manager_factory.h",
-    "account_manager_ui.cc",
-    "account_manager_ui.h",
   ]
 
   public_deps = [ "//components/account_manager_core:account_manager_core" ]
 
-  deps = [
-    "//ash/constants",
-    "//base",
-    "//chromeos/crosapi/mojom",
-    "//components/prefs:prefs",
-    "//google_apis",
-    "//net",
-    "//services/network/public/cpp:cpp",
-  ]
+  deps = [ "//base" ]
 
   defines = [ "IS_ASH_COMPONENTS_ACCOUNT_MANAGER_IMPL" ]
 }
-
-source_set("unit_tests") {
-  testonly = true
-  sources = [ "account_manager_ash_unittest.cc" ]
-
-  deps = [
-    ":account_manager",
-    "//base",
-    "//base/test:test_support",
-    "//chromeos/crosapi/mojom",
-    "//components/prefs:test_support",
-    "//google_apis",
-    "//net",
-    "//services/network:test_support",
-    "//services/network/public/cpp:cpp",
-    "//testing/gmock",
-    "//testing/gtest",
-  ]
-}
diff --git a/ash/components/account_manager/account_manager_factory.cc b/ash/components/account_manager/account_manager_factory.cc
index 87ae60e..83938875 100644
--- a/ash/components/account_manager/account_manager_factory.cc
+++ b/ash/components/account_manager/account_manager_factory.cc
@@ -9,6 +9,7 @@
 
 #include "base/macros.h"
 #include "components/account_manager_core/chromeos/account_manager.h"
+#include "components/account_manager_core/chromeos/account_manager_ash.h"
 
 namespace ash {
 
diff --git a/ash/components/account_manager/account_manager_factory.h b/ash/components/account_manager/account_manager_factory.h
index 08b4ae7..716d07e 100644
--- a/ash/components/account_manager/account_manager_factory.h
+++ b/ash/components/account_manager/account_manager_factory.h
@@ -9,7 +9,6 @@
 #include <string>
 #include <unordered_map>
 
-#include "ash/components/account_manager/account_manager_ash.h"
 #include "base/component_export.h"
 #include "base/sequence_checker.h"
 
@@ -17,6 +16,10 @@
 class AccountManager;
 }  // namespace account_manager
 
+namespace crosapi {
+class AccountManagerAsh;
+}  // namespace crosapi
+
 namespace ash {
 
 // This factory is needed because of multi signin on Chrome OS. Device Accounts,
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 24919b6..4cbf3b8 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -804,6 +804,11 @@
 const base::Feature kPerDeskShelf{"PerDeskShelf",
                                   base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Allows tablet mode split screen to resize by moving windows instead of
+// resizing. This reduces jank on low end devices.
+const base::Feature kPerformantSplitViewResizing{
+    "PerformantSplitViewResizing", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Provides a UI for users to view information about their Android phone
 // and perform phone-side actions within Chrome OS.
 const base::Feature kPhoneHub{"PhoneHub", base::FEATURE_ENABLED_BY_DEFAULT};
@@ -1443,6 +1448,10 @@
   return base::FeatureList::IsEnabled(kPhoneHubCameraRoll);
 }
 
+bool IsPerformantSplitViewResizingEnabled() {
+  return base::FeatureList::IsEnabled(kPerformantSplitViewResizing);
+}
+
 bool IsPhoneHubEnabled() {
   return base::FeatureList::IsEnabled(kPhoneHub);
 }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 8c794bf..bf35045 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -302,6 +302,8 @@
 extern const base::Feature kOsSettingsDeepLinking;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kOverviewButton;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kPerDeskShelf;
+COMPONENT_EXPORT(ASH_CONSTANTS)
+extern const base::Feature kPerformantSplitViewResizing;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kPhoneHub;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kPhoneHubCameraRoll;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kPhoneHubRecentApps;
@@ -502,6 +504,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsPciguardUiEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsPerDeskShelfEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsPhoneHubCameraRollEnabled();
+COMPONENT_EXPORT(ASH_CONSTANTS) bool IsPerformantSplitViewResizingEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsPhoneHubEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsPhoneHubRecentAppsEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsPinAutosubmitBackfillFeatureEnabled();
diff --git a/ash/public/cpp/desk_template.cc b/ash/public/cpp/desk_template.cc
index 81e640c..acf9c2e 100644
--- a/ash/public/cpp/desk_template.cc
+++ b/ash/public/cpp/desk_template.cc
@@ -4,12 +4,23 @@
 
 #include "ash/public/cpp/desk_template.h"
 
-#include "base/time/time.h"
+#include "base/strings/utf_string_conversions.h"
 
 namespace ash {
 
-DeskTemplate::DeskTemplate() : uuid_(base::Time::Now().ToDoubleT()) {}
-DeskTemplate::DeskTemplate(double uuid) : uuid_(uuid) {}
+DeskTemplate::DeskTemplate()
+    : uuid_(base::GUID::GenerateRandomV4()), created_time_(base::Time::Now()) {}
+
+DeskTemplate::DeskTemplate(const base::GUID& guid)
+    : uuid_(guid), created_time_(base::Time::Now()) {}
+
+DeskTemplate::DeskTemplate(const std::string& uuid,
+                           const std::string& name,
+                           const base::Time& created_time)
+    : uuid_(base::GUID::ParseCaseInsensitive(uuid)),
+      created_time_(created_time),
+      template_name_(base::UTF8ToUTF16(name)) {}
+
 DeskTemplate::~DeskTemplate() = default;
 
-}  // namespace ash
+}  // namespace ash
\ No newline at end of file
diff --git a/ash/public/cpp/desk_template.h b/ash/public/cpp/desk_template.h
index a3da064..ed8bf84 100644
--- a/ash/public/cpp/desk_template.h
+++ b/ash/public/cpp/desk_template.h
@@ -8,6 +8,8 @@
 #include <string>
 
 #include "ash/public/cpp/ash_public_export.h"
+#include "base/guid.h"
+#include "base/time/time.h"
 #include "components/full_restore/restore_data.h"
 
 namespace ash {
@@ -17,12 +19,18 @@
 class ASH_PUBLIC_EXPORT DeskTemplate {
  public:
   DeskTemplate();
-  explicit DeskTemplate(double uuid);
+  explicit DeskTemplate(const base::GUID& uuid);
+  // This constructor is used in the instantiation of the DeskTemplate from
+  // a WorkspaceDeskSpecifics proto and base::Value.
+  DeskTemplate(const std::string& uuid,
+               const std::string& name,
+               const base::Time& time_created);
   DeskTemplate(const DeskTemplate&) = delete;
   DeskTemplate& operator=(const DeskTemplate&) = delete;
   ~DeskTemplate();
 
-  double uuid() const { return uuid_; }
+  base::GUID uuid() const { return uuid_; }
+  base::Time created_time() const { return created_time_; }
   const std::u16string& template_name() const { return template_name_; }
   void set_template_name(const std::u16string& template_name) {
     template_name_ = template_name;
@@ -36,9 +44,11 @@
   }
 
  private:
-  // We'll use the current time in seconds since epoch to uniquely identify the
-  // template. TODO: change it to base::GUID type.
-  const double uuid_;
+  const base::GUID uuid_;  // We utilize the string based base::GUID to uniquely
+                           // identify the template.
+
+  const base::Time created_time_;  // We'll use the current time in seconds
+                                   // since the Windows epoch.
   std::u16string template_name_;
 
   // Contains the app launching and window information that can be used to
diff --git a/ash/quick_pair/BUILD.gn b/ash/quick_pair/BUILD.gn
index 7c23b87..86baaf8 100644
--- a/ash/quick_pair/BUILD.gn
+++ b/ash/quick_pair/BUILD.gn
@@ -25,6 +25,7 @@
     "//ash/quick_pair/common:unit_tests",
     "//ash/quick_pair/feature_status_tracker:unit_tests",
     "//ash/quick_pair/keyed_service:unit_tests",
+    "//ash/quick_pair/pairing:unit_tests",
     "//ash/quick_pair/scanning:unit_tests",
   ]
 }
diff --git a/ash/quick_pair/common/BUILD.gn b/ash/quick_pair/common/BUILD.gn
index 58767e2..3cd0715 100644
--- a/ash/quick_pair/common/BUILD.gn
+++ b/ash/quick_pair/common/BUILD.gn
@@ -13,6 +13,8 @@
   defines = [ "IS_QUICK_PAIR_COMMON_IMPL" ]
 
   sources = [
+    "account_key_failure.cc",
+    "account_key_failure.h",
     "constants.h",
     "device.cc",
     "device.h",
diff --git a/ash/quick_pair/common/account_key_failure.cc b/ash/quick_pair/common/account_key_failure.cc
new file mode 100644
index 0000000..6aed88b
--- /dev/null
+++ b/ash/quick_pair/common/account_key_failure.cc
@@ -0,0 +1,25 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/quick_pair/common/account_key_failure.h"
+
+namespace ash {
+namespace quick_pair {
+
+std::ostream& operator<<(std::ostream& stream, AccountKeyFailure failure) {
+  switch (failure) {
+    case AccountKeyFailure::kAccountKeyCharacteristicDiscovery:
+      stream << "[Failed to find the Account Key GATT characteristic]";
+      break;
+
+    case AccountKeyFailure::kKeyBasedPairingCharacteristicWrite:
+      stream << "[Failed to write to the Account Key GATT characteristic]";
+      break;
+  }
+
+  return stream;
+}
+
+}  // namespace quick_pair
+}  // namespace ash
diff --git a/ash/quick_pair/common/account_key_failure.h b/ash/quick_pair/common/account_key_failure.h
new file mode 100644
index 0000000..a12c9ade
--- /dev/null
+++ b/ash/quick_pair/common/account_key_failure.h
@@ -0,0 +1,27 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_QUICK_PAIR_COMMON_ACCOUNT_KEY_FAILURE_H_
+#define ASH_QUICK_PAIR_COMMON_ACCOUNT_KEY_FAILURE_H_
+
+#include <ostream>
+#include "base/component_export.h"
+
+namespace ash {
+namespace quick_pair {
+
+enum class AccountKeyFailure {
+  // Failed to find the Account Key GATT characteristic.
+  kAccountKeyCharacteristicDiscovery = 0,
+  // Failed to write to the Account Key GATT characteristic.
+  kKeyBasedPairingCharacteristicWrite = 1,
+};
+
+COMPONENT_EXPORT(QUICK_PAIR_COMMON)
+std::ostream& operator<<(std::ostream& stream, AccountKeyFailure protocol);
+
+}  // namespace quick_pair
+}  // namespace ash
+
+#endif  // ASH_QUICK_PAIR_COMMON_ACCOUNT_KEY_FAILURE_H_
diff --git a/ash/quick_pair/pairing/BUILD.gn b/ash/quick_pair/pairing/BUILD.gn
new file mode 100644
index 0000000..f3756a2e
--- /dev/null
+++ b/ash/quick_pair/pairing/BUILD.gn
@@ -0,0 +1,37 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/chromeos/ui_mode.gni")
+
+assert(is_chromeos_ash,
+       "Quick Pair protocols (e.g. Fast Pair) are ash-chrome only")
+
+source_set("pairing") {
+  sources = [
+    "fast_pair/fast_pair_pairer.cc",
+    "fast_pair/fast_pair_pairer.h",
+    "pairer_broker.h",
+    "pairer_broker_impl.cc",
+    "pairer_broker_impl.h",
+  ]
+
+  deps = [
+    "//ash/quick_pair/common",
+    "//base",
+    "//device/bluetooth",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+
+  sources = [ "fast_pair/fast_pair_pairer_unittest.cc" ]
+
+  deps = [
+    ":pairing",
+    "//ash/quick_pair/common",
+    "//base/test:test_support",
+    "//testing/gtest",
+  ]
+}
diff --git a/ash/quick_pair/pairing/fast_pair/fast_pair_pairer.cc b/ash/quick_pair/pairing/fast_pair/fast_pair_pairer.cc
new file mode 100644
index 0000000..dbf3bfc2
--- /dev/null
+++ b/ash/quick_pair/pairing/fast_pair/fast_pair_pairer.cc
@@ -0,0 +1,44 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/quick_pair/pairing/fast_pair/fast_pair_pairer.h"
+
+#include "ash/quick_pair/common/account_key_failure.h"
+#include "ash/quick_pair/common/device.h"
+#include "ash/quick_pair/common/logging.h"
+#include "ash/quick_pair/common/pair_failure.h"
+#include "base/callback.h"
+
+namespace ash {
+namespace quick_pair {
+
+FastPairPairer::FastPairPairer(
+    const Device& device,
+    base::OnceCallback<void(const Device&)> paired_callback,
+    base::OnceCallback<void(const Device&, PairFailure)> pair_failed_callback,
+    base::OnceCallback<void(const Device&, AccountKeyFailure)>
+        account_key_failure_callback,
+    base::OnceCallback<void(const Device&)> pairing_procedure_complete)
+    : device_(device),
+      paired_callback_(std::move(paired_callback)),
+      pair_failed_callback_(std::move(pair_failed_callback)),
+      account_key_failure_callback_(std::move(account_key_failure_callback)),
+      pairing_procedure_complete_(std::move(pairing_procedure_complete)) {
+  StartPairing();
+}
+
+FastPairPairer::FastPairPairer(FastPairPairer&&) = default;
+
+FastPairPairer& FastPairPairer::operator=(FastPairPairer&&) = default;
+
+FastPairPairer::~FastPairPairer() = default;
+
+void FastPairPairer::StartPairing() {
+  QP_LOG(INFO) << __func__ << ": " << device_;
+  std::move(paired_callback_).Run(device_);
+  std::move(pairing_procedure_complete_).Run(device_);
+}
+
+}  // namespace quick_pair
+}  // namespace ash
diff --git a/ash/quick_pair/pairing/fast_pair/fast_pair_pairer.h b/ash/quick_pair/pairing/fast_pair/fast_pair_pairer.h
new file mode 100644
index 0000000..7ef37292
--- /dev/null
+++ b/ash/quick_pair/pairing/fast_pair/fast_pair_pairer.h
@@ -0,0 +1,49 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_QUICK_PAIR_PAIRING_FAST_PAIR_FAST_PAIR_PAIRER_H_
+#define ASH_QUICK_PAIR_PAIRING_FAST_PAIR_FAST_PAIR_PAIRER_H_
+
+#include <functional>
+#include "ash/quick_pair/common/device.h"
+#include "base/callback.h"
+
+namespace ash {
+namespace quick_pair {
+
+enum class AccountKeyFailure;
+enum class PairFailure;
+
+// A FastPairPairer instance is responsible for the pairing procedure to a
+// single device.  Pairing begins on instantiation.
+class FastPairPairer {
+ public:
+  FastPairPairer(
+      const Device& device,
+      base::OnceCallback<void(const Device&)> paired_callback,
+      base::OnceCallback<void(const Device&, PairFailure)> pair_failed_callback,
+      base::OnceCallback<void(const Device&, AccountKeyFailure)>
+          account_key_failure_callback,
+      base::OnceCallback<void(const Device&)> pairing_procedure_complete);
+  FastPairPairer(const FastPairPairer&) = delete;
+  FastPairPairer& operator=(const FastPairPairer&) = delete;
+  FastPairPairer(FastPairPairer&&);
+  FastPairPairer& operator=(FastPairPairer&&);
+  ~FastPairPairer();
+
+ private:
+  void StartPairing();
+
+  std::reference_wrapper<const Device> device_;
+  base::OnceCallback<void(const Device&)> paired_callback_;
+  base::OnceCallback<void(const Device&, PairFailure)> pair_failed_callback_;
+  base::OnceCallback<void(const Device&, AccountKeyFailure)>
+      account_key_failure_callback_;
+  base::OnceCallback<void(const Device&)> pairing_procedure_complete_;
+};
+
+}  // namespace quick_pair
+}  // namespace ash
+
+#endif  // ASH_QUICK_PAIR_PAIRING_FAST_PAIR_FAST_PAIR_PAIRER_H_
diff --git a/ash/quick_pair/pairing/fast_pair/fast_pair_pairer_unittest.cc b/ash/quick_pair/pairing/fast_pair/fast_pair_pairer_unittest.cc
new file mode 100644
index 0000000..6a2a07e
--- /dev/null
+++ b/ash/quick_pair/pairing/fast_pair/fast_pair_pairer_unittest.cc
@@ -0,0 +1,45 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/quick_pair/pairing/fast_pair/fast_pair_pairer.h"
+
+#include <memory>
+
+#include "ash/quick_pair/common/account_key_failure.h"
+#include "ash/quick_pair/common/device.h"
+#include "ash/quick_pair/common/pair_failure.h"
+#include "ash/quick_pair/common/protocol.h"
+#include "base/test/mock_callback.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ash {
+namespace quick_pair {
+
+class FastPairPairerTest : public testing::Test {
+ protected:
+  // This is done on-demand to enable setting up mock expectations first.
+  void CreatePairer() {
+    pairer_ = std::make_unique<FastPairPairer>(
+        device_, paired_callback_.Get(), pair_failed_callback_.Get(),
+        account_key_failure_callback_.Get(), pairing_procedure_complete_.Get());
+  }
+
+  Device device_{"test_id", "test_address", Protocol::kFastPair};
+  base::MockCallback<base::OnceCallback<void(const Device&)>> paired_callback_;
+  base::MockCallback<base::OnceCallback<void(const Device&, PairFailure)>>
+      pair_failed_callback_;
+  base::MockCallback<base::OnceCallback<void(const Device&, AccountKeyFailure)>>
+      account_key_failure_callback_;
+  base::MockCallback<base::OnceCallback<void(const Device&)>>
+      pairing_procedure_complete_;
+  std::unique_ptr<FastPairPairer> pairer_;
+};
+
+TEST_F(FastPairPairerTest, PairingProcedureCompleteCallbackIsInvoked) {
+  EXPECT_CALL(pairing_procedure_complete_, Run);
+  CreatePairer();
+}
+
+}  // namespace quick_pair
+}  // namespace ash
diff --git a/ash/quick_pair/pairing/pairer_broker.h b/ash/quick_pair/pairing/pairer_broker.h
new file mode 100644
index 0000000..2436e87
--- /dev/null
+++ b/ash/quick_pair/pairing/pairer_broker.h
@@ -0,0 +1,43 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_QUICK_PAIR_PAIRING_PAIRER_BROKER_H_
+#define ASH_QUICK_PAIR_PAIRING_PAIRER_BROKER_H_
+
+#include "ash/quick_pair/common/pair_failure.h"
+#include "ash/quick_pair/common/protocol.h"
+#include "base/observer_list_types.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace ash {
+namespace quick_pair {
+
+struct Device;
+enum class AccountKeyFailure;
+
+// The PairerBroker is the entry point for the Pairing component in the Quick
+// pair system. It is responsible for brokering the 'pair to device' calls to
+// the correct concrete Pairer implementation, and exposing an observer pattern
+// for other components to become aware of pairing results.
+class PairerBroker {
+ public:
+  class Observer : public base::CheckedObserver {
+   public:
+    virtual void OnDevicePaired(const Device& device) = 0;
+    virtual void OnPairFailure(const Device& device, PairFailure failure) = 0;
+    virtual void OnAccountKeyWrite(const Device& device,
+                                   absl::optional<AccountKeyFailure> error) = 0;
+  };
+
+  virtual ~PairerBroker() = default;
+
+  virtual void AddObserver(Observer* observer) = 0;
+  virtual void RemoveObserver(Observer* observer) = 0;
+  virtual void PairDevice(const Device& device) = 0;
+};
+
+}  // namespace quick_pair
+}  // namespace ash
+
+#endif  // ASH_QUICK_PAIR_PAIRING_PAIRER_BROKER_H_
diff --git a/ash/quick_pair/pairing/pairer_broker_impl.cc b/ash/quick_pair/pairing/pairer_broker_impl.cc
new file mode 100644
index 0000000..a232587
--- /dev/null
+++ b/ash/quick_pair/pairing/pairer_broker_impl.cc
@@ -0,0 +1,80 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/quick_pair/pairing/pairer_broker_impl.h"
+
+#include "ash/quick_pair/common/account_key_failure.h"
+#include "ash/quick_pair/common/device.h"
+#include "ash/quick_pair/common/logging.h"
+#include "ash/quick_pair/common/pair_failure.h"
+#include "ash/quick_pair/common/protocol.h"
+#include "ash/quick_pair/pairing/fast_pair/fast_pair_pairer.h"
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/containers/contains.h"
+
+namespace ash {
+namespace quick_pair {
+
+PairerBrokerImpl::PairerBrokerImpl() = default;
+
+PairerBrokerImpl::~PairerBrokerImpl() = default;
+
+void PairerBrokerImpl::AddObserver(Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void PairerBrokerImpl::RemoveObserver(Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+void PairerBrokerImpl::PairDevice(const Device& device) {
+  switch (device.protocol) {
+    case Protocol::kFastPair:
+      PairFastPairDevice(device);
+      break;
+  }
+}
+
+void PairerBrokerImpl::PairFastPairDevice(const Device& device) {
+  if (base::Contains(fast_pair_pairers_, device.address)) {
+    QP_LOG(WARNING) << __func__ << ": Already pairing device" << device;
+    return;
+  }
+
+  QP_LOG(INFO) << __func__ << ": " << device;
+
+  fast_pair_pairers_[device.address] = std::make_unique<FastPairPairer>(
+      device,
+      base::BindOnce(&PairerBrokerImpl::OnFastPairDevicePaired,
+                     weak_pointer_factory_.GetWeakPtr()),
+      base::BindOnce(&PairerBrokerImpl::OnFastPairPairingFailure,
+                     weak_pointer_factory_.GetWeakPtr()),
+      base::BindOnce(&PairerBrokerImpl::OnAccountKeyFailure,
+                     weak_pointer_factory_.GetWeakPtr()),
+      base::BindOnce(&PairerBrokerImpl::OnFastPairProcedureComplete,
+                     weak_pointer_factory_.GetWeakPtr()));
+}
+
+void PairerBrokerImpl::OnFastPairDevicePaired(const Device& device) {
+  QP_LOG(INFO) << __func__ << ": Device=" << device;
+}
+
+void PairerBrokerImpl::OnFastPairPairingFailure(const Device& device,
+                                                PairFailure failure) {
+  QP_LOG(INFO) << __func__ << ": Device=" << device << ", Failure=" << failure;
+}
+
+void PairerBrokerImpl::OnAccountKeyFailure(const Device& device,
+                                           AccountKeyFailure failure) {
+  QP_LOG(INFO) << __func__ << ": Device=" << device << ", Failure=" << failure;
+}
+
+void PairerBrokerImpl::OnFastPairProcedureComplete(const Device& device) {
+  QP_LOG(INFO) << __func__ << ": Device=" << device;
+  fast_pair_pairers_.erase(device.address);
+}
+
+}  // namespace quick_pair
+}  // namespace ash
diff --git a/ash/quick_pair/pairing/pairer_broker_impl.h b/ash/quick_pair/pairing/pairer_broker_impl.h
new file mode 100644
index 0000000..8edafff
--- /dev/null
+++ b/ash/quick_pair/pairing/pairer_broker_impl.h
@@ -0,0 +1,55 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_QUICK_PAIR_PAIRING_PAIRER_BROKER_IMPL_H_
+#define ASH_QUICK_PAIR_PAIRING_PAIRER_BROKER_IMPL_H_
+
+#include <memory>
+#include <string>
+
+#include "ash/quick_pair/pairing/pairer_broker.h"
+
+#include "ash/quick_pair/common/account_key_failure.h"
+#include "ash/quick_pair/common/pair_failure.h"
+#include "ash/quick_pair/common/protocol.h"
+#include "base/containers/flat_map.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace ash {
+namespace quick_pair {
+
+struct Device;
+class FastPairPairer;
+
+class PairerBrokerImpl : public PairerBroker {
+ public:
+  PairerBrokerImpl();
+  PairerBrokerImpl(const PairerBrokerImpl&) = delete;
+  PairerBrokerImpl& operator=(const PairerBrokerImpl&) = delete;
+  ~PairerBrokerImpl() final;
+
+  // PairingBroker:
+  void AddObserver(Observer* observer) override;
+  void RemoveObserver(Observer* observer) override;
+  void PairDevice(const Device& device) override;
+
+ private:
+  void PairFastPairDevice(const Device& device);
+  void OnFastPairDevicePaired(const Device& device);
+  void OnFastPairPairingFailure(const Device& device, PairFailure failure);
+  void OnAccountKeyFailure(const Device& device, AccountKeyFailure failure);
+  void OnFastPairProcedureComplete(const Device& device);
+
+  base::flat_map<std::string, std::unique_ptr<FastPairPairer>>
+      fast_pair_pairers_;
+  base::ObserverList<Observer> observers_;
+  base::WeakPtrFactory<PairerBrokerImpl> weak_pointer_factory_{this};
+};
+
+}  // namespace quick_pair
+}  // namespace ash
+
+#endif  // ASH_QUICK_PAIR_PAIRING_PAIRER_BROKER_IMPL_H_
diff --git a/ash/quick_pair/scanning/fast_pair/fast_pair_scanner_impl.cc b/ash/quick_pair/scanning/fast_pair/fast_pair_scanner_impl.cc
index 453e2c5..8ed662c 100644
--- a/ash/quick_pair/scanning/fast_pair/fast_pair_scanner_impl.cc
+++ b/ash/quick_pair/scanning/fast_pair/fast_pair_scanner_impl.cc
@@ -7,15 +7,18 @@
 #include "ash/quick_pair/common/constants.h"
 #include "ash/quick_pair/common/logging.h"
 #include "base/containers/contains.h"
+#include "base/time/time.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "device/bluetooth/bluetooth_low_energy_scan_filter.h"
 
 namespace {
 
 constexpr int16_t kFilterDeviceFoundThreshold = -80;
-constexpr uint16_t kFilterDeviceFoundTimeout = 1;
+constexpr base::TimeDelta kFilterDeviceFoundTimeout =
+    base::TimeDelta::FromSeconds(1);
 constexpr int16_t kFilterDeviceLostThreshold = -100;
-constexpr uint16_t kFilterDeviceLostTimeout = 5;
+constexpr base::TimeDelta kFilterDeviceLostTimeout =
+    base::TimeDelta::FromSeconds(5);
 constexpr uint8_t kFilterPatternStartPosition = 0;
 const std::vector<uint8_t> kFastPairFilterPatternValue = {0x2c, 0xfe};
 
@@ -46,14 +49,13 @@
   adapter_ = adapter;
   adapter_observation_.Observe(adapter_.get());
 
-  auto filter = std::make_unique<device::BluetoothLowEnergyScanFilter>(
-      kFilterDeviceFoundThreshold, kFilterDeviceFoundTimeout,
-      kFilterDeviceLostThreshold, kFilterDeviceLostTimeout);
-
-  filter->AddPattern(
+  device::BluetoothLowEnergyScanFilter::Pattern pattern(
       kFilterPatternStartPosition,
       device::BluetoothLowEnergyScanFilter::AdvertisementDataType::kServiceData,
       kFastPairFilterPatternValue);
+  auto filter = device::BluetoothLowEnergyScanFilter::Create(
+      kFilterDeviceFoundThreshold, kFilterDeviceLostThreshold,
+      kFilterDeviceFoundTimeout, kFilterDeviceLostTimeout, {pattern});
 
   background_scan_session_ = adapter_->StartLowEnergyScanSession(
       std::move(filter), weak_ptr_factory_.GetWeakPtr());
diff --git a/ash/system/bluetooth/bluetooth_power_controller.cc b/ash/system/bluetooth/bluetooth_power_controller.cc
index da6bd40..96209e51 100644
--- a/ash/system/bluetooth/bluetooth_power_controller.cc
+++ b/ash/system/bluetooth/bluetooth_power_controller.cc
@@ -15,6 +15,7 @@
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
+#include "device/bluetooth/chromeos/bluetooth_utils.h"
 
 namespace ash {
 
@@ -248,6 +249,7 @@
       &BluetoothPowerController::RunNextPendingBluetoothTask,
       weak_ptr_factory_.GetWeakPtr());
   bluetooth_adapter_->SetPowered(enabled, run_next_task, run_next_task);
+  device::RecordPoweredState(enabled);
 }
 
 void BluetoothPowerController::RunBluetoothTaskWhenAdapterReady(
diff --git a/ash/system/bluetooth/bluetooth_power_controller_unittest.cc b/ash/system/bluetooth/bluetooth_power_controller_unittest.cc
index 0d9b7e0..423c1f01 100644
--- a/ash/system/bluetooth/bluetooth_power_controller_unittest.cc
+++ b/ash/system/bluetooth/bluetooth_power_controller_unittest.cc
@@ -11,6 +11,7 @@
 #include "ash/test_shell_delegate.h"
 #include "base/callback_helpers.h"
 #include "base/run_loop.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/testing_pref_service.h"
 #include "device/bluetooth/dbus/bluez_dbus_manager.h"
@@ -98,6 +99,7 @@
   }
 
   TestingPrefServiceSimple active_user_prefs_;
+  base::HistogramTester histogram_tester;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(BluetoothPowerControllerTest);
@@ -111,6 +113,12 @@
 
 // Tests toggling Bluetooth setting on and off.
 TEST_F(BluetoothPowerControllerNoSessionTest, ToggleBluetoothEnabled) {
+  // Initially power state is set to default value.
+  histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.PoweredState", false,
+                                     1);
+  histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.PoweredState", true,
+                                     0);
+
   // Toggling bluetooth on/off when there is no user session should affect
   // local state prefs.
   EXPECT_FALSE(
@@ -121,6 +129,11 @@
   EXPECT_FALSE(
       local_state()->GetBoolean(prefs::kSystemBluetoothAdapterEnabled));
 
+  histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.PoweredState", false,
+                                     2);
+  histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.PoweredState", true,
+                                     1);
+
   // Toggling bluetooth on/off when there is user session should affect
   // user prefs.
   AddUserSessionAndStartWatchingPrefsChanges(kUser1Email);
@@ -132,11 +145,20 @@
   GetController()->SetBluetoothEnabled(false);
   EXPECT_FALSE(
       active_user_prefs_.GetBoolean(prefs::kUserBluetoothAdapterEnabled));
+  histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.PoweredState", false,
+                                     3);
+  histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.PoweredState", true,
+                                     2);
 }
 
 // Tests that BluetoothPowerController listens to local state pref changes
 // and applies the changes to bluetooth device.
 TEST_F(BluetoothPowerControllerTest, ListensPrefChangesLocalState) {
+  // Initially power state is set to default value .
+  histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.PoweredState", false,
+                                     1);
+  histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.PoweredState", true,
+                                     0);
   StartWatchingLocalStatePrefsChanges();
 
   // Makes sure we start with bluetooth power off.
@@ -148,9 +170,19 @@
   local_state()->SetBoolean(prefs::kSystemBluetoothAdapterEnabled, true);
   EXPECT_TRUE(GetBluetoothAdapter()->IsPowered());
 
+  histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.PoweredState", false,
+                                     1);
+  histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.PoweredState", true,
+                                     1);
+
   // Power should be turned off when pref changes to disabled.
   local_state()->SetBoolean(prefs::kSystemBluetoothAdapterEnabled, false);
   EXPECT_FALSE(GetBluetoothAdapter()->IsPowered());
+
+  histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.PoweredState", false,
+                                     2);
+  histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.PoweredState", true,
+                                     1);
 }
 
 // Tests that BluetoothPowerController listens to active user pref changes
@@ -177,6 +209,11 @@
 // power change tasks shouldn't be executed all but rather only the last request
 // is executed.
 TEST_F(BluetoothPowerControllerTest, ListensPrefChangesLongQueue) {
+  // Initially power state is set to default value.
+  histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.PoweredState", false,
+                                     1);
+  histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.PoweredState", true,
+                                     0);
   AddUserSessionAndStartWatchingPrefsChanges(kUser1Email);
 
   // Makes sure we start with bluetooth power off.
@@ -198,6 +235,12 @@
   SimulateControllerBusy(false);
   // The power state should represent the last request in the queue.
   EXPECT_TRUE(GetBluetoothAdapter()->IsPowered());
+
+  // Since controller executes only last request only power on is recorded.
+  histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.PoweredState", false,
+                                     1);
+  histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.PoweredState", true,
+                                     1);
 }
 
 // Tests how BluetoothPowerController applies the local state pref when
@@ -224,11 +267,23 @@
 // Tests how BluetoothPowerController applies the local state pref when
 // the pref has been set before.
 TEST_F(BluetoothPowerControllerTest, ApplyBluetoothLocalStatePrefOn) {
+  // Initially power state is set to default value .
+  histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.PoweredState", false,
+                                     1);
+  histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.PoweredState", true,
+                                     0);
+
   // Set the pref to true.
   local_state()->SetBoolean(prefs::kSystemBluetoothAdapterEnabled, true);
   EXPECT_FALSE(local_state()
                    ->FindPreference(prefs::kSystemBluetoothAdapterEnabled)
                    ->IsDefaultValue());
+
+  histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.PoweredState", false,
+                                     1);
+  histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.PoweredState", true,
+                                     1);
+
   // Start with bluetooth power off.
   GetBluetoothAdapter()->SetPowered(false, base::DoNothing(),
                                     base::DoNothing());
@@ -239,6 +294,11 @@
   // Bluetooth power setting should be applied (on), and pref value unchanged.
   EXPECT_TRUE(local_state()->GetBoolean(prefs::kSystemBluetoothAdapterEnabled));
   EXPECT_TRUE(GetBluetoothAdapter()->IsPowered());
+
+  histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.PoweredState", false,
+                                     1);
+  histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.PoweredState", true,
+                                     2);
 }
 
 // Tests how BluetoothPowerController applies the user pref when
diff --git a/ash/system/message_center/message_center_ui_controller.cc b/ash/system/message_center/message_center_ui_controller.cc
index 8a5b5f4..a03e955 100644
--- a/ash/system/message_center/message_center_ui_controller.cc
+++ b/ash/system/message_center/message_center_ui_controller.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "ash/shell.h"
 #include "ash/system/message_center/metrics_utils.h"
 #include "base/observer_list.h"
 #include "ui/message_center/message_center.h"
@@ -14,6 +15,13 @@
 
 namespace ash {
 
+namespace {
+// The duration used to log the number of notifications shown
+// right after a user logs in.
+constexpr base::TimeDelta kLoginNotificationLogDuration =
+    base::TimeDelta::FromMinutes(1);
+}  // namespace
+
 MessageCenterUiController::MessageCenterUiController(
     MessageCenterUiDelegate* delegate)
     : message_center_(message_center::MessageCenter::Get()),
@@ -21,10 +29,12 @@
       popups_visible_(false),
       delegate_(delegate) {
   message_center_->AddObserver(this);
+  session_observer_.Observe(Shell::Get()->session_controller());
 }
 
 MessageCenterUiController::~MessageCenterUiController() {
   message_center_->RemoveObserver(this);
+  session_observer_.Reset();
 }
 
 bool MessageCenterUiController::ShowMessageCenterBubble() {
@@ -138,6 +148,9 @@
 void MessageCenterUiController::OnNotificationDisplayed(
     const std::string& notification_id,
     const message_center::DisplaySource source) {
+  if (login_notification_logging_timer_.IsRunning())
+    notifications_displayed_in_first_minute_count_++;
+
   NotifyUiControllerChanged();
 }
 
@@ -158,6 +171,17 @@
     metrics_utils::LogPopupExpiredToTray(notification_id);
 }
 
+void MessageCenterUiController::OnFirstSessionStarted() {
+  login_notification_logging_timer_.Start(
+      FROM_HERE, kLoginNotificationLogDuration, this,
+      &MessageCenterUiController::OnLoginTimerEnded);
+}
+
+void MessageCenterUiController::OnLoginTimerEnded() {
+  metrics_utils::LogNotificationsShownInFirstMinute(
+      notifications_displayed_in_first_minute_count_);
+}
+
 void MessageCenterUiController::OnMessageCenterChanged() {
   if (hide_on_last_notification_ && message_center_visible_ &&
       message_center_->NotificationCount() == 0) {
diff --git a/ash/system/message_center/message_center_ui_controller.h b/ash/system/message_center/message_center_ui_controller.h
index 50ef5712..009b86c1 100644
--- a/ash/system/message_center/message_center_ui_controller.h
+++ b/ash/system/message_center/message_center_ui_controller.h
@@ -8,8 +8,12 @@
 #include <string>
 
 #include "ash/ash_export.h"
+#include "ash/public/cpp/session/session_observer.h"
+#include "ash/session/session_controller_impl.h"
 #include "ash/system/message_center/message_center_ui_delegate.h"
 #include "base/macros.h"
+#include "base/scoped_observation.h"
+#include "base/timer/timer.h"
 #include "ui/message_center/message_center_export.h"
 #include "ui/message_center/message_center_observer.h"
 #include "ui/message_center/public/cpp/notifier_id.h"
@@ -25,7 +29,8 @@
 // UiDelegate when the tray is changed, as well as when bubbles are shown and
 // hidden.
 class ASH_EXPORT MessageCenterUiController
-    : public message_center::MessageCenterObserver {
+    : public message_center::MessageCenterObserver,
+      public SessionObserver {
  public:
   explicit MessageCenterUiController(MessageCenterUiDelegate* delegate);
   ~MessageCenterUiController() override;
@@ -78,7 +83,11 @@
   void OnNotificationPopupShown(const std::string& notification_id,
                                 bool mark_notification_as_read) override;
 
+  // SessionObserver:
+  void OnFirstSessionStarted() override;
+
  private:
+  void OnLoginTimerEnded();
   void OnMessageCenterChanged();
   void NotifyUiControllerChanged();
   void HidePopupBubbleInternal();
@@ -91,6 +100,12 @@
   // Set true to hide MessageCenterView when the last notification is dismissed.
   bool hide_on_last_notification_ = true;
 
+  int notifications_displayed_in_first_minute_count_ = 0;
+  base::OneShotTimer login_notification_logging_timer_;
+
+  base::ScopedObservation<SessionController, SessionObserver> session_observer_{
+      this};
+
   DISALLOW_COPY_AND_ASSIGN(MessageCenterUiController);
 };
 
diff --git a/ash/system/message_center/message_center_ui_controller_unittest.cc b/ash/system/message_center/message_center_ui_controller_unittest.cc
index 7b25716b..ac79cbb 100644
--- a/ash/system/message_center/message_center_ui_controller_unittest.cc
+++ b/ash/system/message_center/message_center_ui_controller_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <utility>
 
+#include "ash/test/ash_test_base.h"
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -63,13 +64,13 @@
 
 }  // namespace
 
-class MessageCenterUiControllerTest : public testing::Test {
+class MessageCenterUiControllerTest : public AshTestBase {
  public:
   MessageCenterUiControllerTest() {}
   ~MessageCenterUiControllerTest() override {}
 
   void SetUp() override {
-    message_center::MessageCenter::Initialize();
+    AshTestBase::SetUp();
     delegate_ = std::make_unique<MockDelegate>();
     message_center_ = message_center::MessageCenter::Get();
     ui_controller_ =
@@ -80,7 +81,7 @@
     ui_controller_.reset();
     delegate_.reset();
     message_center_ = nullptr;
-    message_center::MessageCenter::Shutdown();
+    AshTestBase::TearDown();
   }
 
  protected:
diff --git a/ash/system/message_center/metrics_utils.cc b/ash/system/message_center/metrics_utils.cc
index a9d19a4..1be65f0 100644
--- a/ash/system/message_center/metrics_utils.cc
+++ b/ash/system/message_center/metrics_utils.cc
@@ -391,5 +391,11 @@
                                 type.value());
 }
 
+void LogNotificationsShownInFirstMinute(int count) {
+  UMA_HISTOGRAM_COUNTS_1000(
+      "Notifications.Cros.Actions.CountOfNotificationShownInFirstMinutePerUser",
+      count);
+}
+
 }  // namespace metrics_utils
 }  // namespace ash
diff --git a/ash/system/message_center/metrics_utils.h b/ash/system/message_center/metrics_utils.h
index e3cc568..09c54d8f 100644
--- a/ash/system/message_center/metrics_utils.h
+++ b/ash/system/message_center/metrics_utils.h
@@ -105,6 +105,10 @@
 // Logs a notification added event.
 void LogNotificationAdded(const std::string& notification_id);
 
+// Logs the count of notifications displayed during the first minute after a
+// user logs in.
+void LogNotificationsShownInFirstMinute(int notifications_count);
+
 }  // namespace metrics_utils
 
 }  // namespace ash
diff --git a/ash/webui/diagnostics_ui/diagnostics_ui.cc b/ash/webui/diagnostics_ui/diagnostics_ui.cc
index ffe92ca..23ffad32 100644
--- a/ash/webui/diagnostics_ui/diagnostics_ui.cc
+++ b/ash/webui/diagnostics_ui/diagnostics_ui.cc
@@ -114,6 +114,7 @@
       {"learnMore", IDS_DIANOSTICS_LEARN_MORE_LABEL},
       {"learnMoreShort", IDS_DIAGNOSTICS_LEARN_MORE_LABEL_SHORT},
       {"memoryAvailable", IDS_DIAGNOSTICS_MEMORY_AVAILABLE_TEXT},
+      {"memoryBannerMessage", IDS_DIAGNOSTICS_MEMORY_BANNER_MESSAGE},
       {"memoryRoutineText", IDS_DIAGNOSTICS_MEMORY_ROUTINE_TEXT},
       {"memoryTitle", IDS_DIAGNOSTICS_MEMORY_TITLE},
       {"noEthernet", IDS_DIAGNOSTICS_NO_ETHERNET},
diff --git a/ash/webui/diagnostics_ui/resources/cpu_card.html b/ash/webui/diagnostics_ui/resources/cpu_card.html
index 7428253..e24ae2c 100644
--- a/ash/webui/diagnostics_ui/resources/cpu_card.html
+++ b/ash/webui/diagnostics_ui/resources/cpu_card.html
@@ -32,7 +32,7 @@
     routine-runtime="{{getEstimateRuntimeInMinutes_(routines_)}}"
     is-test-running="{{isTestRunning}}"
     run-tests-button-text="[[i18n('runCpuTestText')]]"
-    should-show-caution-banner="true"
+    banner-message="[[i18n('cpuBannerMessage')]]"
     learn-more-link-section="cpu"
     is-active="[[isActive]]"
     hide-vertical-lines="true">
diff --git a/ash/webui/diagnostics_ui/resources/memory_card.html b/ash/webui/diagnostics_ui/resources/memory_card.html
index 1a9581b..87764f2a 100644
--- a/ash/webui/diagnostics_ui/resources/memory_card.html
+++ b/ash/webui/diagnostics_ui/resources/memory_card.html
@@ -13,6 +13,7 @@
     routine-runtime="{{getEstimateRuntimeInMinutes_(routines_, memoryUsage_)}}"
     is-test-running="{{isTestRunning}}"
     run-tests-button-text="[[i18n('runMemoryTestText')]]"
+    banner-message="[[i18n('memoryBannerMessage')]]"
     learn-more-link-section="memory"
     is-active="[[isActive]]"
     additional-message="[[getRunTestsAdditionalMessage_(
diff --git a/ash/webui/diagnostics_ui/resources/routine_section.js b/ash/webui/diagnostics_ui/resources/routine_section.js
index 10c400f..658f8e0 100644
--- a/ash/webui/diagnostics_ui/resources/routine_section.js
+++ b/ash/webui/diagnostics_ui/resources/routine_section.js
@@ -155,10 +155,10 @@
       value: loadTimeData.getBoolean('isLoggedIn'),
     },
 
-    /** @type {boolean} */
-    shouldShowCautionBanner: {
+    /** @type {string} */
+    bannerMessage: {
       type: Boolean,
-      value: false,
+      value: '',
     },
 
     /** @type {boolean} */
@@ -241,8 +241,8 @@
         this.$.collapse.show();
       }
 
-      if (this.shouldShowCautionBanner) {
-        this.showCautionBanner_(loadTimeData.getString('cpuBannerMessage'));
+      if (this.bannerMessage) {
+        this.showCautionBanner_();
       }
 
       this.routineStartTimeMs_ = performance.now();
@@ -307,7 +307,7 @@
       this.executor_ = null;
     }
 
-    if (this.shouldShowCautionBanner) {
+    if (this.bannerMessage) {
       this.dismissCautionBanner_();
     }
 
@@ -495,12 +495,13 @@
 
   /**
    * @private
-   * @param {string} message
    */
-  showCautionBanner_(message) {
-    this.dispatchEvent(new CustomEvent(
-        'show-caution-banner',
-        {bubbles: true, composed: true, detail: {message}}));
+  showCautionBanner_() {
+    this.dispatchEvent(new CustomEvent('show-caution-banner', {
+      bubbles: true,
+      composed: true,
+      detail: {message: this.bannerMessage}
+    }));
   },
 
   /** @private */
diff --git a/ash/webui/shimless_rma/resources/BUILD.gn b/ash/webui/shimless_rma/resources/BUILD.gn
index 233d6b26..196ce27 100644
--- a/ash/webui/shimless_rma/resources/BUILD.gn
+++ b/ash/webui/shimless_rma/resources/BUILD.gn
@@ -25,6 +25,7 @@
   "onboarding_wp_disable_complete_page.js",
   "reimaging_firmware_update_page.js",
   "reimaging_provisioning_page.js",
+  "repair_component_chip.js",
   "shimless_rma.js",
   "shimless_rma_shared_css.js",
   "wrapup_repair_complete_page.js",
@@ -71,6 +72,7 @@
     ":onboarding_wp_disable_complete_page",
     ":reimaging_firmware_update_page",
     ":reimaging_provisioning_page",
+    ":repair_component_chip",
     ":shimless_rma",
     ":shimless_rma_types",
     ":wrapup_repair_complete_page",
@@ -214,6 +216,12 @@
   ]
 }
 
+js_library("repair_component_chip") {
+  deps = [
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+  ]
+}
+
 js_library("wrapup_repair_complete_page") {
   deps = [
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
diff --git a/ash/webui/shimless_rma/resources/onboarding_select_components_page.html b/ash/webui/shimless_rma/resources/onboarding_select_components_page.html
index eed24d77..9ad8a20c 100644
--- a/ash/webui/shimless_rma/resources/onboarding_select_components_page.html
+++ b/ash/webui/shimless_rma/resources/onboarding_select_components_page.html
@@ -8,12 +8,12 @@
   </div>
   <div slot="body">
     <div>
-      <template is="dom-repeat" items="{{componentCheckboxes_}}" as="component" mutable-data>
-        <cr-checkbox id="[[component.id]]"
+      <template is="dom-repeat" items="{{componentCheckboxes_}}" as="component">
+        <repair-component-chip id="[[component.id]]"
           checked="{{component.checked}}"
-          disabled$="[[component.disabled]]">
-          [[component.name]]
-        </cr-checkbox>
+          disabled$="[[component.disabled]]"
+          component-name="[[component.name]]">
+        </repair-component-chip>
       </template>
     </div>
     <div>If you are reworking a motherboard to use in another device, go to the
diff --git a/ash/webui/shimless_rma/resources/onboarding_select_components_page.js b/ash/webui/shimless_rma/resources/onboarding_select_components_page.js
index ac4c76f6..b026ca6 100644
--- a/ash/webui/shimless_rma/resources/onboarding_select_components_page.js
+++ b/ash/webui/shimless_rma/resources/onboarding_select_components_page.js
@@ -2,10 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import './shimless_rma_shared_css.js';
 import './base_page.js';
+import './repair_component_chip.js';
+import './shimless_rma_shared_css.js';
 
-import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js';
+import {assert} from 'chrome://resources/js/assert.m.js';
 import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {getShimlessRmaService} from './mojo_interface_provider.js';
@@ -78,29 +79,31 @@
   ready() {
     super.ready();
     this.shimlessRmaService_ = getShimlessRmaService();
+    this.getComponents_();
+  }
+
+  /** @private */
+  getComponents_() {
     this.shimlessRmaService_.getComponentList().then((result) => {
-      if (result === undefined || result.components === undefined) {
+      if (!result || !result.hasOwnProperty('components')) {
         // TODO(gavindodd): Set an error state?
         console.error('Could not get components!');
-      } else {
-        let newComponentCheckboxes = [];
-        result.components.forEach(item => {
-          if (ComponentTypeToName.hasOwnProperty(item.component)) {
-            newComponentCheckboxes.push({
-              component: item.component,
-              id: ComponentTypeToId[item.component],
-              name: ComponentTypeToName[item.component],
-              checked: item.state === ComponentRepairState.kReplaced,
-              disabled: item.state === ComponentRepairState.kMissing
-            });
-          } else {
-            // TODO(gavindodd): Set an error state?
-            console.error(
-                'Could not find name for component ' + item.component);
-          }
-        });
-        this.componentCheckboxes_ = newComponentCheckboxes;
+        return;
       }
+
+      let componentList = [];
+      result.components.forEach(item => {
+        const component = assert(item.component);
+
+        componentList.push({
+          component: item.component,
+          id: ComponentTypeToId[item.component],
+          name: ComponentTypeToName[item.component],
+          checked: item.state === ComponentRepairState.kReplaced,
+          disabled: item.state === ComponentRepairState.kMissing
+        });
+      });
+      this.componentCheckboxes_ = componentList;
     });
   }
 
diff --git a/ash/webui/shimless_rma/resources/repair_component_chip.html b/ash/webui/shimless_rma/resources/repair_component_chip.html
new file mode 100644
index 0000000..70c603e
--- /dev/null
+++ b/ash/webui/shimless_rma/resources/repair_component_chip.html
@@ -0,0 +1,36 @@
+<style include="cr-shared-style shimless-rma-shared">
+  :host {
+    padding: 1px;
+  }
+
+  /* TODO(joonbug): update colors to CrOS */
+  :host([checked]) #containerButton {
+    background-color: lightskyblue;
+  }
+
+  #containerButton {
+    width:  180px;
+    height: 40px;
+    border-radius: 10px;
+    box-shadow: 0px 2px 2px 2px #bbb;
+  }
+
+  .checkedBox {
+    background-color: lightblue;
+    position: absolute;
+    top: 5px;
+    right: 5px;
+    width: 15px;
+    height:  15px;
+  }
+
+</style>
+
+<div>
+  <cr-button disabled$="[[disabled]]"
+      id="containerButton" on-click="onComponentButtonClicked_">
+    <span id="componentName">[[componentName]]</span>
+    <!-- TODO(joonbug): replace with iron-icon -->
+    <span hidden$="[[!checked]]" class="checkedBox"></span>
+  </cr-button>
+</div>
\ No newline at end of file
diff --git a/ash/webui/shimless_rma/resources/repair_component_chip.js b/ash/webui/shimless_rma/resources/repair_component_chip.js
new file mode 100644
index 0000000..5de86a6f
--- /dev/null
+++ b/ash/webui/shimless_rma/resources/repair_component_chip.js
@@ -0,0 +1,57 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
+import './shimless_rma_shared_css.js';
+
+import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+/**
+ * @fileoverview
+ * 'repair-component-chip' represents a single component chip that can be marked
+ * as replaced.
+ */
+
+export class RepairComponentChipElement extends PolymerElement {
+  static get is() {
+    return 'repair-component-chip';
+  }
+
+  static get template() {
+    return html`{__html_template__}`;
+  }
+
+  static get properties() {
+    return {
+      /** @type {boolean} */
+      disabled: {
+        type: Boolean,
+        value: false,
+      },
+
+      /** @type {boolean} */
+      checked: {
+        notify: true,
+        reflectToAttribute: true,
+        type: Boolean,
+        value: false,
+      },
+
+      /** @type {string} */
+      componentName: {type: String, value: ''}
+    };
+  }
+
+  /** @protected */
+  onComponentButtonClicked_() {
+    this.checked = !this.checked;
+  }
+
+  click() {
+    this.onComponentButtonClicked_();
+  }
+};
+
+customElements.define(
+    RepairComponentChipElement.is, RepairComponentChipElement);
diff --git a/ash/wm/desks/persistent_desks_bar_controller.cc b/ash/wm/desks/persistent_desks_bar_controller.cc
index 78e41bd..99dad61 100644
--- a/ash/wm/desks/persistent_desks_bar_controller.cc
+++ b/ash/wm/desks/persistent_desks_bar_controller.cc
@@ -14,6 +14,7 @@
 #include "ash/wm/desks/persistent_desks_bar_view.h"
 #include "ash/wm/overview/overview_controller.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
+#include "ash/wm/work_area_insets.h"
 #include "base/metrics/histogram_macros.h"
 #include "ui/aura/window.h"
 #include "ui/display/screen.h"
@@ -85,10 +86,8 @@
     DestroyBarWidget();
 }
 
-void PersistentDesksBarController::OnOverviewModeStartingAnimationComplete(
-    bool canceled) {
-  if (!canceled)
-    DestroyBarWidget();
+void PersistentDesksBarController::OnOverviewModeWillStart() {
+  DestroyBarWidget();
 }
 
 void PersistentDesksBarController::OnOverviewModeEndingAnimationComplete(
@@ -228,11 +227,21 @@
   }
   persistent_desks_bar_view_->RefreshDeskButtons();
   persistent_desks_bar_widget_->Show();
+
+  // Update work area on the persistent desks bar's state. Note, the bar is only
+  // created in the primary display.
+  WorkAreaInsets::ForWindow(Shell::GetPrimaryRootWindow())
+      ->SetPersistentDeskBarHeight(kBarHeight);
 }
 
 void PersistentDesksBarController::DestroyBarWidget() {
   persistent_desks_bar_widget_.reset();
   persistent_desks_bar_view_ = nullptr;
+
+  // Update work area on the persistent desks bar's state. Note, the bar is only
+  // created in the primary display.
+  WorkAreaInsets::ForWindow(Shell::GetPrimaryRootWindow())
+      ->SetPersistentDeskBarHeight(0);
 }
 
 }  // namespace ash
diff --git a/ash/wm/desks/persistent_desks_bar_controller.h b/ash/wm/desks/persistent_desks_bar_controller.h
index 9a1ef9f..060d47d 100644
--- a/ash/wm/desks/persistent_desks_bar_controller.h
+++ b/ash/wm/desks/persistent_desks_bar_controller.h
@@ -57,7 +57,7 @@
   void OnSessionStateChanged(session_manager::SessionState state) override;
 
   // OverviewObserver:
-  void OnOverviewModeStartingAnimationComplete(bool canceled) override;
+  void OnOverviewModeWillStart() override;
   void OnOverviewModeEndingAnimationComplete(bool canceled) override;
 
   // DesksController::Observer:
diff --git a/ash/wm/full_restore/full_restore_controller.cc b/ash/wm/full_restore/full_restore_controller.cc
index 36cca00..d32e2e0 100644
--- a/ash/wm/full_restore/full_restore_controller.cc
+++ b/ash/wm/full_restore/full_restore_controller.cc
@@ -48,7 +48,7 @@
 FullRestoreController::SaveWindowCallback g_save_window_callback_for_testing;
 
 // The list of possible app window parents.
-constexpr ShellWindowId kAppParentContainers[9] = {
+constexpr ShellWindowId kAppParentContainers[10] = {
     kShellWindowId_DefaultContainerDeprecated,
     kShellWindowId_DeskContainerB,
     kShellWindowId_DeskContainerC,
@@ -58,6 +58,7 @@
     kShellWindowId_DeskContainerG,
     kShellWindowId_DeskContainerH,
     kShellWindowId_AlwaysOnTopContainer,
+    kShellWindowId_UnparentedContainer,
 };
 
 // The types of apps currently supported by full restore.
@@ -161,6 +162,32 @@
   }
 }
 
+// Self deleting class which watches a unparented window and deletes itself once
+// the window has a parent.
+class ParentChangeObserver : public aura::WindowObserver {
+ public:
+  ParentChangeObserver(aura::Window* window) {
+    DCHECK(!window->parent());
+    window_observation_.Observe(window);
+  }
+  ParentChangeObserver(const ParentChangeObserver&) = delete;
+  ParentChangeObserver& operator=(const ParentChangeObserver&) = delete;
+  ~ParentChangeObserver() override = default;
+
+  // aura::WindowObserver:
+  void OnWindowParentChanged(aura::Window* window,
+                             aura::Window* parent) override {
+    if (!parent)
+      return;
+    FullRestoreController::Get()->SaveAllWindows();
+    delete this;
+  }
+  void OnWindowDestroying(aura::Window* window) override { delete this; }
+
+  base::ScopedObservation<aura::Window, aura::WindowObserver>
+      window_observation_{this};
+};
+
 }  // namespace
 
 FullRestoreController::FullRestoreController() {
@@ -218,6 +245,18 @@
   SaveWindowImpl(window_state, /*activation_index=*/absl::nullopt);
 }
 
+void FullRestoreController::SaveAllWindows() {
+  auto mru_windows =
+      Shell::Get()->mru_window_tracker()->BuildMruWindowList(kAllDesks);
+  for (int i = 0; i < static_cast<int>(mru_windows.size()); ++i) {
+    // Provide the activation index here since we need to loop through `windows`
+    // anyhow. Otherwise we need to loop again to get the same value in
+    // `SaveWindowImpl()`.
+    WindowState* window_state = WindowState::Get(mru_windows[i]);
+    SaveWindowImpl(window_state, /*activation_index=*/i);
+  }
+}
+
 void FullRestoreController::OnWindowActivated(aura::Window* gained_active) {
   DCHECK(gained_active);
 
@@ -246,6 +285,24 @@
     SaveAllWindows();
 }
 
+void FullRestoreController::OnAppLaunched(aura::Window* window) {
+  // Non ARC windows will already be saved as this point, as this is for cases
+  // where an ARC window is created without a task.
+  if (!IsArcWindow(window))
+    return;
+
+  // Save the window info once the app launched. If `window` does not have a
+  // parent yet, there won't be any window state, so create an observer that
+  // will save when `window` gets a parent. Save all windows since we need to
+  // update the activation index of the other windows.
+  if (window->parent()) {
+    SaveAllWindows();
+    return;
+  }
+
+  new ParentChangeObserver(window);
+}
+
 void FullRestoreController::OnWidgetInitialized(views::Widget* widget) {
   DCHECK(widget);
 
@@ -413,18 +470,6 @@
   }
 }
 
-void FullRestoreController::SaveAllWindows() {
-  auto mru_windows =
-      Shell::Get()->mru_window_tracker()->BuildMruWindowList(kAllDesks);
-  for (int i = 0; i < static_cast<int>(mru_windows.size()); ++i) {
-    // Provide the activation index here since we need to loop through |windows|
-    // anyhow. Otherwise we need to loop again to get the same value in
-    // SaveWindowImpl().
-    WindowState* window_state = WindowState::Get(mru_windows[i]);
-    SaveWindowImpl(window_state, /*activation_index=*/i);
-  }
-}
-
 void FullRestoreController::SaveWindowImpl(
     WindowState* window_state,
     absl::optional<int> activation_index) {
diff --git a/ash/wm/full_restore/full_restore_controller.h b/ash/wm/full_restore/full_restore_controller.h
index 6ae4e20..619fd08 100644
--- a/ash/wm/full_restore/full_restore_controller.h
+++ b/ash/wm/full_restore/full_restore_controller.h
@@ -60,6 +60,10 @@
   // calculated in SaveWindowImpl.
   void SaveWindow(WindowState* window_state);
 
+  // Gets all windows on all desk in the MRU window tracker and saves them to
+  // file.
+  void SaveAllWindows();
+
   // Called from MruWindowTracker when |gained_active| gets activation. This is
   // not done as an observer to ensure changes to the MRU list get handled first
   // before this is called.
@@ -73,6 +77,7 @@
   // full_restore::FullRestoreInfo::Observer:
   void OnRestorePrefChanged(const AccountId& account_id,
                             bool could_restore) override;
+  void OnAppLaunched(aura::Window* window) override;
   void OnWidgetInitialized(views::Widget* widget) override;
   void OnARCTaskReadyForUnparentedWindow(aura::Window* window) override;
 
@@ -94,10 +99,6 @@
   // shown.
   void UpdateAndObserveWindow(aura::Window* window);
 
-  // Gets all windows on all desk in the MRU window tracker and saves them to
-  // file.
-  void SaveAllWindows();
-
   // Calls full_restore::FullRestoreSaveHandler to save to file. The handler has
   // timer to prevent too many writes, but we should limit calls regardless if
   // possible. Optionally passes |activation_index|, which is calculated with
@@ -120,6 +121,7 @@
   // Cancels and removes the Full Restore property clear callback for `window`
   // from `restore_property_clear_callbacks_`.
   void CancelAndRemoveRestorePropertyClearCallback(aura::Window* window);
+
   // Sets a callback for testing that will be fired immediately when
   // SaveWindowImpl is about to notify the full restore component we want to
   // write to file.
diff --git a/ash/wm/mru_window_tracker.cc b/ash/wm/mru_window_tracker.cc
index 463c752..ae59471 100644
--- a/ash/wm/mru_window_tracker.cc
+++ b/ash/wm/mru_window_tracker.cc
@@ -197,6 +197,11 @@
 }  // namespace
 
 bool CanIncludeWindowInMruList(aura::Window* window) {
+  // If `window` was launched from Full Restore it won't be activatable
+  // temporarily, but it should still be included in the MRU list.
+  if (window->GetProperty(full_restore::kLaunchedFromFullRestoreKey))
+    return true;
+
   return wm::CanActivateWindow(window) &&
          !window->GetProperty(ash::kExcludeInMruKey);
 }
diff --git a/ash/wm/mru_window_tracker_unittest.cc b/ash/wm/mru_window_tracker_unittest.cc
index 7a00a61..1c72803 100644
--- a/ash/wm/mru_window_tracker_unittest.cc
+++ b/ash/wm/mru_window_tracker_unittest.cc
@@ -17,6 +17,7 @@
 #include "ui/base/hit_test.h"
 #include "ui/base/ui_base_types.h"
 #include "ui/views/widget/widget_delegate.h"
+#include "ui/wm/core/window_util.h"
 
 namespace ash {
 
@@ -226,6 +227,25 @@
                          user_created_window.get()});
 }
 
+// Tests that Full Restore'd windows are included in the MRU window list. See
+// crbug.com/1229260.
+TEST_F(MruWindowTrackerFullRestoreTest, FullRestoredWindowsInMRUWindowList) {
+  // Create an `aura::Window` using `CreateTestWindow()` so that the window is
+  // parented to something. Then set its
+  // `full_restore::kLaunchedFromFullRestoreKey` to simulate it being Full
+  // Restore'd. `w1` should not be activatable.
+  std::unique_ptr<aura::Window> w1(CreateTestWindow());
+  w1.get()->SetProperty(full_restore::kLaunchedFromFullRestoreKey, true);
+  ASSERT_FALSE(wm::CanActivateWindow(w1.get()));
+
+  // Build the MRU window list. `w1` should be included despite not being
+  // activatable.
+  MruWindowTracker::WindowList window_list =
+      mru_window_tracker()->BuildMruWindowList(kAllDesks);
+  EXPECT_EQ(1u, window_list.size());
+  EXPECT_EQ(w1.get(), window_list[0]);
+}
+
 INSTANTIATE_TEST_SUITE_P(MruWindowTrackerOrder,
                          MruWindowTrackerOrderTest,
                          /*use ignore modal=*/::testing::Bool());
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc
index 809973e9..2d3087f 100644
--- a/ash/wm/splitview/split_view_controller.cc
+++ b/ash/wm/splitview/split_view_controller.cc
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "ash/accessibility/accessibility_controller_impl.h"
+#include "ash/constants/ash_features.h"
 #include "ash/display/screen_orientation_controller.h"
 #include "ash/public/cpp/metrics_util.h"
 #include "ash/public/cpp/presentation_time_recorder.h"
@@ -39,6 +40,7 @@
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_transient_descendant_iterator.h"
 #include "ash/wm/window_util.h"
+#include "base/auto_reset.h"
 #include "base/bind.h"
 #include "base/containers/contains.h"
 #include "base/containers/flat_set.h"
@@ -46,6 +48,7 @@
 #include "base/metrics/user_metrics.h"
 #include "base/numerics/ranges.h"
 #include "base/system/sys_info.h"
+#include "chromeos/ui/base/window_properties.h"
 #include "components/full_restore/features.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/aura/client/aura_constants.h"
@@ -89,6 +92,16 @@
 constexpr float kBlackScrimFadeInRatio = 0.1f;
 constexpr float kBlackScrimOpacity = 0.4f;
 
+// If performant split view resizing is enabled, the speed at which the divider
+// is moved controls whether windows are scaled or translated. If the divider is
+// moved more than this many pixels per second, the "fast" mode is enabled.
+constexpr int kPerformantSplitViewThresholdPixelsPerSec = 72;
+
+// If performant split view resizing is enabled, this is how often the divider
+// drag speed is checked.
+constexpr base::TimeDelta kPerformantSplitViewChunkTime =
+    base::TimeDelta::FromMilliseconds(500);
+
 // Records the animation smoothness when the divider is released during a resize
 // and animated to a fixed position ratio.
 constexpr char kDividerAnimationSmoothness[] =
@@ -157,8 +170,8 @@
   return WindowStateType::kDefault;
 }
 
-// Returns the minimum size of the window according to the screen orientation.
-int GetMinimumWindowSize(aura::Window* window, bool horizontal) {
+// Returns the minimum length of the window according to the screen orientation.
+int GetMinimumWindowLength(aura::Window* window, bool horizontal) {
   int minimum_width = 0;
   if (window && window->delegate()) {
     gfx::Size minimum_size = window->delegate()->GetMinimumSize();
@@ -167,6 +180,12 @@
   return minimum_width;
 }
 
+// Returns the length of the window according to the screen orientation.
+int GetWindowLength(aura::Window* window, bool horizontal) {
+  const auto& bounds = window->bounds();
+  return horizontal ? bounds.width() : bounds.height();
+}
+
 // Returns true if |window| is currently snapped.
 bool IsSnapped(aura::Window* window) {
   if (!window)
@@ -350,8 +369,10 @@
     split_view_controller_->NotifyDividerPositionChanged();
     split_view_controller_->UpdateSnappedWindowsAndDividerBounds();
     // Updating the window may stop animation.
-    if (is_animating())
+    if (is_animating()) {
+      split_view_controller_->UpdateResizeBackdrop();
       split_view_controller_->SetWindowsTransformDuringResizing();
+    }
   }
 
   void AnimationCanceled(const gfx::Animation* animation) override {
@@ -750,7 +771,7 @@
   if (!restoring_snap_state && !wm::CanActivateWindow(window))
     return false;
 
-  return GetMinimumWindowSize(window, IsLayoutHorizontal()) <=
+  return GetMinimumWindowLength(window, IsLayoutHorizontal()) <=
          GetDividerEndPosition() / 2 - kSplitviewDividerShortSideLength / 2;
 }
 
@@ -982,6 +1003,12 @@
   if (snap_position == NONE)
     return work_area_bounds_in_screen;
 
+  if (window_for_minimum_size && ShouldUseWindowBoundsDuringFastResize()) {
+    gfx::Rect bounds = window_for_minimum_size->bounds();
+    ::wm::ConvertRectToScreen(window_for_minimum_size->parent(), &bounds);
+    return bounds;
+  }
+
   const bool horizontal = IsLayoutHorizontal();
   const bool snap_left_or_top = IsPhysicalLeftOrTop(snap_position);
   const bool in_tablet = Shell::Get()->tablet_mode_controller()->InTabletMode();
@@ -1000,7 +1027,8 @@
       window_size -= kSplitviewDividerShortSideLength;
   }
 
-  const int minimum = GetMinimumWindowSize(window_for_minimum_size, horizontal);
+  const int minimum =
+      GetMinimumWindowLength(window_for_minimum_size, horizontal);
   DCHECK(window_for_minimum_size || minimum == 0);
   if (window_size < minimum) {
     if (in_tablet && !is_resizing_) {
@@ -1038,6 +1066,10 @@
   return snapped_window_bounds_in_screen;
 }
 
+bool SplitViewController::ShouldUseWindowBoundsDuringFastResize() {
+  return is_resizing_ && tablet_resize_mode_ == TabletResizeMode::kFast;
+}
+
 int SplitViewController::GetDefaultDividerPosition() const {
   int default_divider_position = GetDividerEndPosition() / 2;
   if (split_view_type_ == SplitViewType::kTabletType)
@@ -1066,6 +1098,11 @@
   split_view_divider_->UpdateDividerBounds();
   previous_event_location_ = location_in_screen;
 
+  accumulated_drag_time_ticks_ = base::TimeTicks::Now();
+  accumulated_drag_distance_ = 0;
+
+  tablet_resize_mode_ = TabletResizeMode::kNormal;
+
   for (auto* window : {left_window_, right_window_}) {
     if (window == nullptr)
       continue;
@@ -1106,6 +1143,9 @@
 
   if (!is_resizing_)
     return;
+
+  base::AutoReset<bool> auto_reset(&processing_resize_event_, true);
+
   presentation_time_recorder_->RequestNext();
   const gfx::Rect work_area_bounds =
       screen_util::GetDisplayWorkAreaBoundsInScreenForActiveDeskContainer(
@@ -1113,16 +1153,30 @@
   gfx::Point modified_location_in_screen =
       GetBoundedPosition(location_in_screen, work_area_bounds);
 
+  // This updates `tablet_resize_mode_` based on drag speed.
+  UpdateTabletResizeMode(base::TimeTicks::Now(), modified_location_in_screen);
+
+  // If we are in the fast mode, start a timer that automatically invokes
+  // `Resize()` after a timeout. This ensure that we can switch back to the
+  // normal mode if the user stops dragging. Note: if the timer is already
+  // active, this will simply move the deadline forward.
+  if (tablet_resize_mode_ == TabletResizeMode::kFast) {
+    resize_timer_.Start(FROM_HERE, kPerformantSplitViewChunkTime, this,
+                        &SplitViewController::OnResizeTimer);
+  }
+
   // Update |divider_position_|.
   UpdateDividerPosition(modified_location_in_screen);
   NotifyDividerPositionChanged();
 
-  // Update the black scrim layer's bounds and opacity.
-  UpdateBlackScrim(modified_location_in_screen);
-
   // Update the snapped window/windows and divider's position.
   UpdateSnappedWindowsAndDividerBounds();
 
+  // Update the resize backdrop, as well as the black scrim layer's bounds and
+  // opacity.
+  UpdateResizeBackdrop();
+  UpdateBlackScrim(modified_location_in_screen);
+
   // Apply window transform if necessary.
   SetWindowsTransformDuringResizing();
 
@@ -1136,6 +1190,9 @@
     return;
   // TODO(xdai): Use fade out animation instead of just removing it.
   black_scrim_layer_.reset();
+
+  resize_timer_.Stop();
+  tablet_resize_mode_ = TabletResizeMode::kNormal;
   is_resizing_ = false;
 
   const gfx::Rect work_area_bounds =
@@ -1368,6 +1425,17 @@
     ui::PropertyChangeReason reason) {
   DCHECK_EQ(root_window_, window->GetRootWindow());
 
+  if (InTabletSplitViewMode() && is_resizing_) {
+    // Bounds may be changed while we are processing a resize event. In this
+    // case, we don't update the windows transform here, since it will be done
+    // soon anyway. If we are *not* currently processing a resize, it means the
+    // bounds of a window have been updated "async", and we need to update the
+    // window's transform.
+    if (!processing_resize_event_)
+      SetWindowsTransformDuringResizing();
+    return;
+  }
+
   if (!InClamshellSplitViewMode())
     return;
 
@@ -1822,8 +1890,8 @@
     black_scrim_layer_.reset();
     return;
   }
-  black_scrim_layer_->SetBounds(
-      GetSnappedWindowBoundsInScreen(position, GetSnappedWindow(position)));
+  black_scrim_layer_->SetBounds(GetSnappedWindowBoundsInScreen(
+      position, /*window_for_minimum_size=*/nullptr));
 
   // Update its opacity. The opacity increases as it gets closer to the edge of
   // the screen.
@@ -1847,6 +1915,44 @@
   black_scrim_layer_->SetOpacity(opacity);
 }
 
+void SplitViewController::UpdateResizeBackdrop() {
+  if (!features::IsPerformantSplitViewResizingEnabled())
+    return;
+
+  // Creates a backdrop layer. It is stacked below the snapped window.
+  auto create_backdrop = [](aura::Window* window) {
+    auto resize_backdrop_layer =
+        std::make_unique<ui::Layer>(ui::LAYER_SOLID_COLOR);
+
+    ui::Layer* parent = window->layer()->parent();
+    ui::Layer* stacking_target = window->layer();
+    parent->Add(resize_backdrop_layer.get());
+    parent->StackBelow(resize_backdrop_layer.get(), stacking_target);
+
+    return resize_backdrop_layer;
+  };
+
+  // Updates the bounds and color of a backdrop.
+  auto update_backdrop = [this](SnapPosition position, aura::Window* window,
+                                ui::Layer* backdrop) {
+    backdrop->SetBounds(GetSnappedWindowBoundsInParent(position, nullptr));
+    backdrop->SetColor(window->GetProperty(
+        wm::IsActiveWindow(window) ? chromeos::kFrameActiveColorKey
+                                   : chromeos::kFrameInactiveColorKey));
+  };
+
+  if (state_ == State::kLeftSnapped || state_ == State::kBothSnapped) {
+    if (!left_resize_backdrop_layer_)
+      left_resize_backdrop_layer_ = create_backdrop(left_window_);
+    update_backdrop(LEFT, left_window_, left_resize_backdrop_layer_.get());
+  }
+  if (state_ == State::kRightSnapped || state_ == State::kBothSnapped) {
+    if (!right_resize_backdrop_layer_)
+      right_resize_backdrop_layer_ = create_backdrop(right_window_);
+    update_backdrop(RIGHT, right_window_, right_resize_backdrop_layer_.get());
+  }
+}
+
 void SplitViewController::UpdateSnappedWindowsAndDividerBounds() {
   // Update the snapped windows' bounds.
   if (IsSnapped(left_window_)) {
@@ -2086,9 +2192,9 @@
     std::vector<float>* out_position_ratios) {
   const bool landscape = IsCurrentScreenOrientationLandscape();
   const int min_left_size =
-      GetMinimumWindowSize(GetPhysicalLeftOrTopWindow(), landscape);
+      GetMinimumWindowLength(GetPhysicalLeftOrTopWindow(), landscape);
   const int min_right_size =
-      GetMinimumWindowSize(GetPhysicalRightOrBottomWindow(), landscape);
+      GetMinimumWindowLength(GetPhysicalRightOrBottomWindow(), landscape);
   const int divider_end_position = GetDividerEndPosition();
   const float min_size_left_ratio =
       static_cast<float>(min_left_size) / divider_end_position;
@@ -2171,9 +2277,8 @@
   gfx::Transform left_or_top_transform;
   if (left_or_top_window) {
     const int left_size = divider_position_;
-    const int left_minimum_size =
-        GetMinimumWindowSize(left_or_top_window, horizontal);
-    const int distance = left_size - left_minimum_size;
+    const int distance =
+        left_size - GetWindowLength(left_or_top_window, horizontal);
     if (distance < 0) {
       left_or_top_transform.Translate(horizontal ? distance : 0,
                                       horizontal ? 0 : distance);
@@ -2185,21 +2290,14 @@
   if (right_or_bottom_window) {
     const int right_size = GetDividerEndPosition() - divider_position_ -
                            kSplitviewDividerShortSideLength;
-    const int right_minimum_size =
-        GetMinimumWindowSize(right_or_bottom_window, horizontal);
-    const int distance = right_size - right_minimum_size;
+    const int distance =
+        right_size - GetWindowLength(right_or_bottom_window, horizontal);
     if (distance < 0) {
       right_or_bottom_transform.Translate(horizontal ? -distance : 0,
                                           horizontal ? 0 : -distance);
     }
     SetTransform(right_or_bottom_window, right_or_bottom_transform);
   }
-
-  if (black_scrim_layer_.get()) {
-    black_scrim_layer_->SetTransform(left_or_top_transform.IsIdentity()
-                                         ? right_or_bottom_transform
-                                         : left_or_top_transform);
-  }
 }
 
 void SplitViewController::RestoreWindowsTransformAfterResizing() {
@@ -2271,13 +2369,59 @@
 void SplitViewController::EndResizeImpl() {
   DCHECK(InSplitViewMode());
   DCHECK(!is_resizing_);
+
+  // The backdrop layers are removed here (rather than in `EndResize()`) since
+  // they may be used while the divider is animating to a snapped position.
+  left_resize_backdrop_layer_.reset();
+  right_resize_backdrop_layer_.reset();
+
   // Resize may not end with |EndResize()|, so make sure to clear here too.
+  resize_timer_.Stop();
   presentation_time_recorder_.reset();
   RestoreWindowsTransformAfterResizing();
   FinishWindowResizing(left_window_);
   FinishWindowResizing(right_window_);
 }
 
+void SplitViewController::OnResizeTimer() {
+  if (InSplitViewMode())
+    Resize(previous_event_location_);
+}
+
+void SplitViewController::UpdateTabletResizeMode(
+    base::TimeTicks event_time_ticks,
+    const gfx::Point& event_location) {
+  if (!features::IsPerformantSplitViewResizingEnabled())
+    return;
+
+  if (IsLayoutHorizontal()) {
+    accumulated_drag_distance_ +=
+        std::abs(event_location.x() - previous_event_location_.x());
+  } else {
+    accumulated_drag_distance_ +=
+        std::abs(event_location.y() - previous_event_location_.y());
+  }
+
+  const base::TimeDelta chunk_time_ticks =
+      event_time_ticks - accumulated_drag_time_ticks_;
+  // We switch between fast and normal resize mode depending on how fast the
+  // divider is dragged. This is done in "chunks" by keeping track of how far
+  // the divider has been dragged. When the chunk gone on for long enough, we
+  // calculate the drag speed based on `accumulated_drag_distance_` and update
+  // the resize mode accordingly.
+  if (chunk_time_ticks >= kPerformantSplitViewChunkTime) {
+    int drag_per_second =
+        accumulated_drag_distance_ / chunk_time_ticks.InSecondsF();
+    tablet_resize_mode_ =
+        drag_per_second > kPerformantSplitViewThresholdPixelsPerSec
+            ? TabletResizeMode::kFast
+            : TabletResizeMode::kNormal;
+
+    accumulated_drag_time_ticks_ = event_time_ticks;
+    accumulated_drag_distance_ = 0;
+  }
+}
+
 void SplitViewController::EndWindowDragImpl(
     aura::Window* window,
     bool is_being_destroyed,
diff --git a/ash/wm/splitview/split_view_controller.h b/ash/wm/splitview/split_view_controller.h
index 3fb162b8..541b9ddb 100644
--- a/ash/wm/splitview/split_view_controller.h
+++ b/ash/wm/splitview/split_view_controller.h
@@ -92,6 +92,14 @@
     kBothSnapped,
   };
 
+  // The split view resize behavior in tablet mode. The normal mode resizes
+  // windows on drag events. In the fast mode, windows are instead moved. A
+  // single drag "session" may involve both modes.
+  enum class TabletResizeMode {
+    kNormal,
+    kFast,
+  };
+
   // Gets the |SplitViewController| for the root window of |window|. |window| is
   // important in clamshell mode. In tablet mode, the working assumption for now
   // is mirror mode (or just one display), and so |window| can be almost any
@@ -193,6 +201,11 @@
       SnapPosition snap_position,
       aura::Window* window_for_minimum_size);
 
+  // Returns true if we are resizing with the fast resize
+  // mode. `GetSnappedWindowBoundsInScreen()` should then return the windows
+  // current bounds in screen coordinates.
+  bool ShouldUseWindowBoundsDuringFastResize();
+
   // Gets the default value of |divider_position_|.
   int GetDefaultDividerPosition() const;
 
@@ -298,6 +311,9 @@
   SplitViewMetricsController* split_view_metrics_controller() {
     return split_view_metrics_controller_.get();
   }
+  aura::Window* to_be_activated_window() const {
+    return to_be_activated_window_;
+  }
 
  private:
   friend class SplitViewControllerTest;
@@ -342,6 +358,11 @@
   // of the screen.
   void UpdateBlackScrim(const gfx::Point& location_in_screen);
 
+  // Updates the resize mode backdrop. This is drawn behind windows to ensure
+  // that the allotted space is always filled, even if the window itself hasn't
+  // resized yet.
+  void UpdateResizeBackdrop();
+
   // Updates the bounds for the snapped windows and divider according to the
   // current snap direction.
   void UpdateSnappedWindowsAndDividerBounds();
@@ -448,6 +469,15 @@
   // snapping animation completes or is interrupted or totally skipped.
   void EndResizeImpl();
 
+  // Called from a timer during resizing. Facilitates switching between fast and
+  // normal tablet resizing modes.
+  void OnResizeTimer();
+
+  // Figure out which resize mode we should be using. This is based on the speed
+  // at which the divider is dragged.
+  void UpdateTabletResizeMode(base::TimeTicks event_time_ticks,
+                              const gfx::Point& event_location);
+
   // Called by OnWindowDragEnded to do the actual work of finishing the window
   // dragging. If |is_being_destroyed| equals true, the dragged window is to be
   // destroyed, and SplitViewController should not try to put it in splitview.
@@ -481,6 +511,10 @@
   // closer to the edge of the screen.
   std::unique_ptr<ui::Layer> black_scrim_layer_;
 
+  // Backdrop layers that may be visible below windows when resizing.
+  std::unique_ptr<ui::Layer> left_resize_backdrop_layer_;
+  std::unique_ptr<ui::Layer> right_resize_backdrop_layer_;
+
   // The window observer that obseves the tab-dragged window in tablet mode.
   std::unique_ptr<TabDraggedWindowObserver> dragged_window_observer_;
 
@@ -562,6 +596,21 @@
   // should remain to be the active window.
   aura::Window* to_be_activated_window_ = nullptr;
 
+  // The split view resize mode for tablet mode.
+  TabletResizeMode tablet_resize_mode_ = TabletResizeMode::kNormal;
+
+  // True *while* a resize event is being processed.
+  bool processing_resize_event_ = false;
+
+  // Accumulated drag distance, during a time interval.
+  int accumulated_drag_distance_ = 0;
+  base::TimeTicks accumulated_drag_time_ticks_;
+
+  // Used to potentially invoke `Resize()` during resizes. This is so that
+  // tablet resize mode can switch to normal mode (letting windows be resized)
+  // even if the divider isn't moved.
+  base::OneShotTimer resize_timer_;
+
   DISALLOW_COPY_AND_ASSIGN(SplitViewController);
 };
 
diff --git a/ash/wm/splitview/split_view_metrics_controller.cc b/ash/wm/splitview/split_view_metrics_controller.cc
index 1919c35..7853d10 100644
--- a/ash/wm/splitview/split_view_metrics_controller.cc
+++ b/ash/wm/splitview/split_view_metrics_controller.cc
@@ -5,13 +5,27 @@
 #include "ash/wm/splitview/split_view_metrics_controller.h"
 
 #include "ash/root_window_controller.h"
+#include "ash/root_window_settings.h"
 #include "ash/shell.h"
+#include "ash/wm/desks/desk.h"
+#include "ash/wm/desks/desks_util.h"
+#include "ash/wm/mru_window_tracker.h"
 #include "ash/wm/overview/overview_controller.h"
 #include "ash/wm/splitview/split_view_controller.h"
+#include "ash/wm/switchable_windows.h"
+#include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
+#include "base/check_op.h"
+#include "base/containers/adapters.h"
+#include "base/containers/contains.h"
 #include "base/metrics/histogram_functions.h"
+#include "chromeos/ui/base/window_state_type.h"
+#include "components/full_restore/full_restore_utils.h"
+#include "components/full_restore/window_info.h"
+#include "ui/aura/env.h"
 #include "ui/display/manager/display_manager.h"
 #include "ui/display/screen.h"
+#include "ui/wm/public/activation_client.h"
 
 namespace ash {
 
@@ -52,16 +66,32 @@
 constexpr base::TimeTicks kInvalidTime = base::TimeTicks::Max();
 
 // Start time of clamshell and tablet multi-display split view.
-base::TimeTicks g_tablet_multi_display_split_view_start_time;
 base::TimeTicks g_clamshell_multi_display_split_view_start_time;
+base::TimeTicks g_tablet_multi_display_split_view_start_time;
+
+// An accumulator of clamshell multi-display split view engagement time. When
+// the clamshell split view with two windows snapped on both sides is paused
+// (the definition of "pause" is defined in the comments at the beginning of the
+// the header file), accumulate the current engagement time period.
+int64_t g_clamshell_multi_display_split_view_time_ms;
+
+bool IsRecordingClamshellMultiDisplaySplitView() {
+  return g_clamshell_multi_display_split_view_start_time != kInvalidTime;
+}
+
+bool IsRecordingTabletMultiDisplaySplitView() {
+  return g_tablet_multi_display_split_view_start_time != kInvalidTime;
+}
 
 // Number of root windows in split view.
-int NumRootWindowsInSplitView() {
+int NumRootWindowsInSplitViewRecording() {
   auto root_windows = Shell::GetAllRootWindows();
-  return std::count_if(
-      root_windows.begin(), root_windows.end(), [](aura::Window* root_window) {
-        return SplitViewController::Get(root_window)->InSplitViewMode();
-      });
+  return std::count_if(root_windows.begin(), root_windows.end(),
+                       [](aura::Window* root_window) {
+                         return SplitViewController::Get(root_window)
+                             ->split_view_metrics_controller()
+                             ->in_split_view_recording();
+                       });
 }
 
 // Checks if the device is in tablet mode.
@@ -69,6 +99,37 @@
   return Shell::Get()->tablet_mode_controller()->InTabletMode();
 }
 
+bool TopTwoVisibleWindowsBothSnapped(
+    const std::vector<aura::Window*>& windows) {
+  int windows_size = windows.size();
+  if (windows_size < 2)
+    return false;
+
+  // Check if there are snapped windows on both sides without hidden by other
+  // windows. The topmost window is at the end of the list.
+  WindowState* top_snap_window_state = WindowState::Get(windows.back());
+  if (!top_snap_window_state->IsSnapped())
+    return false;
+
+  for (auto* window : base::Reversed(windows)) {
+    // Skip the top one.
+    if (window == windows.back())
+      continue;
+
+    auto* window_state = WindowState::Get(window);
+    // Skip the invisible windows.
+    if (!window->IsVisible())
+      continue;
+    if (!window_state->IsSnapped())
+      return false;
+    if (window_state->GetStateType() == top_snap_window_state->GetStateType())
+      continue;
+    else
+      return true;
+  }
+  return false;
+}
+
 }  // namespace
 
 // static
@@ -91,28 +152,38 @@
   tablet_mode_controller_observation_.Observe(
       Shell::Get()->tablet_mode_controller());
   Shell::Get()->display_manager()->AddObserver(this);
+  Shell::Get()->activation_client()->AddObserver(this);
+
+  auto* desks_controller = Shell::Get()->desks_controller();
+  desks_controller->AddObserver(this);
+  current_desk_ = desks_controller->active_desk();
+
+  aura::Env::GetInstance()->AddObserver(this);
 
   orientation_ = SplitViewController::IsLayoutHorizontal()
                      ? DeviceOrientation::kLandscape
                      : DeviceOrientation::kPortrait;
-
   ResetTimeAndCounter();
 }
 
 SplitViewMetricsController::~SplitViewMetricsController() {
+  ClearObservedWindows();
   tablet_mode_controller_observation_.Reset();
   split_view_controller_->RemoveObserver(this);
   Shell::Get()->display_manager()->RemoveObserver(this);
+  Shell::Get()->activation_client()->RemoveObserver(this);
+  Shell::Get()->desks_controller()->RemoveObserver(this);
+  aura::Env::GetInstance()->RemoveObserver(this);
 }
 
 void SplitViewMetricsController::OnTabletModeStarted() {
   // If it has been in split view and recording clamshell mode metrics, stop
   // recording clamshell mode metrics and start to record tablet mode metrics.
-  if (split_view_controller_->InSplitViewMode() &&
-      IsRecordingClamshellMetrics()) {
+  if (in_split_view_recording_ && IsRecordingClamshellMetrics()) {
     StopRecordClamshellSplitView();
     StartRecordTabletSplitView();
-    if (NumRootWindowsInSplitView() > 1) {
+    if (NumRootWindowsInSplitViewRecording() > 1 &&
+        IsRecordingClamshellMultiDisplaySplitView()) {
       StopRecordClamshellMultiDisplaySplitView();
       StartRecordTabletMultiDisplaySplitView();
     }
@@ -122,10 +193,11 @@
 void SplitViewMetricsController::OnTabletModeEnded() {
   // If it has been in split view and recording tablet mode metrics, stop
   // recording tablet mode metrics and start to record clamshell mode metrics.
-  if (split_view_controller_->InSplitViewMode() && IsRecordingTabletMetrics()) {
+  if (in_split_view_recording_ && IsRecordingTabletMetrics()) {
     StopRecordTabletSplitView();
     StartRecordClamshellSplitView();
-    if (NumRootWindowsInSplitView() > 1) {
+    if (NumRootWindowsInSplitViewRecording() > 1 &&
+        IsRecordingTabletMultiDisplaySplitView()) {
       StopRecordTabletMultiDisplaySplitView();
       StartRecordClamshellMultiDisplaySplitView();
     }
@@ -143,9 +215,9 @@
     return;
 
   if (previous_state == SplitViewController::State::kNoSnap)
-    OnSplitViewStarted();
+    StartRecordSplitViewMetrics();
   else if (state == SplitViewController::State::kNoSnap)
-    OnSplitViewEnded();
+    StopRecordSplitViewMetrics();
 }
 
 void SplitViewMetricsController::OnSplitViewWindowResized() {
@@ -174,14 +246,13 @@
     const display::Display& display,
     uint32_t changed_metrics) {
   // Checks if the device is in split view.
-  if (!split_view_controller_->InSplitViewMode())
+  if (!in_split_view_recording_)
     return;
 
   // Checks if the root window of |split_view_controller_| is in the changed
   // display.
-  if (display::Screen::GetScreen()
-          ->GetDisplayNearestWindow(split_view_controller_->root_window())
-          .id() != display.id()) {
+  if (GetRootWindowSettings(split_view_controller_->root_window())
+          ->display_id != display.id()) {
     return;
   }
 
@@ -203,16 +274,188 @@
   }
 }
 
-void SplitViewMetricsController::OnSplitViewStarted() {
+void SplitViewMetricsController::OnWindowParentChanged(aura::Window* window,
+                                                       aura::Window* parent) {
+  // Stop observing the window when it is moved to another desk. If the restored
+  // window is parented to current desk, observe its window state change.
+  if (parent && desks_util::IsDeskContainer(parent)) {
+    if (parent->GetId() != current_desk_->container_id()) {
+      RemoveObservedWindow(window);
+    } else if (base::Contains(no_state_observed_windows_, window)) {
+      WindowState::Get(window)->AddObserver(this);
+      no_state_observed_windows_.erase(window);
+    }
+
+    // If the top two windows snapped on both sides in clamshell mode, moving
+    // one of the snapped windows to another desk may end the split view. If
+    // there are two windows snapped on both sides with another unsnapped window
+    // on top in clamshell mode, moving the unsnapped window to another desk may
+    // start split view.
+    MaybeStartOrEndRecordBothSnappedClamshellSplitView();
+  }
+}
+
+void SplitViewMetricsController::OnResizeLoopEnded(aura::Window* window) {
+  // Only report window resizing if it is in the split view with two windows
+  // snapped on both sides.
+  if (!in_split_view_recording_ || split_view_controller_->InSplitViewMode())
+    return;
+
+  clamshell_resize_count_ += 1;
+}
+
+void SplitViewMetricsController::OnWindowDestroyed(aura::Window* window) {
+  RemoveObservedWindow(window);
+
+  // If the top two windows snapped on both sides in clamshell mode,
+  // destroying one of the snapped windows may end the split view. If there
+  // are two windows snapped on both sides with another unsnapped window
+  // on top in clamshell mode, destroying the unsnapped window may start split
+  // view.
+  MaybeStartOrEndRecordBothSnappedClamshellSplitView();
+}
+
+void SplitViewMetricsController::OnWindowRemovingFromRootWindow(
+    aura::Window* window,
+    aura::Window* new_root) {
+  // Stop observing the window if it is removing from current root window.
+  RemoveObservedWindow(window);
+
+  // If the top two windows snapped on both sides in clamshell mode,
+  // moving one of the snapped windows to another display may end the split
+  // view. If there are two windows snapped on both sides with another unsnapped
+  // window on top in clamshell mode, moving the unsnapped window to another
+  // display may start split view.
+  MaybeStartOrEndRecordBothSnappedClamshellSplitView();
+
+  // Add the window to the new root window's split view metrics controller. It
+  // may make the new root window start or end split view metrics recording.
+  if (new_root) {
+    auto* target_split_view_metrics_controller =
+        SplitViewController::Get(new_root)->split_view_metrics_controller();
+    DCHECK(target_split_view_metrics_controller);
+    if (!target_split_view_metrics_controller->IsObservingWindow(window)) {
+      target_split_view_metrics_controller->AddObservedWindow(window);
+      target_split_view_metrics_controller
+          ->MaybeStartOrEndRecordBothSnappedClamshellSplitView();
+    }
+  }
+}
+
+void SplitViewMetricsController::OnPostWindowStateTypeChange(
+    WindowState* window_state,
+    chromeos::WindowStateType old_type) {
+  // We only care if a window is snapped or unsnapped.
+  bool is_snapped = window_state->IsSnapped();
+  bool was_snapped = old_type == chromeos::WindowStateType::kPrimarySnapped ||
+                     old_type == chromeos::WindowStateType::kSecondarySnapped;
+  if (is_snapped == was_snapped)
+    return;
+  MaybeStartOrEndRecordBothSnappedClamshellSplitView();
+}
+
+void SplitViewMetricsController::OnWindowActivated(ActivationReason reason,
+                                                   aura::Window* gained_active,
+                                                   aura::Window* lost_active) {
+  // Reorder the observed windows.
+  AddOrStackWindowOnTop(gained_active);
+  MaybeStartOrEndRecordBothSnappedClamshellSplitView();
+}
+
+void SplitViewMetricsController::OnDeskAdded(const Desk* desk) {}
+void SplitViewMetricsController::OnDeskRemoved(const Desk* desk) {}
+void SplitViewMetricsController::OnDeskReordered(int old_index, int new_index) {
+}
+
+void SplitViewMetricsController::OnDeskActivationChanged(
+    const Desk* activated,
+    const Desk* deactivated) {
+  // When switching desks, ends the split view and updates observed windows.
+  StopRecordSplitViewMetrics();
+  current_desk_ = Shell::Get()->desks_controller()->active_desk();
+  InitObservedWindowsOnActiveDesk();
+
+  // Check if the new desk is in clamshell split view with two windows snapped
+  // on both sides.
+  MaybeStartOrEndRecordBothSnappedClamshellSplitView();
+}
+
+void SplitViewMetricsController::OnDeskSwitchAnimationLaunching() {}
+void SplitViewMetricsController::OnDeskSwitchAnimationFinished() {}
+
+void SplitViewMetricsController::OnWindowInitialized(aura::Window* window) {
+  int32_t* activation_index =
+      window->GetProperty(full_restore::kActivationIndexKey);
+  if (!activation_index)
+    return;
+
+  std::unique_ptr<full_restore::WindowInfo> window_info =
+      full_restore::GetWindowInfo(window);
+  if (!window_info)
+    return;
+
+  // Check if the recovered window belongs to the same root window.
+  // Note: The display id saved in window_info has no value. Need to use the
+  // restore bounds/
+  if (!window_info->current_bounds.has_value() ||
+      !display::Screen::GetScreen()
+           ->GetDisplayNearestWindow(split_view_controller_->root_window())
+           .work_area()
+           .Contains(window_info->current_bounds.value())) {
+    return;
+  }
+
+  // Check if the recovered window is in the current desk.
+  if (!window_info->desk_id.has_value() ||
+      window_info->desk_id.value() !=
+          DesksController::Get()->GetDeskIndex(current_desk_)) {
+    return;
+  }
+
+  // Insert the window in the `observed_windows_` list according to its
+  // activation index key. Since the window is not parented at this stage, the
+  // `WindowStateObserver` will be added later in `OnWindowParentChanged`.
+  window->AddObserver(this);
+  no_state_observed_windows_.insert(window);
+  auto reverse_iter = observed_windows_.rbegin();
+  while (reverse_iter != observed_windows_.rend()) {
+    int32_t* curr_window_activation_index =
+        (*reverse_iter)->GetProperty(full_restore::kActivationIndexKey);
+    if (curr_window_activation_index &&
+        *curr_window_activation_index > *activation_index) {
+      break;
+    }
+    reverse_iter = std::next(reverse_iter);
+  }
+
+  observed_windows_.insert(reverse_iter.base(), window);
+}
+
+void SplitViewMetricsController::StartRecordSplitViewMetrics() {
+  if (in_split_view_recording_)
+    return;
+
+  // If the split view is started with a snapped window next to the overview,
+  // and there is only one window (no overview items), the overview will end
+  // immediately so does the split view. We won't record this case.
+  if (split_view_controller_->InClamshellSplitViewMode() &&
+      Shell::Get()
+              ->mru_window_tracker()
+              ->BuildMruWindowList(DesksMruType::kActiveDesk)
+              .size() == 1) {
+    return;
+  }
+
   bool in_clamshell = !InTabletMode();
   if (in_clamshell)
     StartRecordClamshellSplitView();
   else
     StartRecordTabletSplitView();
 
+  in_split_view_recording_ = true;
   // The starting of this split view makes the number of root windows in split
   // view become two, which means the multi-display split view just started.
-  if (NumRootWindowsInSplitView() == 2) {
+  if (NumRootWindowsInSplitViewRecording() == 2) {
     if (in_clamshell)
       StartRecordClamshellMultiDisplaySplitView();
     else
@@ -226,18 +469,36 @@
       in_clamshell ? DeviceUIMode::kClamshell : DeviceUIMode::kTablet);
 }
 
-void SplitViewMetricsController::OnSplitViewEnded() {
+void SplitViewMetricsController::StopRecordSplitViewMetrics() {
+  if (!in_split_view_recording_)
+    return;
+
   bool is_recording_clamshell_metrics = IsRecordingClamshellMetrics();
-  if (is_recording_clamshell_metrics)
+  if (is_recording_clamshell_metrics) {
+    // If the split view is started with a snapped window next to the overview,
+    // the the user activate a window by clicking the overview item, the window
+    // will snap to the other side. Therefore, stacks the window on top.
+    if (auto* to_be_activated_window =
+            split_view_controller_->to_be_activated_window()) {
+      AddOrStackWindowOnTop(to_be_activated_window);
+    }
+
+    // Do not end if there are still two windows snapped on both sides on top.
+    if (TopTwoVisibleWindowsBothSnapped(observed_windows_))
+      return;
+
     StopRecordClamshellSplitView();
-  else
+  } else {
     StopRecordTabletSplitView();
+  }
 
   base::UmaHistogramCounts100(kSplitViewSwapWindowCountHistogram, swap_count_);
 
+  in_split_view_recording_ = false;
+
   // The ending of this split view makes the number of root windows in split
   // view become one, which means the multi-display split view just ended.
-  if (NumRootWindowsInSplitView() == 1) {
+  if (NumRootWindowsInSplitViewRecording() == 1) {
     if (is_recording_clamshell_metrics)
       StopRecordClamshellMultiDisplaySplitView();
     else
@@ -246,6 +507,115 @@
   ResetTimeAndCounter();
 }
 
+bool SplitViewMetricsController::IsObservingWindow(aura::Window* window) const {
+  return base::Contains(observed_windows_, window);
+}
+
+void SplitViewMetricsController::AddObservedWindow(aura::Window* window) {
+  window->AddObserver(this);
+  WindowState::Get(window)->AddObserver(this);
+  observed_windows_.emplace_back(window);
+}
+
+void SplitViewMetricsController::RemoveObservedWindow(aura::Window* window) {
+  if (base::Erase(observed_windows_, window)) {
+    WindowState::Get(window)->RemoveObserver(this);
+    window->RemoveObserver(this);
+  }
+}
+
+void SplitViewMetricsController::AddOrStackWindowOnTop(aura::Window* window) {
+  // We only observe the activable windows on active desk of the root window
+  // attached by |split_view_controller_|.
+  if (!window)
+    return;
+
+  if (window->GetRootWindow() != split_view_controller_->root_window())
+    return;
+
+  aura::Window* parent = window->parent();
+  if (!parent || !IsSwitchableContainer(parent))
+    return;
+
+  const int parent_id = parent->GetId();
+  if (desks_util::IsDeskContainerId(parent_id) &&
+      parent_id != current_desk_->container_id()) {
+    return;
+  }
+
+  if (!CanIncludeWindowInMruList(window))
+    return;
+
+  auto iter =
+      std::find(observed_windows_.begin(), observed_windows_.end(), window);
+  if (iter == observed_windows_.end()) {
+    AddObservedWindow(window);
+  } else {
+    observed_windows_.erase(iter);
+    observed_windows_.emplace_back(window);
+  }
+}
+
+void SplitViewMetricsController::InitObservedWindowsOnActiveDesk() {
+  ClearObservedWindows();
+
+  auto windows =
+      current_desk_
+          ->GetDeskContainerForRoot(split_view_controller_->root_window())
+          ->children();
+  for (auto* window : windows) {
+    if (!CanIncludeWindowInMruList(window))
+      continue;
+    AddObservedWindow(window);
+  }
+}
+
+void SplitViewMetricsController::ClearObservedWindows() {
+  for (auto* window : observed_windows_) {
+    WindowState::Get(window)->RemoveObserver(this);
+    window->RemoveObserver(this);
+  }
+  observed_windows_.clear();
+}
+
+void SplitViewMetricsController::
+    MaybeStartOrEndRecordBothSnappedClamshellSplitView() {
+  if (InTabletMode() || split_view_controller_->InSplitViewMode())
+    return;
+
+  bool both_snapped = TopTwoVisibleWindowsBothSnapped(observed_windows_);
+  if (!in_split_view_recording_ && both_snapped)
+    StartRecordSplitViewMetrics();
+  else if (in_split_view_recording_ && !both_snapped)
+    StopRecordSplitViewMetrics();
+}
+
+bool SplitViewMetricsController::
+    MaybePauseRecordBothSnappedClamshellSplitView() {
+  if (InTabletMode() || split_view_controller_->InSplitViewMode())
+    return false;
+
+  if (observed_windows_.size() < 3)
+    return false;
+  // Find the topmost unsnapped visible window.
+  auto iter = observed_windows_.end() - 1;
+  auto begin_iter = observed_windows_.begin();
+  for (; iter != begin_iter; iter--) {
+    if (!(*iter)->IsVisible())
+      continue;
+    if (WindowState::Get(*iter)->IsSnapped())
+      return false;
+    else
+      break;
+  }
+
+  if (iter == begin_iter)
+    return false;
+
+  return TopTwoVisibleWindowsBothSnapped(
+      std::vector<aura::Window*>(begin_iter, iter));
+}
+
 void SplitViewMetricsController::ResetTimeAndCounter() {
   clamshell_split_view_start_time_ = kInvalidTime;
   tablet_split_view_start_time_ = kInvalidTime;
@@ -268,13 +638,22 @@
 void SplitViewMetricsController::StopRecordClamshellSplitView() {
   DCHECK_NE(clamshell_split_view_start_time_, kInvalidTime);
 
-  base::UmaHistogramLongTimes(
-      kTimeInSplitScreenClamshellHistogram,
-      base::TimeTicks::Now() - clamshell_split_view_start_time_);
+  // Accumulate the engagement time.
+  clamshell_split_view_time_ +=
+      (base::TimeTicks::Now() - clamshell_split_view_start_time_)
+          .InMicroseconds();
   clamshell_split_view_start_time_ = kInvalidTime;
 
+  // If pauses, do not emit the records.
+  if (MaybePauseRecordBothSnappedClamshellSplitView())
+    return;
+
+  base::UmaHistogramLongTimes(
+      kTimeInSplitScreenClamshellHistogram,
+      base::TimeDelta::FromMilliseconds(clamshell_split_view_time_));
   base::UmaHistogramCounts100(kSplitViewResizeWindowCountClamshellHistogram,
                               clamshell_resize_count_);
+  clamshell_split_view_time_ = 0;
   clamshell_resize_count_ = 0;
 }
 
@@ -302,10 +681,21 @@
 void SplitViewMetricsController::StopRecordClamshellMultiDisplaySplitView() {
   DCHECK_NE(g_clamshell_multi_display_split_view_start_time, kInvalidTime);
 
+  // Accumulate the engagement time.
+  g_clamshell_multi_display_split_view_time_ms =
+      (base::TimeTicks::Now() - g_clamshell_multi_display_split_view_start_time)
+          .InMilliseconds();
+  g_clamshell_multi_display_split_view_start_time = kInvalidTime;
+
+  // If pauses, do not emit the records.
+  if (MaybePauseRecordBothSnappedClamshellSplitView())
+    return;
+
   base::UmaHistogramLongTimes(
       kTimeInMultiDisplaySplitScreenClamshellHistogram,
-      base::TimeTicks::Now() - g_clamshell_multi_display_split_view_start_time);
-  g_clamshell_multi_display_split_view_start_time = kInvalidTime;
+      base::TimeDelta::FromMilliseconds(
+          g_clamshell_multi_display_split_view_time_ms));
+  g_clamshell_multi_display_split_view_time_ms = 0;
 }
 
 void SplitViewMetricsController::StartRecordTabletMultiDisplaySplitView() {
diff --git a/ash/wm/splitview/split_view_metrics_controller.h b/ash/wm/splitview/split_view_metrics_controller.h
index adc9886..df10bec 100644
--- a/ash/wm/splitview/split_view_metrics_controller.h
+++ b/ash/wm/splitview/split_view_metrics_controller.h
@@ -5,11 +5,20 @@
 #ifndef ASH_WM_SPLITVIEW_SPLIT_VIEW_METRICS_CONTROLLER_H_
 #define ASH_WM_SPLITVIEW_SPLIT_VIEW_METRICS_CONTROLLER_H_
 
+#include <cstdint>
+#include <set>
+#include <vector>
+
 #include "ash/public/cpp/tablet_mode_observer.h"
+#include "ash/wm/desks/desks_controller.h"
 #include "ash/wm/splitview/split_view_observer.h"
+#include "ash/wm/window_state_observer.h"
 #include "base/scoped_observation.h"
 #include "base/time/time.h"
+#include "ui/aura/env_observer.h"
+#include "ui/aura/window_observer.h"
 #include "ui/display/display_observer.h"
+#include "ui/wm/public/activation_change_observer.h"
 
 namespace aura {
 class Window;
@@ -18,17 +27,33 @@
 namespace ash {
 class SplitViewController;
 
-////////////////////////////////////////////////////////////////////////////////
 // SplitViewMetricsController:
 // Manages split view related metrics. Tablet mode split view and clamshell
 // split view with overview next to a snapped window are managed by
-// |SplitViewController|. The UMA can be recorded at corresponding points. There
-// is another clamshell split view state which has two snapped windows on both
-// sides. |SplitViewMetricsController| also inspects the entry and exit point of
-// this type of split view state and records related UMA.
+// `SplitViewController`. The UMA can be recorded by the corresponding methods
+// of `SplitViewObserver`.
+//
+// There is another clamshell split view mode with two windows snapped on both
+// sides which is not managed by the `SplitViewController`. Therefore,
+// `SplitViewMetricsController` needs to inspect this type of split view mode
+// whose entry and exit points are defined as below:
+// Entry: When the top two visible windows on the active desk are snapped on
+//        the left and right sides respectively, the clamshell split view
+//        starts.
+// Pause: After the split view starts, an unsnapped window is activated,
+//        covering the two windows snapped on both sides. The clamshell split
+//        view is paused (accumulate the engagement time without reporting to
+//        the UMA).
+// End: When no two windows are snapped on both sides or tablet model split view
+//        starts, the clamshell split view ends.
 class SplitViewMetricsController : public TabletModeObserver,
                                    public SplitViewObserver,
-                                   public display::DisplayObserver {
+                                   public display::DisplayObserver,
+                                   public aura::WindowObserver,
+                                   public WindowStateObserver,
+                                   public wm::ActivationChangeObserver,
+                                   public DesksController::Observer,
+                                   public aura::EnvObserver {
  public:
   // Enumeration of device mode when entering split view.
   // Note that these values are persisted to histograms so existing values
@@ -53,7 +78,7 @@
   // static
   static SplitViewMetricsController* Get(aura::Window* window);
 
-  // |SplitViewMetricsController| is attached to a |SplitViewController| with
+  // `SplitViewMetricsController` is attached to a `SplitViewController` with
   // the same root window.
   explicit SplitViewMetricsController(
       SplitViewController* split_view_controller);
@@ -77,12 +102,70 @@
   // display::DisplayObserver:
   void OnDisplayMetricsChanged(const display::Display& display,
                                uint32_t changed_metrics) override;
+  // aura::WindowObserver:
+  void OnWindowParentChanged(aura::Window* window,
+                             aura::Window* parent) override;
+  void OnResizeLoopEnded(aura::Window* window) override;
+  void OnWindowDestroyed(aura::Window* window) override;
+  void OnWindowRemovingFromRootWindow(aura::Window* window,
+                                      aura::Window* new_root) override;
+
+  // WindowStateObserver:
+  void OnPostWindowStateTypeChange(WindowState* window_state,
+                                   chromeos::WindowStateType old_type) override;
+
+  // wm::ActivationChangeObserver:
+  void OnWindowActivated(ActivationReason reason,
+                         aura::Window* gained_active,
+                         aura::Window* lost_active) override;
+
+  // DeskController::Observer:
+  void OnDeskAdded(const Desk* desk) override;
+  void OnDeskRemoved(const Desk* desk) override;
+  void OnDeskReordered(int old_index, int new_index) override;
+  void OnDeskActivationChanged(const Desk* activated,
+                               const Desk* deactivated) override;
+  void OnDeskSwitchAnimationLaunching() override;
+  void OnDeskSwitchAnimationFinished() override;
+
+  // aura::EnvObserver
+  void OnWindowInitialized(aura::Window* window) override;
+
+  bool in_split_view_recording() const { return in_split_view_recording_; }
 
  private:
-  // Calls when entering the split view mode.
-  void OnSplitViewStarted();
-  // Calls when exiting the split view mode.
-  void OnSplitViewEnded();
+  // Calls when start to record split view metrics.
+  void StartRecordSplitViewMetrics();
+  // Calls when stop recording split view metrics.
+  void StopRecordSplitViewMetrics();
+
+  // Checks if the `window` is in the `observed_windows_` list. Returns true, if
+  // the window is being observed.
+  bool IsObservingWindow(aura::Window* window) const;
+
+  // Adds and removes a window to the `observed_windows_` list. Note that adding
+  // (removing) window and window state observers should be performed at the
+  // same time with adding (removing) observed windows.
+  void AddObservedWindow(aura::Window* window);
+  void RemoveObservedWindow(aura::Window* window);
+
+  // Attaches a new window to the end of `observed_windows_` (the window is
+  // stacked on top). If the window is already in the list, just stacks it on
+  // top.
+  void AddOrStackWindowOnTop(aura::Window* window);
+
+  // Adds windows on active desk to `observed_windows_` list.
+  void InitObservedWindowsOnActiveDesk();
+  // Remove all current observed windows.
+  void ClearObservedWindows();
+
+  // If there are top windows snapped on both sides, start to record split
+  // view metrics. Otherwise, stop recording split view metrics.
+  void MaybeStartOrEndRecordBothSnappedClamshellSplitView();
+  // Pauses recording of engagement time when a window hides the windows
+  // snapped on both sides. Return true, if the recording is paused. Otherwise,
+  // return false.
+  bool MaybePauseRecordBothSnappedClamshellSplitView();
 
   // Resets the variables related to time and counter metrics.
   void ResetTimeAndCounter();
@@ -112,26 +195,47 @@
   void StartRecordTabletMultiDisplaySplitView();
   void StopRecordTabletMultiDisplaySplitView();
 
-  // We need to save an ptr of the observed |SplitViewController|. Because the
-  // |RootWindowController| will be deconstructed in advance. Then, we cannot
-  // use it to get observed |SplitViewController|.
-  SplitViewController* split_view_controller_ = nullptr;
+  // We need to save an ptr of the observed `SplitViewController`. Because the
+  // `RootWindowController` will be deconstructed in advance. Then, we cannot
+  // use it to get observed `SplitViewController`.
+  SplitViewController* const split_view_controller_;
+
+  // Indicates whether it is recording split view metrics.
+  bool in_split_view_recording_ = false;
 
   // Used to track the change of device orientation.
   DeviceOrientation orientation_ = DeviceOrientation::kLandscape;
 
+  // Current observed desk.
+  const Desk* current_desk_ = nullptr;
+
+  // Observed windows on the active desk.
+  std::vector<aura::Window*> observed_windows_;
+
+  // Windows that recovered by full restore have no parents at the initialize
+  // stage, so their window states cannot be observed when are inserted into
+  // `observed_windows_` list. This set contains the windows recovered by full
+  // restored whose window states have not been observed yet.
+  std::set<aura::Window*> no_state_observed_windows_;
+
   // Start time of clamshell and tablet split view. When stop recording, the
-  // start time will be set to |base::TimeTicks::Max()|. This is also used as an
+  // start time will be set to `base::TimeTicks::Max()`. This is also used as an
   // indicator of whether we are recording clamshell/tablet split view.
   base::TimeTicks clamshell_split_view_start_time_;
   base::TimeTicks tablet_split_view_start_time_;
 
+  // An accumulator of clamshell split view engagement time. When the clamshell
+  // split view with two windows snapped on both sides is paused (the definition
+  // of "pause" is defined in the comments at the beginning), accumulate the
+  // current engagement time period.
+  int64_t clamshell_split_view_time_ = 0;
+
   // Counter of resizing windows in split view.
   int tablet_resize_count_ = 0;
   int clamshell_resize_count_ = 0;
 
-  // |TabletModeController| is destroyed before |SplitViewMetricsController|.
-  // Sets a |ScopedObservation| to help remove observer.
+  // `TabletModeController` is destroyed before `SplitViewMetricsController`.
+  // Sets a `ScopedObservation` to help remove observer.
   base::ScopedObservation<TabletModeController, TabletModeObserver>
       tablet_mode_controller_observation_{this};
 
diff --git a/ash/wm/work_area_insets.cc b/ash/wm/work_area_insets.cc
index c44e43a..50ec40e 100644
--- a/ash/wm/work_area_insets.cc
+++ b/ash/wm/work_area_insets.cc
@@ -10,6 +10,7 @@
 #include "ash/session/session_controller_impl.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shell.h"
+#include "base/auto_reset.h"
 #include "ui/aura/window.h"
 #include "ui/wm/core/coordinate_conversion.h"
 
@@ -19,10 +20,12 @@
 
 // Returns work area insets calculated for the provided parameters.
 gfx::Insets CalculateWorkAreaInsets(const gfx::Insets accessibility_insets,
+                                    const gfx::Insets persistent_bar_insets,
                                     const gfx::Insets shelf_insets,
                                     const gfx::Rect keyboard_bounds) {
   gfx::Insets work_area_insets;
   work_area_insets += accessibility_insets;
+  work_area_insets += persistent_bar_insets;
   // The virtual keyboard always hides the shelf (in any orientation).
   // Therefore, if the keyboard is shown, there is no need to reduce the work
   // area by the size of the shelf.
@@ -36,11 +39,13 @@
 // Returns work area bounds calculated for the given |window| and given
 // parameters.
 gfx::Rect CalculateWorkAreaBounds(const gfx::Insets accessibility_insets,
+                                  const gfx::Insets persistent_bar_insets,
                                   const gfx::Rect shelf_bounds_in_screen,
                                   const gfx::Rect keyboard_bounds_in_screen,
                                   aura::Window* window) {
   gfx::Rect work_area_bounds = screen_util::GetDisplayBoundsWithShelf(window);
   work_area_bounds.Inset(accessibility_insets);
+  work_area_bounds.Inset(persistent_bar_insets);
   work_area_bounds.Subtract(shelf_bounds_in_screen);
   work_area_bounds.Subtract(keyboard_bounds_in_screen);
   return work_area_bounds;
@@ -67,6 +72,12 @@
                      0, 0);
 }
 
+gfx::Insets WorkAreaInsets::GetPersistentDeskBarInsets() const {
+  if (accessibility_panel_height_ + docked_magnifier_height_ == 0)
+    return gfx::Insets(persistent_desk_bar_height_, 0, 0, 0);
+  return gfx::Insets(0, 0, 0, 0);
+}
+
 gfx::Rect WorkAreaInsets::ComputeStableWorkArea() const {
   aura::Window* root_window = root_window_controller_->GetRootWindow();
 
@@ -75,9 +86,9 @@
       root_window_controller_->shelf()->GetIdealBoundsForWorkAreaCalculation());
   ::wm::ConvertRectToScreen(root_window, &shelf_bounds_in_screen);
 
-  return CalculateWorkAreaBounds(GetAccessibilityInsets(),
-                                 shelf_bounds_in_screen,
-                                 keyboard_displaced_bounds_, root_window);
+  return CalculateWorkAreaBounds(
+      GetAccessibilityInsets(), GetPersistentDeskBarInsets(),
+      shelf_bounds_in_screen, keyboard_displaced_bounds_, root_window);
 }
 
 bool WorkAreaInsets::IsKeyboardShown() const {
@@ -98,6 +109,21 @@
       root_window_controller_->GetRootWindow());
 }
 
+void WorkAreaInsets::SetPersistentDeskBarHeight(int height) {
+  if (persistent_desk_bar_height_ == height)
+    return;
+  base::AutoReset<bool> in_progress(&persistent_desk_bar_height_in_change_,
+                                    true);
+  persistent_desk_bar_height_ = height;
+  UpdateWorkArea();
+  Shell::Get()->NotifyUserWorkAreaInsetsChanged(
+      root_window_controller_->GetRootWindow());
+}
+
+bool WorkAreaInsets::PersistentDeskBarHeightInChange() {
+  return persistent_desk_bar_height_in_change_;
+}
+
 void WorkAreaInsets::SetShelfBoundsAndInsets(const gfx::Rect& bounds,
                                              const gfx::Insets& insets) {
   shelf_bounds_ = bounds;
@@ -130,10 +156,11 @@
   // Note: Different keyboard bounds properties are used to calculate insets and
   // bounds. See ui/keyboard/keyboard_controller_observer.h for details.
   user_work_area_insets_ = CalculateWorkAreaInsets(
-      GetAccessibilityInsets(), shelf_insets_, keyboard_displaced_bounds_);
+      GetAccessibilityInsets(), GetPersistentDeskBarInsets(), shelf_insets_,
+      keyboard_displaced_bounds_);
   user_work_area_bounds_ = CalculateWorkAreaBounds(
-      GetAccessibilityInsets(), shelf_bounds_, keyboard_occluded_bounds_,
-      root_window_controller_->GetRootWindow());
+      GetAccessibilityInsets(), GetPersistentDeskBarInsets(), shelf_bounds_,
+      keyboard_occluded_bounds_, root_window_controller_->GetRootWindow());
 }
 
 }  // namespace ash
diff --git a/ash/wm/work_area_insets.h b/ash/wm/work_area_insets.h
index d6563e0..3b038d8f 100644
--- a/ash/wm/work_area_insets.h
+++ b/ash/wm/work_area_insets.h
@@ -56,6 +56,9 @@
   // Returns accessibility insets in DIPs.
   gfx::Insets GetAccessibilityInsets() const;
 
+  // Returns the persistent desk bar insets in DIPs.
+  gfx::Insets GetPersistentDeskBarInsets() const;
+
   // Returns bounds of the stable work area (work area when the shelf is
   // visible) in screen coordinates DIPs.
   gfx::Rect ComputeStableWorkArea() const;
@@ -73,6 +76,16 @@
   // Shell observers will be notified that accessibility insets changed.
   void SetAccessibilityPanelHeight(int height);
 
+  // Sets height of the persistent desk bar in DIPs for this root
+  // window. Shell observers will be notified that persistent desk bar
+  // insets changed.
+  void SetPersistentDeskBarHeight(int height);
+
+  // Indicates if the persistent desk bar height is in change. This is useful to
+  // prevent circular call from the App List as it also observes the work area
+  // value.
+  bool PersistentDeskBarHeightInChange();
+
   // Sets bounds (in window coordinates) and insets of the shelf for this root
   // window. |bounds| and |insets| are passed separately, because insets depend
   // on shelf visibility and can be different than calculated from bounds.
@@ -120,6 +133,13 @@
   // screen. It needs to be removed from the available work area.
   int accessibility_panel_height_ = 0;
 
+  // Cached height of the persistent desk bar in DIPs at the top of the
+  // screen. It needs to be removed from the available work area.
+  int persistent_desk_bar_height_ = 0;
+
+  // Indicates if the persistent desk bar height is in change.
+  bool persistent_desk_bar_height_in_change_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(WorkAreaInsets);
 };
 
diff --git a/base/android/java/src/org/chromium/base/annotations/MainDex.java b/base/android/java/src/org/chromium/base/annotations/MainDex.java
index adc0e75..49413fe 100644
--- a/base/android/java/src/org/chromium/base/annotations/MainDex.java
+++ b/base/android/java/src/org/chromium/base/annotations/MainDex.java
@@ -19,5 +19,5 @@
  * causes classes to appear in the main dex file (for "Legacy multidex").
  */
 @Target(ElementType.TYPE)
-@Retention(RetentionPolicy.CLASS)
+@Retention(RetentionPolicy.RUNTIME)
 public @interface MainDex {}
diff --git a/base/android/java/src/org/chromium/base/metrics/UmaRecorderHolder.java b/base/android/java/src/org/chromium/base/metrics/UmaRecorderHolder.java
index a743c10a..a23263f 100644
--- a/base/android/java/src/org/chromium/base/metrics/UmaRecorderHolder.java
+++ b/base/android/java/src/org/chromium/base/metrics/UmaRecorderHolder.java
@@ -11,8 +11,8 @@
     /** The instance held by this class. */
     private static CachingUmaRecorder sRecorder = new CachingUmaRecorder();
 
-    /** Allow calling onLibraryLoaded() */
-    private static boolean sAllowNativeUmaRecorder = true;
+    /** Set up native UMA Recorder */
+    private static boolean sSetUpNativeUmaRecorder = true;
 
     /** Whether onLibraryLoaded() was called. */
     private static boolean sNativeInitialized;
@@ -38,20 +38,20 @@
     }
 
     /**
-     * Disallow calling onLibraryLoaded() to set a {@link NativeUmaRecorder}.
-     * <p>
-     * Can be used in processes that don't load native library to make sure that a native recorder
-     * is never set to avoid possible breakage.
+     * Whether a native UMA Recorder should be set up.
+     * @param setUpNativeUmaRecorder indicates whether a native UMA recorder should be set up.
+     * Defaults to true if unset.
      */
-    public static void setAllowNativeUmaRecorder(boolean allow) {
-        sAllowNativeUmaRecorder = allow;
+    public static void setUpNativeUmaRecorder(boolean setUpNativeUmaRecorder) {
+        sSetUpNativeUmaRecorder = setUpNativeUmaRecorder;
     }
 
     /**
      * Starts forwarding metrics to the native code. Returns after the cache has been flushed.
      */
     public static void onLibraryLoaded() {
-        assert sAllowNativeUmaRecorder : "Setting NativeUmaRecorder is not allowed";
+        if (!sSetUpNativeUmaRecorder) return;
+
         assert !sNativeInitialized;
         sNativeInitialized = true;
         sRecorder.setDelegate(new NativeUmaRecorder());
diff --git a/base/time/time_exploded_ios.cc b/base/time/time_exploded_ios.cc
index b23efee..cac0243 100644
--- a/base/time/time_exploded_ios.cc
+++ b/base/time/time_exploded_ios.cc
@@ -9,6 +9,7 @@
 #include <CoreFoundation/CFTimeZone.h>
 
 #include "base/mac/scoped_cftyperef.h"
+#include "base/numerics/safe_conversions.h"
 
 #if __LP64__
 #error Use posix implementation on 64-bit platforms.
@@ -46,8 +47,7 @@
   // it cannot be suited to int64, then fail to avoid overflows.
   double microseconds =
       (seconds * kMicrosecondsPerSecond) + kTimeTToMicrosecondsOffset;
-  if (microseconds > std::numeric_limits<int64_t>::max() ||
-      microseconds < std::numeric_limits<int64_t>::min()) {
+  if (!IsValueInRangeForNumericType<int64_t>(microseconds)) {
     *time = Time(0);
     return false;
   }
diff --git a/build/android/multidex.flags b/build/android/multidex.flags
deleted file mode 100644
index e3543c1..0000000
--- a/build/android/multidex.flags
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# When multidex is enabled, need to keep the @MainDex annotation so that it
-# can be used to create the main dex list.
--keepattributes *Annotations*
--keep @interface org.chromium.base.annotations.MainDex
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 3ee387c..e6101b0 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -2820,9 +2820,6 @@
         if (defined(invoker.proguard_configs)) {
           proguard_configs += invoker.proguard_configs
         }
-        if (_enable_main_dex_list) {
-          proguard_configs += [ "//build/android/multidex.flags" ]
-        }
         if (!enable_java_asserts && (!defined(testonly) || !testonly) &&
             # Injected JaCoCo code causes -checkdiscards to fail.
             !use_jacoco_coverage) {
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 5176e316..13ed917 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -1609,9 +1609,6 @@
           # TODO(thakis): Only for no_chromium_code? http://crbug.com/912662
           "-Wno-ignored-pragma-optimize",
 
-          # TODO(https://crbug.com/989932): Evaluate and possibly enable.
-          "-Wno-implicit-int-float-conversion",
-
           # TODO(https://crbug.com/999886): Clean up, enable.
           "-Wno-final-dtor-non-final-class",
 
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index eaa675b..9ecaa2a5 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -379,7 +379,9 @@
     "trees/occlusion.h",
     "trees/occlusion_tracker.cc",
     "trees/occlusion_tracker.h",
+    "trees/paint_holding_commit_trigger.cc",
     "trees/paint_holding_commit_trigger.h",
+    "trees/paint_holding_reason.h",
     "trees/presentation_time_callback_buffer.cc",
     "trees/presentation_time_callback_buffer.h",
     "trees/property_animation_state.cc",
diff --git a/cc/test/fake_proxy.cc b/cc/test/fake_proxy.cc
index 3da1d5d..61bba19 100644
--- a/cc/test/fake_proxy.cc
+++ b/cc/test/fake_proxy.cc
@@ -21,6 +21,15 @@
 
 bool FakeProxy::IsStarted() const { return true; }
 
+bool FakeProxy::StartDeferringCommits(base::TimeDelta timeout,
+                                      PaintHoldingReason reason) {
+  return false;
+}
+
+bool FakeProxy::IsDeferringCommits() const {
+  return false;
+}
+
 bool FakeProxy::CommitRequested() const { return false; }
 
 void FakeProxy::SetMutator(std::unique_ptr<LayerTreeMutator> mutator) {}
diff --git a/cc/test/fake_proxy.h b/cc/test/fake_proxy.h
index f73256f..735213c 100644
--- a/cc/test/fake_proxy.h
+++ b/cc/test/fake_proxy.h
@@ -9,6 +9,7 @@
 
 #include "base/single_thread_task_runner.h"
 #include "cc/trees/layer_tree_host.h"
+#include "cc/trees/paint_holding_reason.h"
 #include "cc/trees/proxy.h"
 #include "cc/trees/render_frame_metadata_observer.h"
 #include "services/metrics/public/cpp/ukm_recorder.h"
@@ -35,8 +36,10 @@
       const viz::LocalSurfaceId& target_local_surface_id) override {}
   bool RequestedAnimatePending() override;
   void SetDeferMainFrameUpdate(bool defer_main_frame_update) override {}
-  void StartDeferringCommits(base::TimeDelta timeout) override {}
+  bool StartDeferringCommits(base::TimeDelta timeout,
+                             PaintHoldingReason reason) override;
   void StopDeferringCommits(PaintHoldingCommitTrigger) override {}
+  bool IsDeferringCommits() const override;
   bool CommitRequested() const override;
   void Start() override {}
   void Stop() override {}
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index da05523..35ad7ee 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -36,6 +36,7 @@
 #include "cc/trees/layer_tree_host_impl.h"
 #include "cc/trees/layer_tree_host_single_thread_client.h"
 #include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/paint_holding_reason.h"
 #include "cc/trees/proxy_impl.h"
 #include "cc/trees/proxy_main.h"
 #include "cc/trees/single_thread_proxy.h"
@@ -411,7 +412,7 @@
   }
 
   void OnDeferMainFrameUpdatesChanged(bool) override {}
-  void OnDeferCommitsChanged(bool) override {}
+  void OnDeferCommitsChanged(bool, PaintHoldingReason) override {}
 
   void RecordStartOfFrameMetrics() override {}
   void RecordEndOfFrameMetrics(base::TimeTicks,
diff --git a/cc/test/stub_layer_tree_host_client.h b/cc/test/stub_layer_tree_host_client.h
index 1fb6938..91655cc4 100644
--- a/cc/test/stub_layer_tree_host_client.h
+++ b/cc/test/stub_layer_tree_host_client.h
@@ -9,6 +9,7 @@
 
 #include "cc/paint/element_id.h"
 #include "cc/trees/layer_tree_host_client.h"
+#include "cc/trees/paint_holding_reason.h"
 
 namespace cc {
 
@@ -23,7 +24,7 @@
   void DidUpdateLayers() override {}
   void BeginMainFrame(const viz::BeginFrameArgs& args) override {}
   void OnDeferMainFrameUpdatesChanged(bool) override {}
-  void OnDeferCommitsChanged(bool) override {}
+  void OnDeferCommitsChanged(bool, PaintHoldingReason) override {}
   void RecordStartOfFrameMetrics() override {}
   void RecordEndOfFrameMetrics(base::TimeTicks,
                                ActiveFrameSequenceTrackers) override {}
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index eff1dd5..3c34b8f 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -57,6 +57,7 @@
 #include "cc/trees/layer_tree_host_impl.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "cc/trees/mutator_host.h"
+#include "cc/trees/paint_holding_reason.h"
 #include "cc/trees/property_tree_builder.h"
 #include "cc/trees/proxy_main.h"
 #include "cc/trees/render_frame_metadata_observer.h"
@@ -604,16 +605,22 @@
   client_->OnDeferMainFrameUpdatesChanged(defer_status);
 }
 
-void LayerTreeHost::StartDeferringCommits(base::TimeDelta timeout) {
-  proxy_->StartDeferringCommits(timeout);
+bool LayerTreeHost::StartDeferringCommits(base::TimeDelta timeout,
+                                          PaintHoldingReason reason) {
+  return proxy_->StartDeferringCommits(timeout, reason);
 }
 
 void LayerTreeHost::StopDeferringCommits(PaintHoldingCommitTrigger trigger) {
   proxy_->StopDeferringCommits(trigger);
 }
 
-void LayerTreeHost::OnDeferCommitsChanged(bool defer_status) {
-  client_->OnDeferCommitsChanged(defer_status);
+bool LayerTreeHost::IsDeferringCommits() const {
+  return proxy_->IsDeferringCommits();
+}
+
+void LayerTreeHost::OnDeferCommitsChanged(bool defer_status,
+                                          PaintHoldingReason reason) {
+  client_->OnDeferCommitsChanged(defer_status, reason);
 }
 
 DISABLE_CFI_PERF
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index 547d5e34..2953d81 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -48,6 +48,7 @@
 #include "cc/trees/layer_tree_host_client.h"
 #include "cc/trees/layer_tree_settings.h"
 #include "cc/trees/mutator_host.h"
+#include "cc/trees/paint_holding_reason.h"
 #include "cc/trees/proxy.h"
 #include "cc/trees/swap_promise.h"
 #include "cc/trees/swap_promise_manager.h"
@@ -274,13 +275,17 @@
   // is the interval after which commits will restart if nothing stops
   // deferring sooner. If multiple calls are made to StartDeferringCommits
   // while deferal is active, the first timeout continues to apply.
-  void StartDeferringCommits(base::TimeDelta timeout);
+  bool StartDeferringCommits(base::TimeDelta timeout,
+                             PaintHoldingReason reason);
 
   // Stop deferring commits immediately.
   void StopDeferringCommits(PaintHoldingCommitTrigger);
 
+  // Returns true if commits are currently deferred.
+  bool IsDeferringCommits() const;
+
   // Notification that the proxy started or stopped deferring commits.
-  void OnDeferCommitsChanged(bool);
+  void OnDeferCommitsChanged(bool defer_status, PaintHoldingReason reason);
 
   // Returns whether there are any outstanding ScopedDeferMainFrameUpdate,
   // though commits may be deferred also when the local_surface_id_from_parent()
diff --git a/cc/trees/layer_tree_host_client.h b/cc/trees/layer_tree_host_client.h
index f411eef..00f3e63 100644
--- a/cc/trees/layer_tree_host_client.h
+++ b/cc/trees/layer_tree_host_client.h
@@ -11,6 +11,7 @@
 #include "base/time/time.h"
 #include "cc/input/browser_controls_state.h"
 #include "cc/metrics/frame_sequence_tracker_collection.h"
+#include "cc/trees/paint_holding_reason.h"
 #include "cc/trees/property_tree.h"
 #include "ui/gfx/geometry/scroll_offset.h"
 #include "ui/gfx/geometry/vector2d_f.h"
@@ -119,8 +120,10 @@
   // Notification that the proxy started or stopped deferring main frame updates
   virtual void OnDeferMainFrameUpdatesChanged(bool) = 0;
 
-  // Notification that the proxy started or stopped deferring commits.
-  virtual void OnDeferCommitsChanged(bool) = 0;
+  // Notification that the proxy started or stopped deferring commits. |reason|
+  // indicates why commits are/were deferred.
+  virtual void OnDeferCommitsChanged(bool defer_status,
+                                     PaintHoldingReason reason) = 0;
 
   // Visual frame-based updates to the state of the LayerTreeHost are expected
   // to happen only in calls to LayerTreeHostClient::UpdateLayerTreeHost, which
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 973fda1..7b553e58 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -60,6 +60,7 @@
 #include "cc/trees/effect_node.h"
 #include "cc/trees/layer_tree_host_impl.h"
 #include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/paint_holding_reason.h"
 #include "cc/trees/scroll_node.h"
 #include "cc/trees/single_thread_proxy.h"
 #include "cc/trees/swap_promise.h"
@@ -9498,7 +9499,9 @@
 
  private:
   void DeferCommitOnMain() {
-    layer_tree_host()->StartDeferringCommits(base::TimeDelta::FromDays(1));
+    layer_tree_host()->StartDeferringCommits(
+        base::TimeDelta::FromDays(1),
+        PaintHoldingReason::kFirstContentfulPaint);
   }
 
   void PostDeferCommit() {
diff --git a/cc/trees/paint_holding_commit_trigger.cc b/cc/trees/paint_holding_commit_trigger.cc
new file mode 100644
index 0000000..daba184
--- /dev/null
+++ b/cc/trees/paint_holding_commit_trigger.cc
@@ -0,0 +1,22 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/trees/paint_holding_commit_trigger.h"
+
+#include "base/notreached.h"
+
+namespace cc {
+
+PaintHoldingCommitTrigger ReasonToTimeoutTrigger(PaintHoldingReason reason) {
+  switch (reason) {
+    case PaintHoldingReason::kFirstContentfulPaint:
+      return PaintHoldingCommitTrigger::kTimeoutFCP;
+    case PaintHoldingReason::kDocumentTransition:
+      return PaintHoldingCommitTrigger::kTimeoutDocumentTransition;
+  }
+  NOTREACHED();
+  return PaintHoldingCommitTrigger::kTimeoutFCP;
+}
+
+}  // namespace cc
diff --git a/cc/trees/paint_holding_commit_trigger.h b/cc/trees/paint_holding_commit_trigger.h
index b882802..5c9439d 100644
--- a/cc/trees/paint_holding_commit_trigger.h
+++ b/cc/trees/paint_holding_commit_trigger.h
@@ -5,6 +5,8 @@
 #ifndef CC_TREES_PAINT_HOLDING_COMMIT_TRIGGER_H_
 #define CC_TREES_PAINT_HOLDING_COMMIT_TRIGGER_H_
 
+#include "cc/trees/paint_holding_reason.h"
+
 namespace cc {
 
 enum class PaintHoldingCommitTrigger {
@@ -18,13 +20,19 @@
   // The commit was triggered by first contentful paint (FCP)
   kFirstContentfulPaint = 2,
   // The commit was triggered by a timeout waiting for FCP
-  kTimeout = 3,
+  kTimeoutFCP = 3,
   // The timeout was never set, probably due to non-main frame
   kNotDeferred = 4,
+  // The commit was triggered by a document transition start
+  kDocumentTransition = 5,
+  // The commit was triggered by a timeout waiting for document transition start
+  kTimeoutDocumentTransition = 6,
   // Required for UMA enum
-  kMaxValue = kNotDeferred
+  kMaxValue = kTimeoutDocumentTransition
 };
 
+PaintHoldingCommitTrigger ReasonToTimeoutTrigger(PaintHoldingReason reason);
+
 }  // namespace cc
 
 #endif  // CC_TREES_PAINT_HOLDING_COMMIT_TRIGGER_H_
diff --git a/cc/trees/paint_holding_reason.h b/cc/trees/paint_holding_reason.h
new file mode 100644
index 0000000..3e063246
--- /dev/null
+++ b/cc/trees/paint_holding_reason.h
@@ -0,0 +1,21 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_TREES_PAINT_HOLDING_REASON_H_
+#define CC_TREES_PAINT_HOLDING_REASON_H_
+
+namespace cc {
+
+enum class PaintHoldingReason {
+  // Deferred to allow a frame with contentful paint.
+  kFirstContentfulPaint,
+
+  // Deferred to allow the document to be updated asynchronously for a
+  // transition.
+  kDocumentTransition,
+};
+
+}  // namespace cc
+
+#endif  // CC_TREES_PAINT_HOLDING_REASON_H_
diff --git a/cc/trees/proxy.h b/cc/trees/proxy.h
index 66f9b89..316fbd1a 100644
--- a/cc/trees/proxy.h
+++ b/cc/trees/proxy.h
@@ -14,6 +14,7 @@
 #include "cc/cc_export.h"
 #include "cc/input/browser_controls_state.h"
 #include "cc/trees/paint_holding_commit_trigger.h"
+#include "cc/trees/paint_holding_reason.h"
 #include "cc/trees/task_runner_provider.h"
 #include "components/viz/common/frame_sinks/begin_frame_source.h"
 #include "components/viz/common/surfaces/local_surface_id.h"
@@ -64,11 +65,14 @@
   // but continues to update the document lifecycle in
   // LayerTreeHost::BeginMainFrameUpdate. If multiple calls are made when
   // deferal is active the first |timeout| continues to apply.
-  virtual void StartDeferringCommits(base::TimeDelta timeout) = 0;
+  virtual bool StartDeferringCommits(base::TimeDelta timeout,
+                                     PaintHoldingReason reason) = 0;
 
   // Immediately stop deferring commits.
   virtual void StopDeferringCommits(PaintHoldingCommitTrigger) = 0;
 
+  virtual bool IsDeferringCommits() const = 0;
+
   virtual bool CommitRequested() const = 0;
 
   // Must be called before using the proxy.
diff --git a/cc/trees/proxy_main.cc b/cc/trees/proxy_main.cc
index c91c070..a004dc7 100644
--- a/cc/trees/proxy_main.cc
+++ b/cc/trees/proxy_main.cc
@@ -22,6 +22,7 @@
 #include "cc/trees/layer_tree_frame_sink.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/mutator_host.h"
+#include "cc/trees/paint_holding_reason.h"
 #include "cc/trees/proxy_impl.h"
 #include "cc/trees/render_frame_metadata_observer.h"
 #include "cc/trees/scoped_abort_remaining_swap_promises.h"
@@ -41,8 +42,7 @@
       deferred_final_pipeline_stage_(NO_PIPELINE_STAGE),
       commit_waits_for_activation_(false),
       started_(false),
-      defer_main_frame_update_(false),
-      defer_commits_(false) {
+      defer_main_frame_update_(false) {
   TRACE_EVENT0("cc", "ProxyMain::ProxyMain");
   DCHECK(task_runner_provider_);
   DCHECK(IsMainThread());
@@ -215,9 +215,9 @@
   // Check now if we should stop deferring commits due to a timeout. We
   // may also stop deferring in layer_tree_host_->BeginMainFrame, but update
   // the status at this point to keep scroll in sync.
-  if (defer_commits_ && base::TimeTicks::Now() > commits_restart_time_)
-    StopDeferringCommits(PaintHoldingCommitTrigger::kTimeout);
-  skip_commit |= defer_commits_;
+  if (IsDeferringCommits() && base::TimeTicks::Now() > commits_restart_time_)
+    StopDeferringCommits(ReasonToTimeoutTrigger(*paint_holding_reason_));
+  skip_commit |= IsDeferringCommits();
 
   if (!skip_commit) {
     // Synchronizes scroll offsets and page scale deltas (for pinch zoom) from
@@ -264,7 +264,7 @@
   // avoid committing right now, or we may be deferring commits but not
   // deferring main frame updates. Either may have changed the status
   // of the defer... flags, so re-evaluate skip_commit.
-  skip_commit |= defer_main_frame_update_ || defer_commits_;
+  skip_commit |= defer_main_frame_update_ || IsDeferringCommits();
 
   if (skip_commit) {
     current_pipeline_stage_ = NO_PIPELINE_STAGE;
@@ -514,35 +514,43 @@
                                 defer_main_frame_update));
 }
 
-void ProxyMain::StartDeferringCommits(base::TimeDelta timeout) {
+bool ProxyMain::StartDeferringCommits(base::TimeDelta timeout,
+                                      PaintHoldingReason reason) {
   DCHECK(task_runner_provider_->IsMainThread());
 
   // Do nothing if already deferring. The timeout remains as it was from when
   // we most recently began deferring.
-  if (defer_commits_)
-    return;
+  if (IsDeferringCommits())
+    return false;
 
   TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("cc", "ProxyMain::SetDeferCommits",
                                     TRACE_ID_LOCAL(this));
 
-  defer_commits_ = true;
+  paint_holding_reason_ = reason;
   commits_restart_time_ = base::TimeTicks::Now() + timeout;
 
   // Notify dependent systems that the deferral status has changed.
-  layer_tree_host_->OnDeferCommitsChanged(defer_commits_);
+  layer_tree_host_->OnDeferCommitsChanged(true, reason);
+  return true;
 }
 
 void ProxyMain::StopDeferringCommits(PaintHoldingCommitTrigger trigger) {
-  if (!defer_commits_)
+  if (!IsDeferringCommits())
     return;
-  defer_commits_ = false;
+  auto reason = *paint_holding_reason_;
+  paint_holding_reason_.reset();
   UMA_HISTOGRAM_ENUMERATION("PaintHolding.CommitTrigger2", trigger);
   commits_restart_time_ = base::TimeTicks();
   TRACE_EVENT_NESTABLE_ASYNC_END0("cc", "ProxyMain::SetDeferCommits",
                                   TRACE_ID_LOCAL(this));
 
   // Notify depended systems that the deferral status has changed.
-  layer_tree_host_->OnDeferCommitsChanged(defer_commits_);
+  layer_tree_host_->OnDeferCommitsChanged(false, reason);
+}
+
+bool ProxyMain::IsDeferringCommits() const {
+  DCHECK(IsMainThread());
+  return paint_holding_reason_.has_value();
 }
 
 bool ProxyMain::CommitRequested() const {
diff --git a/cc/trees/proxy_main.h b/cc/trees/proxy_main.h
index d133549..1157b1a 100644
--- a/cc/trees/proxy_main.h
+++ b/cc/trees/proxy_main.h
@@ -11,6 +11,7 @@
 #include "cc/cc_export.h"
 #include "cc/input/browser_controls_state.h"
 #include "cc/trees/layer_tree_host.h"
+#include "cc/trees/paint_holding_reason.h"
 #include "cc/trees/proxy.h"
 #include "cc/trees/proxy_common.h"
 
@@ -89,8 +90,10 @@
       const viz::LocalSurfaceId& target_local_surface_id) override;
   bool RequestedAnimatePending() override;
   void SetDeferMainFrameUpdate(bool defer_main_frame_update) override;
-  void StartDeferringCommits(base::TimeDelta timeout) override;
+  bool StartDeferringCommits(base::TimeDelta timeout,
+                             PaintHoldingReason reason) override;
   void StopDeferringCommits(PaintHoldingCommitTrigger) override;
+  bool IsDeferringCommits() const override;
   bool CommitRequested() const override;
   void Start() override;
   void Stop() override;
@@ -148,9 +151,9 @@
   bool started_;
 
   // defer_main_frame_update_ will also cause commits to be deferred, regardless
-  // of the setting for defer_commits_.
+  // of the setting for paint_holding_reason_.
   bool defer_main_frame_update_;
-  bool defer_commits_;
+  absl::optional<PaintHoldingReason> paint_holding_reason_;
 
   // Only used when defer_commits_ is active and must be set in such cases.
   base::TimeTicks commits_restart_time_;
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index c46ce98..fe22ff0b 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -27,6 +27,7 @@
 #include "cc/trees/layer_tree_host_single_thread_client.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "cc/trees/mutator_host.h"
+#include "cc/trees/paint_holding_reason.h"
 #include "cc/trees/render_frame_metadata_observer.h"
 #include "cc/trees/scoped_abort_remaining_swap_promises.h"
 #include "components/power_scheduler/power_mode_arbiter.h"
@@ -56,7 +57,6 @@
 #endif
       inside_draw_(false),
       defer_main_frame_update_(false),
-      defer_commits_(false),
       animate_requested_(false),
       update_layers_requested_(false),
       commit_requested_(false),
@@ -310,36 +310,44 @@
   scheduler_on_impl_thread_->SetDeferBeginMainFrame(defer_main_frame_update_);
 }
 
-void SingleThreadProxy::StartDeferringCommits(base::TimeDelta timeout) {
+bool SingleThreadProxy::StartDeferringCommits(base::TimeDelta timeout,
+                                              PaintHoldingReason reason) {
   DCHECK(task_runner_provider_->IsMainThread());
 
   // Do nothing if already deferring. The timeout remains as it was from when
   // we most recently began deferring.
-  if (defer_commits_)
-    return;
+  if (IsDeferringCommits())
+    return false;
 
   TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("cc", "SingleThreadProxy::SetDeferCommits",
                                     TRACE_ID_LOCAL(this));
 
-  defer_commits_ = true;
+  paint_holding_reason_ = reason;
   commits_restart_time_ = base::TimeTicks::Now() + timeout;
 
   // Notify dependent systems that the deferral status has changed.
-  layer_tree_host_->OnDeferCommitsChanged(defer_commits_);
+  layer_tree_host_->OnDeferCommitsChanged(true, reason);
+  return true;
 }
 
 void SingleThreadProxy::StopDeferringCommits(
     PaintHoldingCommitTrigger trigger) {
-  if (!defer_commits_)
+  if (!IsDeferringCommits())
     return;
-  defer_commits_ = false;
+  auto reason = *paint_holding_reason_;
+  paint_holding_reason_.reset();
   commits_restart_time_ = base::TimeTicks();
   UMA_HISTOGRAM_ENUMERATION("PaintHolding.CommitTrigger2", trigger);
   TRACE_EVENT_NESTABLE_ASYNC_END0("cc", "SingleThreadProxy::SetDeferCommits",
                                   TRACE_ID_LOCAL(this));
 
   // Notify dependent systems that the deferral status has changed.
-  layer_tree_host_->OnDeferCommitsChanged(defer_commits_);
+  layer_tree_host_->OnDeferCommitsChanged(false, reason);
+}
+
+bool SingleThreadProxy::IsDeferringCommits() const {
+  DCHECK(task_runner_provider_->IsMainThread());
+  return paint_holding_reason_.has_value();
 }
 
 bool SingleThreadProxy::CommitRequested() const {
@@ -857,8 +865,8 @@
   // Check now if we should stop deferring commits. Do this before
   // DoBeginMainFrame because the latter updates scroll offsets, which
   // we should avoid if deferring commits.
-  if (defer_commits_ && base::TimeTicks::Now() > commits_restart_time_)
-    StopDeferringCommits(PaintHoldingCommitTrigger::kTimeout);
+  if (IsDeferringCommits() && base::TimeTicks::Now() > commits_restart_time_)
+    StopDeferringCommits(ReasonToTimeoutTrigger(*paint_holding_reason_));
 
   DoBeginMainFrame(begin_frame_args);
 
@@ -867,7 +875,7 @@
 
   // At this point the main frame may have deferred commits to avoid committing
   // right now.
-  if (defer_main_frame_update_ || defer_commits_ ||
+  if (defer_main_frame_update_ || IsDeferringCommits() ||
       begin_frame_args.animate_only) {
     TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferCommit_InsideBeginMainFrame",
                          TRACE_EVENT_SCOPE_THREAD);
@@ -884,7 +892,7 @@
     const viz::BeginFrameArgs& begin_frame_args) {
   // Only update scroll deltas if we are going to commit the frame, otherwise
   // scroll offsets get confused.
-  if (!defer_commits_) {
+  if (!IsDeferringCommits()) {
     // The impl-side scroll deltas may be manipulated directly via the
     // InputHandler on the UI thread and the scale deltas may change when they
     // are clamped on the impl thread.
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h
index bb6556b1..9d3c9f1 100644
--- a/cc/trees/single_thread_proxy.h
+++ b/cc/trees/single_thread_proxy.h
@@ -14,6 +14,7 @@
 #include "base/time/time.h"
 #include "cc/scheduler/scheduler.h"
 #include "cc/trees/layer_tree_host_impl.h"
+#include "cc/trees/paint_holding_reason.h"
 #include "cc/trees/proxy.h"
 #include "cc/trees/task_runner_provider.h"
 #include "components/viz/common/frame_sinks/begin_frame_args.h"
@@ -58,8 +59,10 @@
       const viz::LocalSurfaceId& target_local_surface_id) override;
   bool RequestedAnimatePending() override;
   void SetDeferMainFrameUpdate(bool defer_main_frame_update) override;
-  void StartDeferringCommits(base::TimeDelta timeout) override;
+  bool StartDeferringCommits(base::TimeDelta timeout,
+                             PaintHoldingReason reason) override;
   void StopDeferringCommits(PaintHoldingCommitTrigger) override;
+  bool IsDeferringCommits() const override;
   bool CommitRequested() const override;
   void Start() override;
   void Stop() override;
@@ -207,7 +210,7 @@
 #endif
   bool inside_draw_;
   bool defer_main_frame_update_;
-  bool defer_commits_;
+  absl::optional<PaintHoldingReason> paint_holding_reason_;
   bool animate_requested_;
   bool update_layers_requested_;
   bool commit_requested_;
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java
index eefb377..0605793b 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java
@@ -118,6 +118,7 @@
 import org.chromium.chrome.browser.tasks.tab_management.TabSwitcherCoordinator;
 import org.chromium.chrome.browser.tasks.tab_management.TabUiFeatureUtilities;
 import org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper;
+import org.chromium.chrome.browser.tasks.tab_management.TabUiThemeProvider;
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
 import org.chromium.chrome.browser.undo_tab_close_snackbar.UndoBarController;
 import org.chromium.chrome.browser.util.ChromeAccessibilityUtil;
@@ -1086,7 +1087,7 @@
         public void check(View view, NoMatchingViewException noMatchException) {
             if (noMatchException != null) throw noMatchException;
             int tabListPadding =
-                    (int) view.getResources().getDimension(R.dimen.tab_list_card_padding);
+                    (int) TabUiThemeProvider.getTabCardPaddingDimension(view.getContext());
 
             assertTrue(view instanceof RecyclerView);
             RecyclerView recyclerView = (RecyclerView) view;
diff --git a/chrome/android/features/tab_ui/java/res/drawable/tab_grid_dialog_background.xml b/chrome/android/features/tab_ui/java/res/drawable/tab_grid_dialog_background.xml
index 0a43dbd..3b53d321 100644
--- a/chrome/android/features/tab_ui/java/res/drawable/tab_grid_dialog_background.xml
+++ b/chrome/android/features/tab_ui/java/res/drawable/tab_grid_dialog_background.xml
@@ -5,5 +5,5 @@
 
 <shape xmlns:android="http://schemas.android.com/apk/res/android">
     <solid android:color="@color/tab_grid_dialog_background_color"/>
-    <corners android:radius="@dimen/tab_list_card_radius" />
+    <corners android:radius="?attr/tabGridDialogCornerRadius" />
 </shape>
\ No newline at end of file
diff --git a/chrome/android/features/tab_ui/java/res/drawable/ungroup_bar_background.xml b/chrome/android/features/tab_ui/java/res/drawable/ungroup_bar_background.xml
index da73a213..8bbd7ee 100644
--- a/chrome/android/features/tab_ui/java/res/drawable/ungroup_bar_background.xml
+++ b/chrome/android/features/tab_ui/java/res/drawable/ungroup_bar_background.xml
@@ -7,6 +7,6 @@
     <corners
         android:topLeftRadius="0dp"
         android:topRightRadius="0dp"
-        android:bottomLeftRadius="@dimen/tab_list_card_radius"
-        android:bottomRightRadius="@dimen/tab_list_card_radius" />
+        android:bottomLeftRadius="?attr/tabGridDialogCornerRadius"
+        android:bottomRightRadius="?attr/tabGridDialogCornerRadius" />
 </shape>
\ No newline at end of file
diff --git a/chrome/android/features/tab_ui/java/res/layout/bottom_tab_grid_toolbar.xml b/chrome/android/features/tab_ui/java/res/layout/bottom_tab_grid_toolbar.xml
index d4d1ea9..a458d83 100644
--- a/chrome/android/features/tab_ui/java/res/layout/bottom_tab_grid_toolbar.xml
+++ b/chrome/android/features/tab_ui/java/res/layout/bottom_tab_grid_toolbar.xml
@@ -15,6 +15,8 @@
         android:id="@+id/main_content"
         android:layout_width="match_parent"
         android:layout_height="@dimen/bottom_sheet_peek_height"
+        android:paddingLeft="?attr/tabGridDialogAppBarPadding"
+        android:paddingRight="?attr/tabGridDialogAppBarPadding"
         android:orientation="horizontal"
         android:gravity="center_vertical"
         android:focusable="true"
diff --git a/chrome/android/features/tab_ui/java/res/layout/bottom_tab_strip_toolbar.xml b/chrome/android/features/tab_ui/java/res/layout/bottom_tab_strip_toolbar.xml
index 46594e6..2d460f99 100644
--- a/chrome/android/features/tab_ui/java/res/layout/bottom_tab_strip_toolbar.xml
+++ b/chrome/android/features/tab_ui/java/res/layout/bottom_tab_strip_toolbar.xml
@@ -10,7 +10,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     xmlns:tools="http://schemas.android.com/tools"
-    android:background="@color/default_bg_color">
+    android:background="?attr/colorSurface">
     <FrameLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent">
diff --git a/chrome/android/features/tab_ui/java/res/layout/tab_grid_dialog_layout.xml b/chrome/android/features/tab_ui/java/res/layout/tab_grid_dialog_layout.xml
index a05a4ba0..74000fb 100644
--- a/chrome/android/features/tab_ui/java/res/layout/tab_grid_dialog_layout.xml
+++ b/chrome/android/features/tab_ui/java/res/layout/tab_grid_dialog_layout.xml
@@ -25,20 +25,18 @@
             android:orientation="vertical"
             android:layout_alignParentBottom="true"
             android:layout_centerHorizontal="true"
-            android:visibility="invisible">
+            android:visibility="invisible"
+            tools:ignore="UseCompoundDrawables">
             <ImageView
                 android:layout_width="match_parent"
-                android:layout_height="@dimen/toolbar_shadow_height"
-                android:src="@drawable/modern_toolbar_shadow"
-                android:scaleType="fitXY"
-                android:scaleY="-1"
-                android:tint="@color/ungroup_bar_shadow_color"
+                style="?attr/tabGridDialogUngroupBarDividerStyle"
                 tools:ignore="ContentDescription" />
             <TextView
                 android:layout_width="match_parent"
                 android:layout_height="@dimen/bottom_sheet_peek_height"
                 android:id="@+id/dialog_ungroup_bar_text"
                 android:text="@string/tab_grid_dialog_remove_from_group"
+                android:textAppearance="@style/TextAppearance.TextMediumThick.Primary"
                 android:background="@drawable/ungroup_bar_background"
                 android:gravity="center" />
         </LinearLayout>
diff --git a/chrome/android/features/tab_ui/java/res/values/attrs.xml b/chrome/android/features/tab_ui/java/res/values/attrs.xml
index 6a92f634..ec0d111 100644
--- a/chrome/android/features/tab_ui/java/res/values/attrs.xml
+++ b/chrome/android/features/tab_ui/java/res/values/attrs.xml
@@ -19,4 +19,9 @@
     <attr name="tabGridFaviconStyle" format="reference" />
     <attr name="tabGridThumbnailStyle" format="reference" />
     <attr name="tabGridActionButtonStyle" format="reference" />
+
+    <!-- Tab grid dialog attributes -->
+    <attr name="tabGridDialogCornerRadius" format="dimension" />
+    <attr name="tabGridDialogAppBarPadding" format="dimension" />
+    <attr name="tabGridDialogUngroupBarDividerStyle" format="reference" />
 </resources>
diff --git a/chrome/android/features/tab_ui/java/res/values/colors.xml b/chrome/android/features/tab_ui/java/res/values/colors.xml
index 74f1558..b0fb190 100644
--- a/chrome/android/features/tab_ui/java/res/values/colors.xml
+++ b/chrome/android/features/tab_ui/java/res/values/colors.xml
@@ -33,6 +33,10 @@
     <color name="tab_grid_dialog_background_color">@color/default_bg_color_elev_1</color>
     <color name="tab_grid_dialog_background_color_incognito">@color/default_bg_color_dark_elev_1</color>
 
+    <color name="tab_grid_dialog_ungroup_button_text_color">@color/default_icon_color_blue</color>
+    <color name="tab_grid_dialog_ungroup_button_text_color_incognito">@color/default_icon_color_blue_light</color>
+    <color name="tab_grid_dialog_ungroup_button_text_color_hovered">@color/default_text_color_light_list</color>
+
     <color name="ungroup_bar_shadow_color">@android:color/black</color>
 
     <color name="favicon_background_color">@color/default_bg_color_secondary</color>
@@ -63,4 +67,11 @@
 
     <color name="incognito_tab_tile_number_color">@color/baseline_neutral_100</color>
     <color name="incognito_tab_tile_number_selected_color">@color/baseline_primary_900</color>
+
+    <color name="incognito_tab_grid_dialog_background_color">@color/baseline_neutral_900</color>
+
+    <color name="incognito_tab_grid_dialog_ungroup_bar_bg_hovered_color">@color/baseline_primary_200</color>
+
+    <color name="incognito_tab_grid_dialog_ungroup_bar_text_color">@color/baseline_primary_200</color>
+    <color name="incognito_tab_grid_dialog_ungroup_bar_text_hovered_color">@color/modern_white</color>
 </resources>
diff --git a/chrome/android/features/tab_ui/java/res/values/dimens.xml b/chrome/android/features/tab_ui/java/res/values/dimens.xml
index 49ffc05a..f82c97add 100644
--- a/chrome/android/features/tab_ui/java/res/values/dimens.xml
+++ b/chrome/android/features/tab_ui/java/res/values/dimens.xml
@@ -60,6 +60,9 @@
     <dimen name="tab_list_card_action_button_size">48dp</dimen>
     <dimen name="tab_list_card_title_fading_length">24dp</dimen>
 
+    <dimen name="tab_grid_dialog_bg_radius">24dp</dimen>
+    <dimen name="tab_grid_dialog_app_bar_padding">8dp</dimen>
+
     <!-- Elevation -->
     <dimen name="tab_bg_elevation">@dimen/default_elevation_4</dimen>
 
diff --git a/chrome/android/features/tab_ui/java/res/values/styles.xml b/chrome/android/features/tab_ui/java/res/values/styles.xml
index 0b77b3f..165627d 100644
--- a/chrome/android/features/tab_ui/java/res/values/styles.xml
+++ b/chrome/android/features/tab_ui/java/res/values/styles.xml
@@ -55,6 +55,19 @@
         <item name="cornerRadiusBottomEnd">@dimen/tab_grid_card_thumbnail_corner_radius_bottom</item>
     </style>
 
+    <style name="TabGridDialogUngroupBarDivider.Shadow" parent="">
+        <item name="android:layout_height">@dimen/toolbar_shadow_height</item>
+        <item name="android:src">@drawable/modern_toolbar_shadow</item>
+        <item name="android:tint">@color/ungroup_bar_shadow_color</item>
+        <item name="android:scaleType">fitXY</item>
+        <item name="android:scaleY">-1</item>
+    </style>
+
+    <style name="TabGridDialogUngroupBarDivider.Hairline" parent="">
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:src">@drawable/toolbar_hairline</item>
+    </style>
+
     <style name="ThemeRefactorOverlay.Disabled.TabUi" parent="">
         <item name="tabGridDividerVisible">@integer/view_visible</item>
         <item name="tabGridHeaderHeight">@dimen/tab_list_card_title_height</item>
@@ -65,6 +78,10 @@
         <item name="tabGridFaviconStyle">@style/TabGridCardTopFaviconStyle</item>
         <item name="tabGridActionButtonStyle">@style/TabGridCardActionButtonStyle</item>
         <item name="tabGridThumbnailStyle">@style/TabGridCardThumbnailStyle</item>
+
+        <item name="tabGridDialogCornerRadius">@dimen/tab_list_card_radius</item>
+        <item name="tabGridDialogAppBarPadding">0dp</item>
+        <item name="tabGridDialogUngroupBarDividerStyle">@style/TabGridDialogUngroupBarDivider.Shadow</item>
     </style>
 
     <style name="ThemeRefactorOverlay.Enabled.TabUi" parent="">
@@ -77,6 +94,10 @@
         <item name="tabGridFaviconStyle">@style/TabGridCardTopFaviconStyle.ThemeRefactor</item>
         <item name="tabGridActionButtonStyle">@style/TabGridCardActionButtonStyle.ThemeRefactor</item>
         <item name="tabGridThumbnailStyle">@style/TabGridCardThumbnailStyle.ThemeRefactor</item>
+
+        <item name="tabGridDialogCornerRadius">@dimen/tab_grid_dialog_bg_radius</item>
+        <item name="tabGridDialogAppBarPadding">@dimen/tab_grid_dialog_app_bar_padding</item>
+        <item name="tabGridDialogUngroupBarDividerStyle">@style/TabGridDialogUngroupBarDivider.Hairline</item>
     </style>
 
     <style name="TabThumbnailPlaceHolderStyle">
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java
index bf061bbe..31dcb6d 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java
@@ -278,7 +278,7 @@
                 resource.getDimension(R.dimen.tab_grid_thumbnail_favicon_background_down_shift),
                 resource.getColor(R.color.modern_grey_800_alpha_38));
 
-        initializedThumbnailRects(resource, expectedThumbnailAspectRatio);
+        initializedThumbnailRects(context, expectedThumbnailAspectRatio);
 
         // Initialize Rects for favicons and favicon frame.
         final float halfFaviconFrameSize =
@@ -344,12 +344,10 @@
      * Initialize rects used for thumbnails. Depending on whether thene refacotr is enabled, the
      * padding around the thumbnail is different.
      */
-    private void initializedThumbnailRects(Resources resource, float expectedThumbnailAspectRatio) {
+    private void initializedThumbnailRects(Context context, float expectedThumbnailAspectRatio) {
         boolean themeRefactorEnabled = TabUiThemeProvider.themeRefactorEnabled();
 
-        float thumbnailHorizontalPadding = themeRefactorEnabled
-                ? resource.getDimension(R.dimen.tab_grid_card_thumbnail_margin)
-                : resource.getDimension(R.dimen.tab_list_card_padding);
+        float thumbnailHorizontalPadding = TabUiThemeProvider.getTabCardPaddingDimension(context);
         float thumbnailVerticalPadding = themeRefactorEnabled
                 ? thumbnailHorizontalPadding
                 : thumbnailHorizontalPadding / expectedThumbnailAspectRatio;
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java
index c7acef6..d319561 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java
@@ -206,24 +206,28 @@
                                 mContext, R.color.default_icon_color_light_tint_list)
                         : AppCompatResources.getColorStateList(
                                 mContext, R.color.default_icon_color_tint_list);
-                int ungroupBarBackgroundColorId = isIncognito
-                        ? R.color.tab_grid_dialog_background_color_incognito
-                        : R.color.tab_grid_dialog_background_color;
-                int ungroupBarHoveredBackgroundColorId = isIncognito
-                        ? R.color.tab_grid_card_selected_color_incognito
-                        : R.color.tab_grid_card_selected_color;
-                int ungroupBarTextAppearance = isIncognito
-                        ? R.style.TextAppearance_TextMediumThick_Blue_Light
-                        : R.style.TextAppearance_TextMediumThick_Blue;
+                int ungroupBarBackgroundColor =
+                        TabUiThemeProvider.getTabGridDialogUngroupBarBackgroundColor(
+                                context, isIncognito);
+                int ungroupBarHoveredBackgroundColor =
+                        TabUiThemeProvider.getTabGridDialogUngroupBarHoveredBackgroundColor(
+                                context, isIncognito);
+                int ungroupBarTextColor = TabUiThemeProvider.getTabGridDialogUngroupBarTextColor(
+                        context, isIncognito);
+                int ungroupBarHoveredTextColor =
+                        TabUiThemeProvider.getTabGridDialogUngroupBarHoveredTextColor(
+                                context, isIncognito);
 
                 mModel.set(TabGridPanelProperties.DIALOG_BACKGROUND_COLOR, dialogBackgroundColor);
                 mModel.set(TabGridPanelProperties.TINT, tintList);
-                mModel.set(TabGridPanelProperties.DIALOG_UNGROUP_BAR_BACKGROUND_COLOR_ID,
-                        ungroupBarBackgroundColorId);
-                mModel.set(TabGridPanelProperties.DIALOG_UNGROUP_BAR_HOVERED_BACKGROUND_COLOR_ID,
-                        ungroupBarHoveredBackgroundColorId);
-                mModel.set(TabGridPanelProperties.DIALOG_UNGROUP_BAR_TEXT_APPEARANCE,
-                        ungroupBarTextAppearance);
+                mModel.set(TabGridPanelProperties.DIALOG_UNGROUP_BAR_BACKGROUND_COLOR,
+                        ungroupBarBackgroundColor);
+                mModel.set(TabGridPanelProperties.DIALOG_UNGROUP_BAR_HOVERED_BACKGROUND_COLOR,
+                        ungroupBarHoveredBackgroundColor);
+                mModel.set(
+                        TabGridPanelProperties.DIALOG_UNGROUP_BAR_TEXT_COLOR, ungroupBarTextColor);
+                mModel.set(TabGridPanelProperties.DIALOG_UNGROUP_BAR_HOVERED_TEXT_COLOR,
+                        ungroupBarHoveredTextColor);
             }
         };
         mTabModelSelector.addObserver(mTabModelSelectorObserver);
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogView.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogView.java
index a7aea8a..37ded69 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogView.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogView.java
@@ -25,6 +25,7 @@
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
+import androidx.annotation.ColorInt;
 import androidx.annotation.IntDef;
 import androidx.annotation.VisibleForTesting;
 import androidx.core.content.ContextCompat;
@@ -97,20 +98,34 @@
     private int mParentWidth;
     private int mBackgroundDrawableColor;
     private int mUngroupBarStatus = UngroupBarStatus.HIDE;
-    private int mUngroupBarBackgroundColorResourceId = R.color.tab_grid_dialog_background_color;
-    private int mUngroupBarHoveredBackgroundColorResourceId = R.color.tab_grid_card_selected_color;
-    private int mUngroupBarTextAppearance = R.style.TextAppearance_TextMediumThick_Blue;
+    private int mUngroupBarBackgroundColor;
+    private int mUngroupBarHoveredBackgroundColor;
+    @ColorInt
+    private int mUngroupBarTextColor;
+    @ColorInt
+    private int mUngroupBarHoveredTextColor;
 
     public TabGridDialogView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mContext = context;
-        mTabGridCardPadding = mContext.getResources().getDimension(R.dimen.tab_list_card_padding);
+        mTabGridCardPadding = TabUiThemeProvider.getTabCardPaddingDimension(mContext);
         mToolbarHeight =
                 (int) mContext.getResources().getDimension(R.dimen.tab_group_toolbar_height);
         mUngroupBarHeight =
                 (int) mContext.getResources().getDimension(R.dimen.bottom_sheet_peek_height);
         mBackgroundDrawableColor =
                 ContextCompat.getColor(mContext, R.color.tab_grid_dialog_background_color);
+
+        mUngroupBarTextColor =
+                TabUiThemeProvider.getTabGridDialogUngroupBarTextColor(mContext, false);
+        mUngroupBarHoveredTextColor =
+                TabUiThemeProvider.getTabGridDialogUngroupBarHoveredTextColor(mContext, false);
+
+        mUngroupBarBackgroundColor =
+                TabUiThemeProvider.getTabGridDialogUngroupBarBackgroundColor(mContext, false);
+        mUngroupBarHoveredBackgroundColor =
+                TabUiThemeProvider.getTabGridDialogUngroupBarHoveredBackgroundColor(
+                        mContext, false);
     }
 
     @Override
@@ -619,8 +634,7 @@
         ImageView sourceCardFavicon = view.findViewById(R.id.tab_favicon);
         ImageView animationCardFavicon = mAnimationCardView.findViewById(R.id.tab_favicon);
         if (sourceCardFavicon.getDrawable() != null) {
-            int padding =
-                    mContext.getResources().getDimensionPixelSize(R.dimen.tab_list_card_padding);
+            int padding = (int) TabUiThemeProvider.getTabCardPaddingDimension(mContext);
             animationCardFavicon.setPadding(padding, padding, padding, padding);
             animationCardFavicon.setImageDrawable(sourceCardFavicon.getDrawable());
         } else {
@@ -753,12 +767,10 @@
         assert mUngroupBarTextView.getBackground() instanceof GradientDrawable;
         mUngroupBar.bringToFront();
         GradientDrawable background = (GradientDrawable) mUngroupBarTextView.getBackground();
-        background.setColor(ContextCompat.getColor(mContext,
-                isHovered ? mUngroupBarHoveredBackgroundColorResourceId
-                          : mUngroupBarBackgroundColorResourceId));
-        mUngroupBarTextView.setTextAppearance(mContext,
-                isHovered ? R.style.TextAppearance_TextMediumThick_Primary_Light
-                          : mUngroupBarTextAppearance);
+        background.setColor(
+                isHovered ? mUngroupBarHoveredBackgroundColor : mUngroupBarBackgroundColor);
+        mUngroupBarTextView.setTextColor(
+                isHovered ? mUngroupBarHoveredTextColor : mUngroupBarTextColor);
     }
 
     /**
@@ -773,30 +785,34 @@
 
     /**
      * Update the ungroup bar background color.
-     *
-     * @param colorResource The new background color resource to use when ungroup bar is visible.
+     * @param colorInt The new background color to use when ungroup bar is visible.
      */
-    void updateUngroupBarBackgroundColor(int colorResource) {
-        mUngroupBarBackgroundColorResourceId = colorResource;
+    void updateUngroupBarBackgroundColor(int colorInt) {
+        mUngroupBarBackgroundColor = colorInt;
     }
 
     /**
      * Update the ungroup bar background color when the ungroup bar is hovered.
-     *
-     * @param colorResource The new background color resource to use when ungroup bar is visible
-     *                      and hovered.
+     * @param colorInt The new background color to use when ungroup bar is visible and hovered.
      */
-    void updateUngroupBarHoveredBackgroundColor(int colorResource) {
-        mUngroupBarHoveredBackgroundColorResourceId = colorResource;
+    void updateUngroupBarHoveredBackgroundColor(int colorInt) {
+        mUngroupBarHoveredBackgroundColor = colorInt;
     }
 
     /**
-     * Update the ungroup bar text appearance when the ungroup bar is visible but not hovered.
-     *
-     * @param textAppearance The new text appearance to use.
+     * Update the ungroup bar text color when the ungroup bar is visible but not hovered.
+     * @param colorInt The new text color to use when ungroup bar is visible.
      */
-    void updateUngroupBarTextAppearance(int textAppearance) {
-        mUngroupBarTextAppearance = textAppearance;
+    void updateUngroupBarTextColor(int colorInt) {
+        mUngroupBarTextColor = colorInt;
+    }
+
+    /**
+     * Update the ungroup bar text color when the ungroup bar is hovered.
+     * @param colorInt The new text color to use when ungroup bar is visible and hovered.
+     */
+    void updateUngroupBarHoveredTextColor(int colorInt) {
+        mUngroupBarHoveredTextColor = colorInt;
     }
 
     /**
@@ -832,18 +848,23 @@
     }
 
     @VisibleForTesting
-    int getUngroupBarBackgroundColorResourceIdForTesting() {
-        return mUngroupBarBackgroundColorResourceId;
+    int getUngroupBarBackgroundColorForTesting() {
+        return mUngroupBarBackgroundColor;
     }
 
     @VisibleForTesting
-    int getUngroupBarHoveredBackgroundColorResourceIdForTesting() {
-        return mUngroupBarHoveredBackgroundColorResourceId;
+    int getUngroupBarHoveredBackgroundColorForTesting() {
+        return mUngroupBarHoveredBackgroundColor;
     }
 
     @VisibleForTesting
-    int getUngroupBarTextAppearanceForTesting() {
-        return mUngroupBarTextAppearance;
+    int getUngroupBarTextColorForTesting() {
+        return mUngroupBarTextColor;
+    }
+
+    @VisibleForTesting
+    int getUngroupBarHoveredTextColorForTesting() {
+        return mUngroupBarHoveredTextColor;
     }
 
     @VisibleForTesting
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelProperties.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelProperties.java
index 8d92a72..66ad6a74 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelProperties.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelProperties.java
@@ -40,13 +40,14 @@
             new PropertyModel.WritableObjectPropertyKey<>(true);
     public static final PropertyModel.WritableIntPropertyKey UNGROUP_BAR_STATUS =
             new PropertyModel.WritableIntPropertyKey();
-    public static final PropertyModel
-            .WritableIntPropertyKey DIALOG_UNGROUP_BAR_BACKGROUND_COLOR_ID =
+    public static final PropertyModel.WritableIntPropertyKey DIALOG_UNGROUP_BAR_BACKGROUND_COLOR =
             new PropertyModel.WritableIntPropertyKey();
     public static final PropertyModel
-            .WritableIntPropertyKey DIALOG_UNGROUP_BAR_HOVERED_BACKGROUND_COLOR_ID =
+            .WritableIntPropertyKey DIALOG_UNGROUP_BAR_HOVERED_BACKGROUND_COLOR =
             new PropertyModel.WritableIntPropertyKey();
-    public static final PropertyModel.WritableIntPropertyKey DIALOG_UNGROUP_BAR_TEXT_APPEARANCE =
+    public static final PropertyModel.WritableIntPropertyKey DIALOG_UNGROUP_BAR_TEXT_COLOR =
+            new PropertyModel.WritableIntPropertyKey();
+    public static final PropertyModel.WritableIntPropertyKey DIALOG_UNGROUP_BAR_HOVERED_TEXT_COLOR =
             new PropertyModel.WritableIntPropertyKey();
     /**
      * Integer, but not {@link PropertyModel.WritableIntPropertyKey} so that we can force update on
@@ -76,9 +77,10 @@
     public static final PropertyKey[] ALL_KEYS = new PropertyKey[] {COLLAPSE_CLICK_LISTENER,
             ADD_CLICK_LISTENER, HEADER_TITLE, CONTENT_TOP_MARGIN, PRIMARY_COLOR,
             DIALOG_BACKGROUND_COLOR, TINT, IS_DIALOG_VISIBLE, SCRIMVIEW_CLICK_RUNNABLE,
-            ANIMATION_SOURCE_VIEW, UNGROUP_BAR_STATUS, DIALOG_UNGROUP_BAR_BACKGROUND_COLOR_ID,
-            DIALOG_UNGROUP_BAR_HOVERED_BACKGROUND_COLOR_ID, DIALOG_UNGROUP_BAR_TEXT_APPEARANCE,
-            INITIAL_SCROLL_INDEX, IS_MAIN_CONTENT_VISIBLE, MENU_CLICK_LISTENER, TITLE_TEXT_WATCHER,
-            TITLE_TEXT_ON_FOCUS_LISTENER, TITLE_CURSOR_VISIBILITY, IS_TITLE_TEXT_FOCUSED,
-            IS_KEYBOARD_VISIBLE, COLLAPSE_BUTTON_CONTENT_DESCRIPTION};
+            ANIMATION_SOURCE_VIEW, UNGROUP_BAR_STATUS, DIALOG_UNGROUP_BAR_BACKGROUND_COLOR,
+            DIALOG_UNGROUP_BAR_HOVERED_BACKGROUND_COLOR, DIALOG_UNGROUP_BAR_TEXT_COLOR,
+            DIALOG_UNGROUP_BAR_HOVERED_TEXT_COLOR, INITIAL_SCROLL_INDEX, IS_MAIN_CONTENT_VISIBLE,
+            MENU_CLICK_LISTENER, TITLE_TEXT_WATCHER, TITLE_TEXT_ON_FOCUS_LISTENER,
+            TITLE_CURSOR_VISIBILITY, IS_TITLE_TEXT_FOCUSED, IS_KEYBOARD_VISIBLE,
+            COLLAPSE_BUTTON_CONTENT_DESCRIPTION};
 }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinder.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinder.java
index 1cb8713..707c6b82 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinder.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinder.java
@@ -10,9 +10,10 @@
 import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.COLLAPSE_CLICK_LISTENER;
 import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.CONTENT_TOP_MARGIN;
 import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.DIALOG_BACKGROUND_COLOR;
-import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.DIALOG_UNGROUP_BAR_BACKGROUND_COLOR_ID;
-import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.DIALOG_UNGROUP_BAR_HOVERED_BACKGROUND_COLOR_ID;
-import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.DIALOG_UNGROUP_BAR_TEXT_APPEARANCE;
+import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.DIALOG_UNGROUP_BAR_BACKGROUND_COLOR;
+import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.DIALOG_UNGROUP_BAR_HOVERED_BACKGROUND_COLOR;
+import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.DIALOG_UNGROUP_BAR_HOVERED_TEXT_COLOR;
+import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.DIALOG_UNGROUP_BAR_TEXT_COLOR;
 import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.HEADER_TITLE;
 import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.INITIAL_SCROLL_INDEX;
 import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.IS_DIALOG_VISIBLE;
@@ -100,20 +101,25 @@
                 viewHolder.dialogView.updateDialogContainerBackgroundColor(backgroundColorInt);
                 viewHolder.toolbarView.setBackgroundColorTint(backgroundColorInt);
             }
-        } else if (DIALOG_UNGROUP_BAR_BACKGROUND_COLOR_ID == propertyKey) {
+        } else if (DIALOG_UNGROUP_BAR_BACKGROUND_COLOR == propertyKey) {
             if (viewHolder.dialogView != null) {
                 viewHolder.dialogView.updateUngroupBarBackgroundColor(
-                        model.get(DIALOG_UNGROUP_BAR_BACKGROUND_COLOR_ID));
+                        model.get(DIALOG_UNGROUP_BAR_BACKGROUND_COLOR));
             }
-        } else if (DIALOG_UNGROUP_BAR_HOVERED_BACKGROUND_COLOR_ID == propertyKey) {
+        } else if (DIALOG_UNGROUP_BAR_HOVERED_BACKGROUND_COLOR == propertyKey) {
             if (viewHolder.dialogView != null) {
                 viewHolder.dialogView.updateUngroupBarHoveredBackgroundColor(
-                        model.get(DIALOG_UNGROUP_BAR_HOVERED_BACKGROUND_COLOR_ID));
+                        model.get(DIALOG_UNGROUP_BAR_HOVERED_BACKGROUND_COLOR));
             }
-        } else if (DIALOG_UNGROUP_BAR_TEXT_APPEARANCE == propertyKey) {
+        } else if (DIALOG_UNGROUP_BAR_TEXT_COLOR == propertyKey) {
             if (viewHolder.dialogView != null) {
-                viewHolder.dialogView.updateUngroupBarTextAppearance(
-                        model.get(DIALOG_UNGROUP_BAR_TEXT_APPEARANCE));
+                viewHolder.dialogView.updateUngroupBarTextColor(
+                        model.get(DIALOG_UNGROUP_BAR_TEXT_COLOR));
+            }
+        } else if (DIALOG_UNGROUP_BAR_HOVERED_TEXT_COLOR == propertyKey) {
+            if (viewHolder.dialogView != null) {
+                viewHolder.dialogView.updateUngroupBarHoveredTextColor(
+                        model.get(DIALOG_UNGROUP_BAR_HOVERED_TEXT_COLOR));
             }
         } else if (INITIAL_SCROLL_INDEX == propertyKey) {
             int index = (Integer) model.get(INITIAL_SCROLL_INDEX);
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java
index b23df77..1ba48ca 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java
@@ -320,9 +320,121 @@
      */
     @ColorInt
     public static int getTabGridDialogBackgroundColor(Context context, boolean isIncognito) {
-        return ContextCompat.getColor(context,
-                isIncognito ? R.color.tab_grid_dialog_background_color_incognito
-                            : R.color.tab_grid_dialog_background_color);
+        if (!themeRefactorEnabled()) {
+            return ContextCompat.getColor(context,
+                    isIncognito ? R.color.tab_grid_dialog_background_color_incognito
+                                : R.color.tab_grid_dialog_background_color);
+        }
+
+        if (isIncognito) {
+            return ApiCompatibilityUtils.getColor(
+                    context.getResources(), R.color.incognito_tab_grid_dialog_background_color);
+        } else {
+            return MaterialColors.getColor(context, R.attr.colorSurface, TAG);
+        }
+    }
+
+    @ColorInt
+    private static int getTabGridDialogUngroupBarBackgroundColor(
+            Context context, boolean isIncognito, boolean isTabHovered) {
+        if (!themeRefactorEnabled()) {
+            @ColorRes
+            int colorRes;
+            if (isTabHovered) {
+                colorRes = isIncognito ? R.color.tab_grid_card_selected_color_incognito
+                                       : R.color.tab_grid_card_selected_color;
+            } else {
+                colorRes = isIncognito ? R.color.tab_grid_dialog_background_color_incognito
+                                       : R.color.tab_grid_dialog_background_color;
+            }
+            return ApiCompatibilityUtils.getColor(context.getResources(), colorRes);
+        }
+
+        if (isIncognito) {
+            return ApiCompatibilityUtils.getColor(context.getResources(),
+                    isTabHovered ? R.color.incognito_tab_grid_dialog_ungroup_bar_bg_hovered_color
+                                 : R.color.incognito_tab_grid_dialog_background_color);
+        } else {
+            return MaterialColors.getColor(
+                    context, isTabHovered ? R.attr.colorPrimary : R.attr.colorSurface, TAG);
+        }
+    }
+
+    @ColorInt
+    private static int getTabGridDialogUngroupBarTextColor(
+            Context context, boolean isIncognito, boolean isTabHovered) {
+        if (!themeRefactorEnabled()) {
+            @ColorRes
+            int colorRes;
+            if (isTabHovered) {
+                colorRes = R.color.tab_grid_dialog_ungroup_button_text_color_hovered;
+            } else {
+                colorRes = isIncognito ? R.color.tab_grid_dialog_ungroup_button_text_color_incognito
+                                       : R.color.tab_grid_dialog_ungroup_button_text_color;
+            }
+            return ApiCompatibilityUtils.getColor(context.getResources(), colorRes);
+        }
+
+        if (isIncognito) {
+            return ApiCompatibilityUtils.getColor(context.getResources(),
+                    isTabHovered ? R.color.incognito_tab_grid_dialog_ungroup_bar_text_hovered_color
+                                 : R.color.incognito_tab_grid_dialog_ungroup_bar_text_color);
+        } else {
+            return MaterialColors.getColor(
+                    context, isTabHovered ? R.attr.colorOnPrimary : R.attr.colorPrimary, TAG);
+        }
+    }
+
+    /**
+     * Returns the background color used for the ungroup bar in tab grid dialog.
+     *
+     * @param context {@link Context} used to retrieve color.
+     * @param isIncognito Whether the color is used for incognito mode.
+     * @return The background color for the ungroup bar in tab grid dialog.
+     */
+    @ColorInt
+    public static int getTabGridDialogUngroupBarTextColor(Context context, boolean isIncognito) {
+        return getTabGridDialogUngroupBarTextColor(context, isIncognito, false);
+    }
+
+    /**
+     * Returns the background color used for the ungroup bar in tab grid dialog when a tab is
+     * hovered.
+     *
+     * @param context {@link Context} used to retrieve color.
+     * @param isIncognito Whether the color is used for incognito mode.
+     * @return The background color for the ungroup bar in tab grid dialog.
+     */
+    @ColorInt
+    public static int getTabGridDialogUngroupBarHoveredTextColor(
+            Context context, boolean isIncognito) {
+        return getTabGridDialogUngroupBarTextColor(context, isIncognito, true);
+    }
+
+    /**
+     * Returns the color used for the ungroup bar text in tab grid dialog.
+     *
+     * @param context {@link Context} used to retrieve color.
+     * @param isIncognito Whether the color is used for incognito mode.
+     * @return The color for the ungroup bar text in tab grid dialog.
+     */
+    @ColorInt
+    public static int getTabGridDialogUngroupBarBackgroundColor(
+            Context context, boolean isIncognito) {
+        return getTabGridDialogUngroupBarBackgroundColor(context, isIncognito, false);
+    }
+
+    /**
+     * Returns the color used for the ungroup bar text in tab grid dialog when a tab is hovered.
+     *
+     * @param context {@link Context} used to retrieve color.
+     * @param isIncognito Whether the color is used for incognito mode.
+     * @return The color for the ungroup bar text in tab grid dialog.
+     */
+    @ColorInt
+    public static int getTabGridDialogUngroupBarHoveredBackgroundColor(
+            Context context, boolean isIncognito) {
+        return getTabGridDialogUngroupBarBackgroundColor(context, isIncognito, true);
     }
 
     /**
@@ -384,6 +496,17 @@
     }
 
     /**
+     * Return the size represented by dimension for padding between tab cards.
+     * @param context {@link Context} to retrieve dimension.
+     * @return The padding between tab cards in float number.
+     */
+    public static float getTabCardPaddingDimension(Context context) {
+        return context.getResources().getDimension(themeRefactorEnabled()
+                        ? R.dimen.tab_grid_card_thumbnail_margin
+                        : R.dimen.tab_list_card_padding);
+    }
+
+    /**
      * Returns the style resource Id that requires for Tab UI.
      *
      * @return The resource Id for the theme overlay used for tab UI.
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java
index b58e9a86..cfdef45 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java
@@ -305,7 +305,7 @@
 
         // Add 400px top margin to the recyclerView.
         RecyclerView recyclerView = cta.findViewById(R.id.tab_list_view);
-        float tabGridCardPadding = cta.getResources().getDimension(R.dimen.tab_list_card_padding);
+        float tabGridCardPadding = TabUiThemeProvider.getTabCardPaddingDimension(cta);
         int deltaTopMargin = 400;
         ViewGroup.MarginLayoutParams params =
                 (ViewGroup.MarginLayoutParams) recyclerView.getLayoutParams();
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinderTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinderTest.java
index 8b326ed..df9d678 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinderTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinderTest.java
@@ -306,49 +306,73 @@
     @SmallTest
     @UiThreadTest
     public void testSetUngroupbarBackgroundColor() {
-        int normalColorId = R.color.tab_grid_dialog_background_color;
-        int incognitoColorId = R.color.tab_grid_dialog_background_color_incognito;
+        int normalColor =
+                ContextCompat.getColor(getActivity(), R.color.tab_grid_dialog_background_color);
+        int incognitoColor = ContextCompat.getColor(
+                getActivity(), R.color.tab_grid_dialog_background_color_incognito);
         // Default setup is in normal mode.
-        Assert.assertEquals(normalColorId,
-                mTabGridDialogView.getUngroupBarBackgroundColorResourceIdForTesting());
+        Assert.assertEquals(
+                normalColor, mTabGridDialogView.getUngroupBarBackgroundColorForTesting());
 
-        mModel.set(TabGridPanelProperties.DIALOG_UNGROUP_BAR_BACKGROUND_COLOR_ID, incognitoColorId);
+        mModel.set(TabGridPanelProperties.DIALOG_UNGROUP_BAR_BACKGROUND_COLOR, incognitoColor);
 
-        Assert.assertEquals(incognitoColorId,
-                mTabGridDialogView.getUngroupBarBackgroundColorResourceIdForTesting());
+        Assert.assertEquals(
+                incognitoColor, mTabGridDialogView.getUngroupBarBackgroundColorForTesting());
     }
 
     @Test
     @SmallTest
     @UiThreadTest
     public void testSetUngroupbarHoveredBackgroundColor() {
-        int normalColorId = R.color.tab_grid_card_selected_color;
-        int incognitoColorId = R.color.tab_grid_card_selected_color_incognito;
+        int normalColorId =
+                ContextCompat.getColor(getActivity(), R.color.tab_grid_card_selected_color);
+        int incognitoColorId = ContextCompat.getColor(
+                getActivity(), R.color.tab_grid_card_selected_color_incognito);
         // Default setup is in normal mode.
-        Assert.assertEquals(normalColorId,
-                mTabGridDialogView.getUngroupBarHoveredBackgroundColorResourceIdForTesting());
+        Assert.assertEquals(
+                normalColorId, mTabGridDialogView.getUngroupBarHoveredBackgroundColorForTesting());
 
-        mModel.set(TabGridPanelProperties.DIALOG_UNGROUP_BAR_HOVERED_BACKGROUND_COLOR_ID,
+        mModel.set(TabGridPanelProperties.DIALOG_UNGROUP_BAR_HOVERED_BACKGROUND_COLOR,
                 incognitoColorId);
 
         Assert.assertEquals(incognitoColorId,
-                mTabGridDialogView.getUngroupBarHoveredBackgroundColorResourceIdForTesting());
+                mTabGridDialogView.getUngroupBarHoveredBackgroundColorForTesting());
     }
 
     @Test
     @SmallTest
     @UiThreadTest
-    public void testSetUngroupbarTextAppearance() {
-        int normalStyleId = R.style.TextAppearance_TextMediumThick_Blue;
-        int incognitoStyleId = R.style.TextAppearance_TextMediumThick_Blue_Light;
+    public void testSetUngroupbarTextColor() {
+        int normalColor = ContextCompat.getColor(
+                getActivity(), R.color.tab_grid_dialog_ungroup_button_text_color);
+        int incognitoColor = ContextCompat.getColor(
+                getActivity(), R.color.tab_grid_dialog_ungroup_button_text_color_incognito);
+        // Default setup is in normal mode.
+        Assert.assertEquals(normalColor, mTabGridDialogView.getUngroupBarTextColorForTesting());
+
+        mModel.set(TabGridPanelProperties.DIALOG_UNGROUP_BAR_TEXT_COLOR, incognitoColor);
+
+        Assert.assertEquals(incognitoColor, mTabGridDialogView.getUngroupBarTextColorForTesting());
+    }
+
+    @Test
+    @SmallTest
+    @UiThreadTest
+    public void testSetUngroupbarHoveredTextColor() {
+        int normalColor = ContextCompat.getColor(
+                getActivity(), R.color.tab_grid_dialog_ungroup_button_text_color_hovered);
+        // Another color just for the sake of testing, as the hovered color does not change before
+        // theme refactor.
+        int incognitoColor = ContextCompat.getColor(
+                getActivity(), R.color.tab_grid_dialog_ungroup_button_text_color_incognito);
         // Default setup is in normal mode.
         Assert.assertEquals(
-                normalStyleId, mTabGridDialogView.getUngroupBarTextAppearanceForTesting());
+                normalColor, mTabGridDialogView.getUngroupBarHoveredTextColorForTesting());
 
-        mModel.set(TabGridPanelProperties.DIALOG_UNGROUP_BAR_TEXT_APPEARANCE, incognitoStyleId);
+        mModel.set(TabGridPanelProperties.DIALOG_UNGROUP_BAR_HOVERED_TEXT_COLOR, incognitoColor);
 
         Assert.assertEquals(
-                incognitoStyleId, mTabGridDialogView.getUngroupBarTextAppearanceForTesting());
+                incognitoColor, mTabGridDialogView.getUngroupBarHoveredTextColorForTesting());
     }
 
     @Test
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java b/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java
index 2ed4b8a..98a5c6a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java
@@ -6,7 +6,7 @@
 
 import android.text.TextUtils;
 
-import org.chromium.base.annotations.RemovableInRelease;
+import org.chromium.build.BuildConfig;
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
 import org.chromium.chrome.browser.customtabs.CustomTabActivity;
 import org.chromium.chrome.browser.firstrun.FirstRunUtils;
@@ -165,8 +165,9 @@
         mIsFinishedCachingNativeFlags = true;
     }
 
-    @RemovableInRelease
     private void tryToCatchMissingParameters(List<CachedFieldTrialParameter> listed) {
+        if (!BuildConfig.ENABLE_ASSERTS) return;
+
         // All instances of CachedFieldTrialParameter should be manually passed to
         // CachedFeatureFlags.cacheFieldTrialParameters(). The following checking is a best-effort
         // attempt to try to catch accidental omissions. It cannot replace the list because some
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordCheckupLauncher.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordCheckupLauncher.java
index 638789ef..74e6df9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordCheckupLauncher.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordCheckupLauncher.java
@@ -6,7 +6,6 @@
 import android.app.Activity;
 import android.content.Intent;
 import android.net.Uri;
-
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.chrome.browser.AppHooks;
 import org.chromium.chrome.browser.password_check.PasswordCheckFactory;
@@ -33,6 +32,14 @@
     }
 
     @CalledByNative
+    private static void launchLocalCheckupFromPhishGuardWarningDialog(WindowAndroid windowAndroid) {
+        if (windowAndroid.getContext().get() == null) return; // Window not available yet/anymore.
+        PasswordCheckFactory.getOrCreate(new SettingsLauncherImpl())
+                .showUi(windowAndroid.getContext().get(),
+                        PasswordCheckReferrer.PHISHED_WARNING_DIALOG);
+    }
+
+    @CalledByNative
     private static void launchCheckupInAccountWithActivity(String checkupUrl, Activity activity) {
         if (tryLaunchingNativePasswordCheckup(activity)) return;
         Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(checkupUrl));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareButtonController.java b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareButtonController.java
index ca8b0557..888c8b8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareButtonController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareButtonController.java
@@ -195,8 +195,7 @@
                     ChromeFeatureList.SHARE_BUTTON_IN_TOP_TOOLBAR, "minimum_width", MIN_WIDTH_DP);
         }
 
-        boolean isDeviceWideEnough = mScreenWidthDp > mMinimumWidthDp;
-
+        final boolean isDeviceWideEnough = mScreenWidthDp >= mMinimumWidthDp;
         if (mShareDelegateSupplier.get() == null || !isDeviceWideEnough) {
             mButtonData.setCanShow(false);
             return;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulatorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulatorTest.java
index 3bd51381..1aac85e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulatorTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulatorTest.java
@@ -155,7 +155,9 @@
                 for (int initialListIndex = 0; initialListIndex < expectedItemsInGroup.length;
                         initialListIndex++) {
                     if (expectedItemsInGroup[initialListIndex]
-                            != R.id.contextmenu_open_in_ephemeral_tab) {
+                                    != R.id.contextmenu_open_in_ephemeral_tab
+                            && expectedItemsInGroup[initialListIndex]
+                                    != R.id.contextmenu_open_image_in_ephemeral_tab) {
                         updatedList.add(expectedItemsInGroup[initialListIndex]);
                     }
                 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/share/ShareButtonControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/share/ShareButtonControllerTest.java
index 26606e1..728cd56 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/share/ShareButtonControllerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/share/ShareButtonControllerTest.java
@@ -78,7 +78,7 @@
         int deviceWidth =
                 mActivityTestRule.getActivity().getResources().getConfiguration().screenWidthDp;
 
-        mButtonExpected = deviceWidth > minimumWidthDp;
+        mButtonExpected = deviceWidth >= minimumWidthDp;
     }
 
     @Test
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/share/ShareButtonControllerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/share/ShareButtonControllerUnitTest.java
index f4004a8..7970a00 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/share/ShareButtonControllerUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/share/ShareButtonControllerUnitTest.java
@@ -5,9 +5,12 @@
 package org.chromium.chrome.browser.share;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
@@ -23,7 +26,6 @@
 import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
 
@@ -33,6 +35,7 @@
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.toolbar.ButtonData;
 import org.chromium.chrome.browser.toolbar.adaptive.AdaptiveToolbarFeatures;
 import org.chromium.chrome.browser.user_education.IPHCommandBuilder;
 import org.chromium.chrome.test.util.browser.Features;
@@ -40,6 +43,7 @@
 import org.chromium.components.feature_engagement.EventConstants;
 import org.chromium.components.feature_engagement.FeatureConstants;
 import org.chromium.components.feature_engagement.Tracker;
+import org.chromium.content_public.browser.WebContents;
 import org.chromium.testing.local.LocalRobolectricTestRunner;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 
@@ -82,13 +86,15 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
+        doReturn(mTab).when(mTabProvider).get();
         doReturn(mContext).when(mTab).getContext();
         doReturn(mResources).when(mContext).getResources();
-
         mConfiguration.screenWidthDp = ShareButtonController.MIN_WIDTH_DP + WIDTH_DELTA;
         doReturn(mConfiguration).when(mResources).getConfiguration();
 
-        doReturn(mTab).when(mTabProvider).get();
+        doReturn(mock(WebContents.class)).when(mTab).getWebContents();
+        doReturn(true).when(mShareUtils).shouldEnableShare(mTab);
+
         doReturn(mShareDelegate).when(mShareDelegateSupplier).get();
 
         AdaptiveToolbarFeatures.clearParsedParamsForTesting();
@@ -124,10 +130,32 @@
         doReturn(true).when(mTracker).shouldTriggerHelpUI(
                 FeatureConstants.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_CUSTOMIZATION_SHARE_FEATURE);
 
-        View view = Mockito.mock(View.class);
+        View view = mock(View.class);
         mShareButtonController.get(mTab).getButtonSpec().getOnClickListener().onClick(view);
 
         verify(mTracker, times(1))
                 .notifyEvent(EventConstants.ADAPTIVE_TOOLBAR_CUSTOMIZATION_SHARE_OPENED);
     }
+
+    @Test
+    @EnableFeatures({ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_CUSTOMIZATION})
+    public void testDoNotShowWhenTooNarrow() {
+        mConfiguration.screenWidthDp = ShareButtonController.MIN_WIDTH_DP - 1;
+        mShareButtonController.onConfigurationChanged(mConfiguration);
+
+        ButtonData buttonData = mShareButtonController.get(mTab);
+
+        assertFalse(buttonData.canShow());
+    }
+
+    @Test
+    @EnableFeatures({ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_CUSTOMIZATION})
+    public void testDoShowWhenWideEnough() {
+        mConfiguration.screenWidthDp = ShareButtonController.MIN_WIDTH_DP;
+        mShareButtonController.onConfigurationChanged(mConfiguration);
+
+        ButtonData buttonData = mShareButtonController.get(mTab);
+
+        assertTrue(buttonData.canShow());
+    }
 }
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 63968fc..bf6e97bc 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-93.0.4574.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-amd64-93.0.4576.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index e8071059..7521487 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -322,33 +322,33 @@
     We've found multiple profiles available to download. Select the ones you would like to download before proceeding.
   </message>
   <message name="IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE" desc="Label for informing the user on ways to retrieve an eSim profile">
-    Scan a QR code using your device camera or enter the activation code provided by your carrier
+    Scan a QR Code using your device camera or enter the activation code provided by your carrier
   </message>
   <message name="IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE_ENTER_ACTIVATION_CODE" desc="Label for informing the user to enter activation code when no media devices have been found">
     Please enter your activation code
   </message>
-  <message name="IDS_CELLULAR_SETUP_ESIM_PAGE_USE_CAMERA" desc="Label for button that uses the camera to scan for QR codes when clicked.">
-    Use camera to scan QR code
+  <message name="IDS_CELLULAR_SETUP_ESIM_PAGE_USE_CAMERA" desc="Label for button that uses the camera to scan for QR Codes when clicked.">
+    Use camera to scan QR Code
   </message>
   <message name="IDS_CELLULAR_SETUP_ESIM_PAGE_SWITCH_CAMERA" desc="Label for button that toggles the camera between user-facing and environment-facing.">
     Flip camera
   </message>
-  <message name="IDS_CELLULAR_SETUP_ESIM_PAGE_A11Y_QR_CODE_CAMERA_ON" desc="Accessibility announcement provided during the eSIM setup flow which alerts the user about how to set up an eSIM profile to use for a cellular connection. The flow involves clicking a button to cause the device's webcam to turn on, then the user showing a QR code to the camera to continue.">
-    Device camera has turned on. Please place your eSIM QR code in front of the camera.
+  <message name="IDS_CELLULAR_SETUP_ESIM_PAGE_A11Y_QR_CODE_CAMERA_ON" desc="Accessibility announcement provided during the eSIM setup flow which alerts the user about how to set up an eSIM profile to use for a cellular connection. The flow involves clicking a button to cause the device's webcam to turn on, then the user showing a QR Code to the camera to continue.">
+    Device camera has turned on. Please place your eSIM QR Code in front of the camera.
   </message>
   <message name="IDS_CELLULAR_SETUP_ESIM_PAGE_A11Y_QR_CODE_CAMERA_SCAN_SUCCESS" desc="Accessibility announcement provided during the eSIM setup flow which alerts the user that a qr code has been succesfully scanned by the device camera.">
-    QR code has been scanned.
+    QR Code has been scanned.
   </message>
   <message name="IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE_SUCCESS" desc="Label informing the user that an an activation code was scanned successfully.">
     Activation code detected
   </message>
-  <message name="IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE_USE_CAMERA_AGAIN" desc="Label for button informing the user to click to use the camera to rescan for QR codes.">
+  <message name="IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE_USE_CAMERA_AGAIN" desc="Label for button informing the user to click to use the camera to rescan for QR Codes.">
     Use camera again
   </message>
   <message name="IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE_ERROR" desc="Label informing the user that there was an error detecting activation code.">
     Error detecting code
   </message>
-  <message name="IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE_RETRY" desc="Label for button informing user to retry rescan of QR codes.">
+  <message name="IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE_RETRY" desc="Label for button informing user to retry rescan of QR Codes.">
     Try again
   </message>
   <message name="IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE_LOADING" desc="Label informing the user that the activation code is currently being verified.">
@@ -363,16 +363,16 @@
   <message name="IDS_CELLULAR_SETUP_ESTABLISH_NETWORK_CONNECTION" desc="Message, informing user that a network connection is being established during cellular setup">
     Establishing network connection ...
   </message>
-  <message name="IDS_CELLULAR_SETUP_EID_MENU_ITEM_TITLE" desc="Title for menu item in the eSIM list triple dot menu that shows the EID and QR code dialog when clicked.">
+  <message name="IDS_CELLULAR_SETUP_EID_MENU_ITEM_TITLE" desc="Title for menu item in the eSIM list triple dot menu that shows the EID and QR Code dialog when clicked.">
     Show device EID
   </message>
-  <message name="IDS_CELLULAR_SETUP_EID_POPUP_TITLE" desc="Label shown when vewing EID and QR code popup describing device EID">
+  <message name="IDS_CELLULAR_SETUP_EID_POPUP_TITLE" desc="Label shown when vewing EID and QR Code popup describing device EID">
     Your device EID
   </message>
-  <message name="IDS_CELLULAR_SETUP_EID_POPUP_DESCRIPTION" desc="Label shown when veiwing EID and QR code popup describing what an EID number is used for">
+  <message name="IDS_CELLULAR_SETUP_EID_POPUP_DESCRIPTION" desc="Label shown when veiwing EID and QR Code popup describing what an EID number is used for">
     A customer service rep can use this EID number to help you activate service
   </message>
-  <message name="IDS_CELLULAR_SETUP_EID_POPUP_A11Y_LABEL" desc="A11y label for EID and QR code dialog describing what the device's EID number is and what it's used for">
+  <message name="IDS_CELLULAR_SETUP_EID_POPUP_A11Y_LABEL" desc="A11y label for EID and QR Code dialog describing what the device's EID number is and what it's used for">
     Your device EID is <ph name="EID_NUMBER">$1<ex>123456789</ex></ph>. A customer service rep can use the EID number to help you activate service.
   </message>
   <message name="IDS_CELLULAR_SETUP_ESIM_PAGE_CONFIRMATION_CODE_MESSAGE" desc="Message, prompting the user to enter the confirmation code to activate an eSIM profile.">
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 2d2531e..c7102b2 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -3861,7 +3861,7 @@
           Profile Importer
         </message>
       </if>
-      <message name="IDS_UTILITY_PROCESS_QRCODE_GENERATOR_SERVICE_NAME" desc="The name of the utility process used for encoding QR codes.">
+      <message name="IDS_UTILITY_PROCESS_QRCODE_GENERATOR_SERVICE_NAME" desc="The name of the utility process used for encoding QR Codes.">
         QR Code Generator
       </message>
       <if expr="is_win">
@@ -7724,55 +7724,55 @@
       </message>
       </if>
 
-      <!-- Share via QR code strings -->
+      <!-- Share via QR Code strings -->
       <if expr="not use_titlecase">
-        <message name="IDS_CONTEXT_MENU_GENERATE_QR_CODE_PAGE" desc="The label for the Create QR code for this Page context menu item.">
-          Create QR code for this page
+        <message name="IDS_CONTEXT_MENU_GENERATE_QR_CODE_PAGE" desc="The label for the Create QR Code for this Page context menu item.">
+          Create QR Code for this page
         </message>
-        <message name="IDS_CONTEXT_MENU_GENERATE_QR_CODE_IMAGE" desc="The label for the Create QR code for this Image context menu item.">
-          Create QR code for this image
+        <message name="IDS_CONTEXT_MENU_GENERATE_QR_CODE_IMAGE" desc="The label for the Create QR Code for this Image context menu item.">
+          Create QR Code for this image
         </message>
       </if>
       <if expr="use_titlecase">
-        <message name="IDS_CONTEXT_MENU_GENERATE_QR_CODE_PAGE" desc="The label for the Create QR code for this Page context menu item.">
-          Create QR code for this Page
+        <message name="IDS_CONTEXT_MENU_GENERATE_QR_CODE_PAGE" desc="The label for the Create QR Code for this Page context menu item.">
+          Create QR Code for this Page
         </message>
-        <message name="IDS_CONTEXT_MENU_GENERATE_QR_CODE_IMAGE" desc="The label for the Create QR code for this Image context menu item.">
-          Create QR code for this Image
+        <message name="IDS_CONTEXT_MENU_GENERATE_QR_CODE_IMAGE" desc="The label for the Create QR Code for this Image context menu item.">
+          Create QR Code for this Image
         </message>
       </if>
       <if expr="not is_android">
-        <message name="IDS_OMNIBOX_QRCODE_GENERATOR_ICON_LABEL" desc="String for the omnibox icon label for the QR code Generator">
-          QR code
+        <message name="IDS_OMNIBOX_QRCODE_GENERATOR_ICON_LABEL" desc="String for the omnibox icon label for the QR Code Generator">
+          QR Code
         </message>
-        <message name="IDS_OMNIBOX_QRCODE_GENERATOR_ICON_TOOLTIP" desc="Tooltip for the omnibox icon label for the QR code Generator">
-          Create QR code for this Page
+        <message name="IDS_OMNIBOX_QRCODE_GENERATOR_ICON_TOOLTIP" desc="Tooltip for the omnibox icon label for the QR Code Generator">
+          Create QR Code for this Page
         </message>
       </if>
       <message name="IDS_BROWSER_SHARING_QR_CODE_DIALOG_TITLE"
           desc="Title for the QR Generator dialog.">
-        Scan QR code
+        Scan QR Code
       </message>
       <message name="IDS_BROWSER_SHARING_QR_CODE_DIALOG_URL_TEXTFIELD_ACCESSIBLE_NAME"
-          desc="Text to be spoken for the QR code Generator's URL Textfield.">
+          desc="Text to be spoken for the QR Code Generator's URL Textfield.">
         URL
       </message>
       <message name="IDS_BROWSER_SHARING_QR_CODE_DIALOG_TOOLTIP"
           desc="Tooltip string for QR Generator dialog informing the user they
-          can scan a QR code with their phone.">
+          can scan a QR Code with their phone.">
         To scan this code, you can use a QR scanner app on your phone, or some camera apps.
       </message>
       <message name="IDS_BROWSER_SHARING_QR_CODE_DIALOG_DOWNLOAD_BUTTON_LABEL"
-          desc="Button text for the QR code generator's download button.">
+          desc="Button text for the QR Code generator's download button.">
         Download
       </message>
       <message name="IDS_BROWSER_SHARING_QR_CODE_DIALOG_ERROR_TOO_LONG"
-          desc="Error message displayed when a URL exceeds the limit for which we can generate a QR code.">
+          desc="Error message displayed when a URL exceeds the limit for which we can generate a QR Code.">
         Use <ph name="CHARACTER_LIMIT">$1<ex>300</ex></ph> characters or fewer
       </message>
       <message name="IDS_BROWSER_SHARING_QR_CODE_DIALOG_ERROR_UNKNOWN"
           desc="Error message displayed when an unknown error occurs.">
-          Can't create QR code
+          Can't create QR Code
       </message>
 
       <!-- Sharing Hub feature strings. -->
@@ -11108,11 +11108,11 @@
       <message name="IDS_WEBAUTHN_CABLE_V2_ACTIVATE_DESCRIPTION_SHORT" desc="Second line of text in an item letting the user know how they can use Chrome on their Android phone as a security key. The substring 'Use phone as a security key' refers to the string IDS_PHONE_AS_SECURITY_KEY_TEXT in Chrome on Android.">
         Open Chrome on your Android phone, and go to "Settings > Passwords > Use phone as a security key", and follow the instructions there.
       </message>
-      <message name="IDS_WEBAUTHN_CABLE_QR_TITLE" desc="Title of a dialog that contains a QR-code for the user to scan with a mobile phone app. A QR code is a type of barcode that can be read using a smartphone's camera.">
+      <message name="IDS_WEBAUTHN_CABLE_QR_TITLE" desc="Title of a dialog that contains a QR-code for the user to scan with a mobile phone app. A QR Code is a type of barcode that can be read using a smartphone's camera.">
         Add new phone
       </message>
-      <message name="IDS_WEBAUTHN_CABLE_QR_DESCRIPTION" desc="Description text in a dialog that contains a QR-code for the user to scan with Chrome on their Android phone. A QR code is a type of barcode that can be read using a smartphone's camera. The substring 'Use phone as a security key' refers to the string IDS_PHONE_AS_SECURITY_KEY_TEXT in Chrome on Android.">
-        To set up an Android phone to be used as a security key with this computer for the first time, open Chrome on your phone and go to "Settings > Passwords > Use phone as a security key". Then tap "Connect new device" and scan this QR code.
+      <message name="IDS_WEBAUTHN_CABLE_QR_DESCRIPTION" desc="Description text in a dialog that contains a QR-code for the user to scan with Chrome on their Android phone. A QR Code is a type of barcode that can be read using a smartphone's camera. The substring 'Use phone as a security key' refers to the string IDS_PHONE_AS_SECURITY_KEY_TEXT in Chrome on Android.">
+        To set up an Android phone to be used as a security key with this computer for the first time, open Chrome on your phone and go to "Settings > Passwords > Use phone as a security key". Then tap "Connect new device" and scan this QR Code.
       </message>
 
       <!-- WebAuthn authenticator PIN entry/setup -->
@@ -11447,8 +11447,22 @@
       Google Drive
     </message>
 
+    <!-- Enterprise file system connector sign in from settings page confirmation dialog -->
+    <message name="IDS_FILE_SYSTEM_CONNECTOR_SIGNIN_CONFIRM_TITLE" desc="Title shown in modal shown upon clicking sign in for downloads connection on settings page, before sign in dialog">
+      Storing <ph name="WEB_DRIVE">$1<ex>Google Drive</ex></ph> Authentication Token
+    </message>
+    <message name="IDS_FILE_SYSTEM_CONNECTOR_SIGNIN_CONFIRM_MESSAGE" desc="Meesage shown in above-mentioned modal">
+      Upon signing in, an unique authentication token will be stored and used for all future eligible downloads.
+    </message>
+    <message name="IDS_FILE_SYSTEM_CONNECTOR_SIGNIN_CONFIRM_CANCEL_BUTTON" desc="Text displayed for cancel button in above-mentioned modal">
+      Cancel
+    </message>
+    <message name="IDS_FILE_SYSTEM_CONNECTOR_SIGNIN_CONFIRM_ACCEPT_BUTTON" desc="Text displayed for accept button in above-mentioned modal">
+      Continue
+    </message>
+
     <!-- Enterprise file system connector sign in on first download confirmation dialog -->
-    <message name="IDS_FILE_SYSTEM_CONNECTOR_SIGNIN_REQUIRED_TITLE" desc="Title shown in modal shown upon first eligible download to be uploaded, before sign in dia;pg">
+    <message name="IDS_FILE_SYSTEM_CONNECTOR_SIGNIN_REQUIRED_TITLE" desc="Title shown in modal shown upon first eligible download to be uploaded, before sign in dialog">
       Sign into <ph name="WEB_DRIVE">$1<ex>Google Drive</ex></ph> to complete download
     </message>
     <message name="IDS_FILE_SYSTEM_CONNECTOR_SIGNIN_REQUIRED_MESSAGE" desc="Meesage shown in above-mentioned modal">
diff --git a/chrome/app/generated_resources_grd/IDS_FILE_SYSTEM_CONNECTOR_SIGNIN_CONFIRM_ACCEPT_BUTTON.png.sha1 b/chrome/app/generated_resources_grd/IDS_FILE_SYSTEM_CONNECTOR_SIGNIN_CONFIRM_ACCEPT_BUTTON.png.sha1
new file mode 100644
index 0000000..6694cc6
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_FILE_SYSTEM_CONNECTOR_SIGNIN_CONFIRM_ACCEPT_BUTTON.png.sha1
@@ -0,0 +1 @@
+ddbfb34d99edde499e6e6938e3a6791d9b91722f
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_FILE_SYSTEM_CONNECTOR_SIGNIN_CONFIRM_CANCEL_BUTTON.png.sha1 b/chrome/app/generated_resources_grd/IDS_FILE_SYSTEM_CONNECTOR_SIGNIN_CONFIRM_CANCEL_BUTTON.png.sha1
new file mode 100644
index 0000000..6694cc6
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_FILE_SYSTEM_CONNECTOR_SIGNIN_CONFIRM_CANCEL_BUTTON.png.sha1
@@ -0,0 +1 @@
+ddbfb34d99edde499e6e6938e3a6791d9b91722f
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_FILE_SYSTEM_CONNECTOR_SIGNIN_CONFIRM_MESSAGE.png.sha1 b/chrome/app/generated_resources_grd/IDS_FILE_SYSTEM_CONNECTOR_SIGNIN_CONFIRM_MESSAGE.png.sha1
new file mode 100644
index 0000000..6694cc6
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_FILE_SYSTEM_CONNECTOR_SIGNIN_CONFIRM_MESSAGE.png.sha1
@@ -0,0 +1 @@
+ddbfb34d99edde499e6e6938e3a6791d9b91722f
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_FILE_SYSTEM_CONNECTOR_SIGNIN_CONFIRM_TITLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_FILE_SYSTEM_CONNECTOR_SIGNIN_CONFIRM_TITLE.png.sha1
new file mode 100644
index 0000000..6694cc6
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_FILE_SYSTEM_CONNECTOR_SIGNIN_CONFIRM_TITLE.png.sha1
@@ -0,0 +1 @@
+ddbfb34d99edde499e6e6938e3a6791d9b91722f
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp
index a6131db..246b273 100644
--- a/chrome/app/os_settings_strings.grdp
+++ b/chrome/app/os_settings_strings.grdp
@@ -409,7 +409,7 @@
     Spelling and grammar check
   </message>
   <message name="IDS_OS_SETTINGS_LANGUAGES_SPELL_AND_GRAMMAR_CHECK_DESCRIPTION" desc="Description for the spell and grammar check section.">
-    Grammar check currently avaiable for English only
+    Grammar check currently available for English only
   </message>
   <message name="IDS_OS_SETTINGS_LANGUAGES_SPELL_CHECK_ENHANCED_LABEL" desc="Label for enhanced spell check toggle, the type of spell check that sends the text the user types to Google spelling service. It is important that it is communicated that the text the user types will be sent to Google.">
     Enhanced spell check in Chrome browser (text is sent to Google for spelling suggestions)
@@ -803,6 +803,18 @@
   <message name="IDS_SETTINGS_DARK_MODE_SCHEDULE_SUNSET_TO_SUNRISE" desc="The label of the option to set the automatic schedule of the Dark Mode feature to turn on at sunset and off at sunrise.">
     Sunset to sunrise
   </message>
+  <message name="IDS_SETTINGS_DARK_MODE_SUBLABEL_SUNSET_TO_SUNRISE_OFF" desc="The sub label for row in personalization settings page that indicates that dark mode is off and will be automatically turned on at sunset.">
+    Off / Will turn on automatically at sunset
+  </message>
+  <message name="IDS_SETTINGS_DARK_MODE_SUBLABEL_SUNSET_TO_SUNRISE_ON" desc="The sub label for row in personalization settings page that indicates that dark mode is on and will be automatically turned off at sunrise.">
+    On / Will turn off automatically at sunrise
+  </message>
+  <message name="IDS_SETTINGS_DARK_MODE_SUBLABEL_CUSTOM_OFF" desc="The sub label for row in personalization settings page that indicates that dark mode is off and will be automatically turned on at the user's custom start time.">
+    Off / Will turn on automatically at <ph name="TIME">$1<ex>6:30 PM</ex></ph>
+  </message>
+  <message name="IDS_SETTINGS_DARK_MODE_SUBLABEL_CUSTOM_ON" desc="The sub label for row in personalization settings page that indicates dark mode is on and will be automatically turned off at the user's custom end time.">
+    On / Will turn off automatically at <ph name="TIME">$1<ex>10:45 AM</ex></ph>
+  </message>
 
   <!-- Search and Assistant section. -->
   <message name="IDS_OS_SETTINGS_SEARCH_ENGINE_LABEL" desc="Label in OS settings describing search engine behavior.">
@@ -2813,8 +2825,8 @@
   <message name="IDS_SETTINGS_INTERNET_TETHER_NOT_SETUP_WITH_LEARN_MORE_LINK" desc="Text shown when viewing the Mobile data page and no instant tether network is available">
     No device detected. <ph name="BEGIN_LINK">&lt;a target="_blank" href="$1"&gt;</ph>Learn more<ph name="END_LINK">&lt;/a&gt;</ph>
   </message>
-  <message name="IDS_SETTINGS_INTERNET_SHOW_EID_POPUP_BUTTON_LABEL" desc="A11y and tooltop label for EID and QR code popup show button when viewing cellular network list">
-    Show device EID and QR code popup
+  <message name="IDS_SETTINGS_INTERNET_SHOW_EID_POPUP_BUTTON_LABEL" desc="A11y and tooltop label for EID and QR Code popup show button when viewing cellular network list">
+    Show device EID and QR Code popup
   </message>
   <message name="IDS_SETTINGS_INTERNET_ESIM_NO_CONNECTION_ERROR_TOAST" desc="Message in toast displayed when user tries to perform an eSIM operation when not connected to a non-cellular network.">
     Connect to Wi-Fi or Ethernet to set up eSIM
diff --git a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_LANGUAGES_SPELL_AND_GRAMMAR_CHECK_DESCRIPTION.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_LANGUAGES_SPELL_AND_GRAMMAR_CHECK_DESCRIPTION.png.sha1
index d82ea3e..8982c8e2 100644
--- a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_LANGUAGES_SPELL_AND_GRAMMAR_CHECK_DESCRIPTION.png.sha1
+++ b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_LANGUAGES_SPELL_AND_GRAMMAR_CHECK_DESCRIPTION.png.sha1
@@ -1 +1 @@
-a5ace9187cf3c524e7e72add4989ea00d06492f1
\ No newline at end of file
+09c88a00ee247759defb73c4dfd9633277f1060b
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_DARK_MODE_SUBLABEL_CUSTOM_OFF.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_DARK_MODE_SUBLABEL_CUSTOM_OFF.png.sha1
new file mode 100644
index 0000000..1807bbe
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_DARK_MODE_SUBLABEL_CUSTOM_OFF.png.sha1
@@ -0,0 +1 @@
+97377ead2268e024d24fce7cedaa09bdaaef1832
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_DARK_MODE_SUBLABEL_CUSTOM_ON.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_DARK_MODE_SUBLABEL_CUSTOM_ON.png.sha1
new file mode 100644
index 0000000..7ed6ba6c
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_DARK_MODE_SUBLABEL_CUSTOM_ON.png.sha1
@@ -0,0 +1 @@
+ab0dbfb7d7d5a436451d128c8dc2c26e195ce766
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_DARK_MODE_SUBLABEL_SUNSET_TO_SUNRISE_OFF.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_DARK_MODE_SUBLABEL_SUNSET_TO_SUNRISE_OFF.png.sha1
new file mode 100644
index 0000000..dff916f
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_DARK_MODE_SUBLABEL_SUNSET_TO_SUNRISE_OFF.png.sha1
@@ -0,0 +1 @@
+139da95f86c005a23cba376b14035d09f6e4189a
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_DARK_MODE_SUBLABEL_SUNSET_TO_SUNRISE_ON.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_DARK_MODE_SUBLABEL_SUNSET_TO_SUNRISE_ON.png.sha1
new file mode 100644
index 0000000..313e399
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_DARK_MODE_SUBLABEL_SUNSET_TO_SUNRISE_ON.png.sha1
@@ -0,0 +1 @@
+d924650530687c43c77b5fc180fc365bd777253e
\ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index b2a3ffe..96fb7493 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -440,59 +440,42 @@
 #endif  // OS_ANDROID
 
 #if defined(OS_ANDROID)
+const FeatureEntry::FeatureParam kAdaptiveButton_AlwaysNone[] = {
+    {"mode", "always-none"}};
+const FeatureEntry::FeatureParam kAdaptiveButton_AlwaysNewTab[] = {
+    {"mode", "always-new-tab"}};
+const FeatureEntry::FeatureParam kAdaptiveButton_AlwaysShare[] = {
+    {"mode", "always-share"}};
+const FeatureEntry::FeatureParam kAdaptiveButton_AlwaysVoice[] = {
+    {"mode", "always-voice"}};
 const FeatureEntry::FeatureVariation kAdaptiveButtonInTopToolbarVariations[] = {
-    {
-        "Always None",
-        (FeatureEntry::FeatureParam[]){{"mode", "always-none"}},
-        1,
-        nullptr,
-    },
-    {
-        "Always New Tab",
-        (FeatureEntry::FeatureParam[]){{"mode", "always-new-tab"}},
-        1,
-        nullptr,
-    },
-    {
-        "Always Share",
-        (FeatureEntry::FeatureParam[]){{"mode", "always-share"}},
-        1,
-        nullptr,
-    },
-    {
-        "Always Voice",
-        (FeatureEntry::FeatureParam[]){{"mode", "always-voice"}},
-        1,
-        nullptr,
-    },
+    {"Always None", kAdaptiveButton_AlwaysNone,
+     base::size(kAdaptiveButton_AlwaysNone), nullptr},
+    {"Always New Tab", kAdaptiveButton_AlwaysNewTab,
+     base::size(kAdaptiveButton_AlwaysNewTab), nullptr},
+    {"Always Share", kAdaptiveButton_AlwaysShare,
+     base::size(kAdaptiveButton_AlwaysShare), nullptr},
+    {"Always Voice", kAdaptiveButton_AlwaysVoice,
+     base::size(kAdaptiveButton_AlwaysVoice), nullptr},
 };
 
+const FeatureEntry::FeatureParam kAdaptiveButtonCustomization_NewTab[] = {
+    {"default_segment", "new-tab"},
+    {"ignore_segmentation_results", "true"}};
+const FeatureEntry::FeatureParam kAdaptiveButtonCustomization_Share[] = {
+    {"default_segment", "share"},
+    {"ignore_segmentation_results", "true"}};
+const FeatureEntry::FeatureParam kAdaptiveButtonCustomization_Voice[] = {
+    {"default_segment", "voice"},
+    {"ignore_segmentation_results", "true"}};
 const FeatureEntry::FeatureVariation
     kAdaptiveButtonInTopToolbarCustomizationVariations[] = {
-        {
-            "New Tab",
-            (FeatureEntry::FeatureParam[]){
-                {"default_segment", "new-tab"},
-                {"ignore_segmentation_results", "true"}},
-            1,
-            nullptr,
-        },
-        {
-            "Share",
-            (FeatureEntry::FeatureParam[]){
-                {"default_segment", "share"},
-                {"ignore_segmentation_results", "true"}},
-            1,
-            nullptr,
-        },
-        {
-            "Voice",
-            (FeatureEntry::FeatureParam[]){
-                {"default_segment", "voice"},
-                {"ignore_segmentation_results", "true"}},
-            1,
-            nullptr,
-        },
+        {"New Tab", kAdaptiveButtonCustomization_NewTab,
+         base::size(kAdaptiveButtonCustomization_NewTab), nullptr},
+        {"Share", kAdaptiveButtonCustomization_Share,
+         base::size(kAdaptiveButtonCustomization_Share), nullptr},
+        {"Voice", kAdaptiveButtonCustomization_Voice,
+         base::size(kAdaptiveButtonCustomization_Voice), nullptr},
 };
 #endif  // OS_ANDROID
 
@@ -1523,12 +1506,47 @@
         {features::kTabHoverCardImagesNotReadyDelayParameterName, "800"},
         {features::kTabHoverCardImagesLoadingDelayParameterName, "300"},
         {features::kTabHoverCardImagesLoadedDelayParameterName, "300"}};
+const FeatureEntry::FeatureParam
+    kTabHoverCardImagesImmediatePlaceholderCrossfade[] = {
+        {features::kTabHoverCardImagesNotReadyDelayParameterName, "500"},
+        {features::kTabHoverCardImagesLoadingDelayParameterName, "100"},
+        {features::kTabHoverCardImagesLoadedDelayParameterName, "0"},
+        {features::kTabHoverCardImagesCrossfadePreviewAtParameterName, "0.0"}};
+const FeatureEntry::FeatureParam
+    kTabHoverCardImagesEarlySlidePlaceholderCrossfade[] = {
+        {features::kTabHoverCardImagesNotReadyDelayParameterName, "500"},
+        {features::kTabHoverCardImagesLoadingDelayParameterName, "100"},
+        {features::kTabHoverCardImagesLoadedDelayParameterName, "0"},
+        {features::kTabHoverCardImagesCrossfadePreviewAtParameterName, "0.25"}};
+const FeatureEntry::FeatureParam
+    kTabHoverCardImagesMidSlidePlaceholderCrossfade[] = {
+        {features::kTabHoverCardImagesNotReadyDelayParameterName, "500"},
+        {features::kTabHoverCardImagesLoadingDelayParameterName, "100"},
+        {features::kTabHoverCardImagesLoadedDelayParameterName, "0"},
+        {features::kTabHoverCardImagesCrossfadePreviewAtParameterName, "0.5"}};
+const FeatureEntry::FeatureParam kTabHoverCardImagesLatePlaceholderCrossfade[] =
+    {{features::kTabHoverCardImagesNotReadyDelayParameterName, "500"},
+     {features::kTabHoverCardImagesLoadingDelayParameterName, "100"},
+     {features::kTabHoverCardImagesLoadedDelayParameterName, "0"},
+     {features::kTabHoverCardImagesCrossfadePreviewAtParameterName, "1.0"}};
 
 const FeatureEntry::FeatureVariation kTabHoverCardImagesVariations[] = {
     {" capture speed", kTabHoverCardImagesOptimizationCaptureSpeed,
      base::size(kTabHoverCardImagesOptimizationCaptureSpeed), nullptr},
     {" resource usage", kTabHoverCardImagesOptimizationResourceUsage,
-     base::size(kTabHoverCardImagesOptimizationResourceUsage), nullptr}};
+     base::size(kTabHoverCardImagesOptimizationResourceUsage), nullptr},
+    {" immediate placeholder crossfade",
+     kTabHoverCardImagesImmediatePlaceholderCrossfade,
+     base::size(kTabHoverCardImagesImmediatePlaceholderCrossfade), nullptr},
+    {" early-transition placeholder crossfade",
+     kTabHoverCardImagesEarlySlidePlaceholderCrossfade,
+     base::size(kTabHoverCardImagesEarlySlidePlaceholderCrossfade), nullptr},
+    {" mid-transition placeholder crossfade",
+     kTabHoverCardImagesMidSlidePlaceholderCrossfade,
+     base::size(kTabHoverCardImagesMidSlidePlaceholderCrossfade), nullptr},
+    {" placeholder crossfade on land",
+     kTabHoverCardImagesLatePlaceholderCrossfade,
+     base::size(kTabHoverCardImagesImmediatePlaceholderCrossfade), nullptr}};
 
 const FeatureEntry::FeatureParam kPromoBrowserCommandUnknownCommandParam[] = {
     {features::kPromoBrowserCommandIdParam, "0"}};
@@ -2170,9 +2188,9 @@
       base::size(kRequestDesktopSiteForTablets1920), nullptr}};
 #endif  // OS_ANDROID
 
+#if defined(OS_ANDROID)
 const FeatureEntry::FeatureVariation
     kOmniboxOnDeviceHeadSuggestNonIncognitoExperimentVariations[] = {
-#if defined(OS_ANDROID)
         {
             "relevance-1000",
             (FeatureEntry::FeatureParam[]){
@@ -2195,23 +2213,6 @@
             3,
             nullptr,
         }};
-#else   // !defined(OS_ANDROID)
-        {
-            "model-500k-queries",
-            (FeatureEntry::FeatureParam[]){
-                {OmniboxFieldTrial::kOnDeviceHeadModelLocaleConstraint,
-                 "500000"}},
-            1,
-            nullptr,
-        },
-        {
-            "model-1m-queries",
-            (FeatureEntry::FeatureParam[]){
-                {OmniboxFieldTrial::kOnDeviceHeadModelLocaleConstraint,
-                 "1000000"}},
-            1,
-            nullptr,
-        }};
 #endif  // defined(OS_ANDROID)
 
 const FeatureEntry::FeatureParam
@@ -4323,6 +4324,7 @@
      flag_descriptions::kOmniboxOnDeviceHeadSuggestionsIncognitoDescription,
      kOsAll, FEATURE_VALUE_TYPE(omnibox::kOnDeviceHeadProviderIncognito)},
 
+#if defined(OS_ANDROID)
     {"omnibox-on-device-head-suggestions-non-incognito",
      flag_descriptions::kOmniboxOnDeviceHeadSuggestionsNonIncognitoName,
      flag_descriptions::kOmniboxOnDeviceHeadSuggestionsNonIncognitoDescription,
@@ -4330,12 +4332,8 @@
      FEATURE_WITH_PARAMS_VALUE_TYPE(
          omnibox::kOnDeviceHeadProviderNonIncognito,
          kOmniboxOnDeviceHeadSuggestNonIncognitoExperimentVariations,
-#if defined(OS_ANDROID)
-         "OmniboxOnDeviceHeadNonIncognitoTuningMobile"
-#else   // !defined(OS_ANDROID)
-         "OmniboxOnDeviceHeadSuggestBigModel"
+         "OmniboxOnDeviceHeadNonIncognitoTuningMobile")},
 #endif  // defined(OS_ANDROID)
-         )},
 
     {"omnibox-on-focus-suggestions-contextual-web",
      flag_descriptions::kOmniboxOnFocusSuggestionsContextualWebName,
@@ -7389,6 +7387,13 @@
      flag_descriptions::kClipboardCustomFormatsDescription, kOsAll,
      FEATURE_VALUE_TYPE(blink::features::kClipboardCustomFormats)},
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+    {"performant-split-view-resizing",
+     flag_descriptions::kPerformantSplitViewResizing,
+     flag_descriptions::kPerformantSplitViewResizingDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(ash::features::kPerformantSplitViewResizing)},
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
     {"privacy-review", flag_descriptions::kPrivacyReviewName,
      flag_descriptions::kPrivacyReviewDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(features::kPrivacyReview)},
diff --git a/chrome/browser/ash/accessibility/select_to_speak_browsertest.cc b/chrome/browser/ash/accessibility/select_to_speak_browsertest.cc
index c092718..8a574e0 100644
--- a/chrome/browser/ash/accessibility/select_to_speak_browsertest.cc
+++ b/chrome/browser/ash/accessibility/select_to_speak_browsertest.cc
@@ -349,7 +349,15 @@
   sm_.Replay();
 }
 
-IN_PROC_BROWSER_TEST_F(SelectToSpeakTest, SmoothlyReadsAcrossFormattedText) {
+// TODO(crbug.com/1225388): Flaky on ChromeOS MSAN bots
+#if defined(OS_CHROMEOS) && defined(MEMORY_SANITIZER)
+#define MAYBE_SmoothlyReadsAcrossFormattedText \
+  DISABLED_SmoothlyReadsAcrossFormattedText
+#else
+#define MAYBE_SmoothlyReadsAcrossFormattedText SmoothlyReadsAcrossFormattedText
+#endif
+IN_PROC_BROWSER_TEST_F(SelectToSpeakTest,
+                       MAYBE_SmoothlyReadsAcrossFormattedText) {
   // Bold or formatted text
   ActivateSelectToSpeakInWindowBounds(
       "data:text/html;charset=utf-8,<p>This is some text <b>with a node"
diff --git a/chrome/browser/ash/account_manager/account_manager_facade_factory_ash.cc b/chrome/browser/ash/account_manager/account_manager_facade_factory_ash.cc
index ebd75aa..739e091 100644
--- a/chrome/browser/ash/account_manager/account_manager_facade_factory_ash.cc
+++ b/chrome/browser/ash/account_manager/account_manager_facade_factory_ash.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/browser_process_platform_part_chromeos.h"
 #include "components/account_manager_core/account_manager_facade_impl.h"
 #include "components/account_manager_core/chromeos/account_manager.h"
+#include "components/account_manager_core/chromeos/account_manager_ash.h"
 
 namespace {
 
diff --git a/chrome/browser/ash/account_manager/account_manager_policy_controller_browsertest.cc b/chrome/browser/ash/account_manager/account_manager_policy_controller_browsertest.cc
index b0b09a0..c191204b 100644
--- a/chrome/browser/ash/account_manager/account_manager_policy_controller_browsertest.cc
+++ b/chrome/browser/ash/account_manager/account_manager_policy_controller_browsertest.cc
@@ -17,7 +17,9 @@
 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/testing_profile.h"
+#include "components/account_manager_core/account.h"
 #include "components/account_manager_core/account_manager_facade.h"
+#include "components/account_manager_core/chromeos/account_manager.h"
 #include "components/account_manager_core/pref_names.h"
 #include "components/signin/public/identity_manager/consent_level.h"
 #include "components/user_manager/scoped_user_manager.h"
diff --git a/chrome/browser/ash/account_manager/account_manager_ui_impl.h b/chrome/browser/ash/account_manager/account_manager_ui_impl.h
index 9b8b961b..cf881d12 100644
--- a/chrome/browser/ash/account_manager/account_manager_ui_impl.h
+++ b/chrome/browser/ash/account_manager/account_manager_ui_impl.h
@@ -5,12 +5,12 @@
 #ifndef CHROME_BROWSER_ASH_ACCOUNT_MANAGER_ACCOUNT_MANAGER_UI_IMPL_H_
 #define CHROME_BROWSER_ASH_ACCOUNT_MANAGER_ACCOUNT_MANAGER_UI_IMPL_H_
 
-#include "ash/components/account_manager/account_manager_ui.h"
 #include "base/callback_forward.h"
+#include "components/account_manager_core/chromeos/account_manager_ui.h"
 
 namespace ash {
 
-class AccountManagerUIImpl : public AccountManagerUI {
+class AccountManagerUIImpl : public account_manager::AccountManagerUI {
  public:
   AccountManagerUIImpl();
   AccountManagerUIImpl(const AccountManagerUIImpl&) = delete;
diff --git a/chrome/browser/ash/account_manager/account_manager_util.cc b/chrome/browser/ash/account_manager/account_manager_util.cc
index cd710bf..beaa796 100644
--- a/chrome/browser/ash/account_manager/account_manager_util.cc
+++ b/chrome/browser/ash/account_manager/account_manager_util.cc
@@ -6,7 +6,6 @@
 
 #include <utility>
 
-#include "ash/components/account_manager/account_manager_ash.h"
 #include "ash/components/account_manager/account_manager_factory.h"
 #include "chrome/browser/ash/account_manager/account_manager_ui_impl.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
@@ -17,6 +16,8 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profiles_state.h"
 #include "components/account_manager_core/chromeos/account_manager.h"
+#include "components/account_manager_core/chromeos/account_manager_ash.h"
+#include "components/account_manager_core/chromeos/account_manager_ui.h"
 #include "components/user_manager/user_manager.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
diff --git a/chrome/browser/ash/crosapi/crosapi_ash.cc b/chrome/browser/ash/crosapi/crosapi_ash.cc
index bff0f895fd..270e8fa7 100644
--- a/chrome/browser/ash/crosapi/crosapi_ash.cc
+++ b/chrome/browser/ash/crosapi/crosapi_ash.cc
@@ -8,7 +8,6 @@
 #include <utility>
 #include <vector>
 
-#include "ash/components/account_manager/account_manager_ash.h"
 #include "ash/components/account_manager/account_manager_factory.h"
 #include "base/dcheck_is_on.h"
 #include "chrome/browser/apps/app_service/publishers/standalone_browser_extension_apps.h"
@@ -68,6 +67,7 @@
 #include "chromeos/services/machine_learning/public/cpp/service_connection.h"
 #include "chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom.h"
 #include "components/account_manager_core/chromeos/account_manager.h"
+#include "components/account_manager_core/chromeos/account_manager_ash.h"
 #include "components/user_manager/user_manager.h"
 #include "content/public/browser/device_service.h"
 #include "content/public/browser/media_session_service.h"
diff --git a/chrome/browser/ash/login/signin/signin_error_notifier_ash.cc b/chrome/browser/ash/login/signin/signin_error_notifier_ash.cc
index b7dfccfc..fc80dfb 100644
--- a/chrome/browser/ash/login/signin/signin_error_notifier_ash.cc
+++ b/chrome/browser/ash/login/signin/signin_error_notifier_ash.cc
@@ -40,6 +40,8 @@
 #include "chrome/grit/theme_resources.h"
 #include "chromeos/ui/vector_icons/vector_icons.h"
 #include "components/account_id/account_id.h"
+#include "components/account_manager_core/account.h"
+#include "components/account_manager_core/chromeos/account_manager.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/public/identity_manager/consent_level.h"
diff --git a/chrome/browser/ash/ownership/owner_settings_service_ash.cc b/chrome/browser/ash/ownership/owner_settings_service_ash.cc
index 272b4a8..564d5be 100644
--- a/chrome/browser/ash/ownership/owner_settings_service_ash.cc
+++ b/chrome/browser/ash/ownership/owner_settings_service_ash.cc
@@ -662,6 +662,8 @@
     //   kReportDeviceLocation
     //   kReportDeviceMemoryInfo
     //   kReportDeviceNetworkInterfaces
+    //   kReportDeviceNetworkConfiguration
+    //   kReportDeviceNetworkStatus
     //   kReportDevicePowerStatus
     //   kReportDeviceStorageStatus
     //   kReportDeviceSessionStatus
diff --git a/chrome/browser/ash/policy/core/device_policy_decoder_chromeos.cc b/chrome/browser/ash/policy/core/device_policy_decoder_chromeos.cc
index f0e19ad2..0322c4ff 100644
--- a/chrome/browser/ash/policy/core/device_policy_decoder_chromeos.cc
+++ b/chrome/browser/ash/policy/core/device_policy_decoder_chromeos.cc
@@ -718,6 +718,19 @@
                     base::Value(container.report_network_interfaces()),
                     nullptr);
     }
+    if (container.has_report_network_configuration()) {
+      policies->Set(key::kReportDeviceNetworkConfiguration,
+                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
+                    POLICY_SOURCE_CLOUD,
+                    base::Value(container.has_report_network_configuration()),
+                    nullptr);
+    }
+    if (container.has_report_network_status()) {
+      policies->Set(key::kReportDeviceNetworkStatus, POLICY_LEVEL_MANDATORY,
+                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
+                    base::Value(container.has_report_network_status()),
+                    nullptr);
+    }
     if (container.has_report_users()) {
       policies->Set(key::kReportDeviceUsers, POLICY_LEVEL_MANDATORY,
                     POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
diff --git a/chrome/browser/ash/policy/core/device_policy_decoder_chromeos_unittest.cc b/chrome/browser/ash/policy/core/device_policy_decoder_chromeos_unittest.cc
index 0b238223..9949d9a7 100644
--- a/chrome/browser/ash/policy/core/device_policy_decoder_chromeos_unittest.cc
+++ b/chrome/browser/ash/policy/core/device_policy_decoder_chromeos_unittest.cc
@@ -222,6 +222,52 @@
   EXPECT_TRUE(report_device_audio_status_bool);
 }
 
+TEST_F(DevicePolicyDecoderChromeOSTest, ReportDeviceNetworkConfiguration) {
+  PolicyBundle bundle;
+  PolicyMap& policies = bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, ""));
+
+  base::WeakPtr<ExternalDataManager> external_data_manager;
+
+  em::ChromeDeviceSettingsProto device_policy;
+  device_policy.mutable_device_reporting()->set_report_network_configuration(true);
+
+  DecodeDevicePolicy(device_policy, external_data_manager, &policies);
+
+  const base::Value* report_device_network_configuration_value =
+      policies.GetValue(key::kReportDeviceNetworkConfiguration);
+  ASSERT_NE(report_device_network_configuration_value, nullptr);
+  ASSERT_TRUE(report_device_network_configuration_value->is_bool());
+
+  bool report_device_network_configuration_bool = false;
+  report_device_network_configuration_value->GetAsBoolean(
+      &report_device_network_configuration_bool);
+
+  EXPECT_TRUE(report_device_network_configuration_bool);
+}
+
+TEST_F(DevicePolicyDecoderChromeOSTest, ReportDeviceNetworkStatus) {
+  PolicyBundle bundle;
+  PolicyMap& policies = bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, ""));
+
+  base::WeakPtr<ExternalDataManager> external_data_manager;
+
+  em::ChromeDeviceSettingsProto device_policy;
+  device_policy.mutable_device_reporting()->set_report_network_status(true);
+
+  DecodeDevicePolicy(device_policy, external_data_manager, &policies);
+
+  const base::Value* report_device_network_status_value =
+      policies.GetValue(key::kReportDeviceNetworkStatus);
+  ASSERT_NE(report_device_network_status_value, nullptr);
+  ASSERT_TRUE(report_device_network_status_value->is_bool());
+
+  bool report_device_network_status_bool = false;
+  report_device_network_status_value->GetAsBoolean(
+      &report_device_network_status_bool);
+
+  EXPECT_TRUE(report_device_network_status_bool);
+}
+
 TEST_F(DevicePolicyDecoderChromeOSTest, DecodeServiceUUIDListSuccess) {
   std::string error;
   absl::optional<base::Value> decoded_json = DecodeJsonStringAndNormalize(
diff --git a/chrome/browser/ash/settings/device_settings_provider.cc b/chrome/browser/ash/settings/device_settings_provider.cc
index d3b54bdf..46e5c8891 100644
--- a/chrome/browser/ash/settings/device_settings_provider.cc
+++ b/chrome/browser/ash/settings/device_settings_provider.cc
@@ -132,7 +132,9 @@
     kReportDeviceLocation,
     kReportDevicePowerStatus,
     kReportDeviceStorageStatus,
+    kReportDeviceNetworkConfiguration,
     kReportDeviceNetworkInterfaces,
+    kReportDeviceNetworkStatus,
     kReportDeviceSessionStatus,
     kReportDeviceTimezoneInfo,
     kReportDeviceGraphicsStatus,
@@ -587,11 +589,21 @@
       new_values_cache->SetBoolean(kReportDeviceCrashReportInfo,
                                    reporting_policy.report_crash_report_info());
     }
+    if (reporting_policy.has_report_network_configuration()) {
+      new_values_cache->SetBoolean(
+          kReportDeviceNetworkConfiguration,
+          reporting_policy.report_network_configuration());
+    }
     if (reporting_policy.has_report_network_interfaces()) {
       new_values_cache->SetBoolean(
           kReportDeviceNetworkInterfaces,
           reporting_policy.report_network_interfaces());
     }
+    if (reporting_policy.has_report_network_status()) {
+      new_values_cache->SetBoolean(
+          kReportDeviceNetworkStatus,
+          reporting_policy.report_network_status());
+    }
     if (reporting_policy.has_report_users()) {
       new_values_cache->SetBoolean(kReportDeviceUsers,
                                    reporting_policy.report_users());
diff --git a/chrome/browser/ash/settings/device_settings_provider_unittest.cc b/chrome/browser/ash/settings/device_settings_provider_unittest.cc
index da8a79a..032e276 100644
--- a/chrome/browser/ash/settings/device_settings_provider_unittest.cc
+++ b/chrome/browser/ash/settings/device_settings_provider_unittest.cc
@@ -94,7 +94,9 @@
     proto->set_report_audio_status(enable_reporting);
     proto->set_report_boot_mode(enable_reporting);
     proto->set_report_location(enable_reporting);
+    proto->set_report_network_configuration(enable_reporting);
     proto->set_report_network_interfaces(enable_reporting);
+    proto->set_report_network_status(enable_reporting);
     proto->set_report_users(enable_reporting);
     proto->set_report_hardware_status(enable_reporting);
     proto->set_report_session_status(enable_reporting);
@@ -176,7 +178,9 @@
         kReportDeviceBootMode,
         // Device location reporting is not currently supported.
         // kReportDeviceLocation,
+        kReportDeviceNetworkConfiguration,
         kReportDeviceNetworkInterfaces,
+        kReportDeviceNetworkStatus,
         kReportDeviceUsers,
         kReportDeviceHardwareStatus,
         kReportDevicePowerStatus,
diff --git a/chrome/browser/ash/smb_client/smb_file_system.cc b/chrome/browser/ash/smb_client/smb_file_system.cc
index 065f7fe0..8033fe58 100644
--- a/chrome/browser/ash/smb_client/smb_file_system.cc
+++ b/chrome/browser/ash/smb_client/smb_file_system.cc
@@ -4,167 +4,23 @@
 
 #include "chrome/browser/ash/smb_client/smb_file_system.h"
 
-#include <algorithm>
 #include <memory>
-#include <utility>
 
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/posix/eintr_wrapper.h"
-#include "base/task/post_task.h"
-#include "base/task/thread_pool.h"
 #include "chrome/browser/ash/file_system_provider/service.h"
-#include "chrome/browser/ash/smb_client/smb_errors.h"
 #include "chrome/browser/ash/smb_client/smb_file_system_id.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/smb_provider_client.h"
 #include "components/services/filesystem/public/mojom/types.mojom.h"
-#include "net/base/io_buffer.h"
 
 namespace ash {
-
-namespace {
-
-using file_system_provider::ProvidedFileSystemInterface;
-
-// This is a bogus data URI.
-// The Files app will attempt to download a whole image to create a thumbnail
-// any time you visit a folder. A bug (crbug.com/548050) tracks not doing that
-// for NETWORK providers. This work around is to supply an icon but make it
-// bogus so it falls back to the generic icon.
-constexpr char kUnknownImageDataUri[] = "data:image/png;base64,X";
-
-// Initial number of entries to send during read directory. This number is
-// smaller than kReadDirectoryMaxBatchSize since we want the initial page to
-// load as quickly as possible.
-constexpr uint32_t kReadDirectoryInitialBatchSize = 64;
-
-// Maximum number of entries to send at a time for read directory,
-constexpr uint32_t kReadDirectoryMaxBatchSize = 2048;
-
-// Capacity of the task queue. Represents how many operations can be in-flight
-// over D-Bus concurrently.
-constexpr size_t kTaskQueueCapacity = 2;
-
-constexpr ProvidedFileSystemInterface::MetadataFieldMask kRequestableFields =
-    ProvidedFileSystemInterface::MetadataField::METADATA_FIELD_IS_DIRECTORY |
-    ProvidedFileSystemInterface::MetadataField::METADATA_FIELD_NAME |
-    ProvidedFileSystemInterface::MetadataField::METADATA_FIELD_SIZE |
-    ProvidedFileSystemInterface::MetadataField::
-        METADATA_FIELD_MODIFICATION_TIME;
-
-bool RequestedIsDirectory(
-    ProvidedFileSystemInterface::MetadataFieldMask fields) {
-  return fields & ProvidedFileSystemInterface::MetadataField::
-                      METADATA_FIELD_IS_DIRECTORY;
-}
-
-bool RequestedName(ProvidedFileSystemInterface::MetadataFieldMask fields) {
-  return fields &
-         ProvidedFileSystemInterface::MetadataField::METADATA_FIELD_NAME;
-}
-
-bool RequestedSize(ProvidedFileSystemInterface::MetadataFieldMask fields) {
-  return fields &
-         ProvidedFileSystemInterface::MetadataField::METADATA_FIELD_SIZE;
-}
-
-bool RequestedModificationTime(
-    ProvidedFileSystemInterface::MetadataFieldMask fields) {
-  return fields & ProvidedFileSystemInterface::MetadataField::
-                      METADATA_FIELD_MODIFICATION_TIME;
-}
-
-bool RequestedThumbnail(ProvidedFileSystemInterface::MetadataFieldMask fields) {
-  return fields &
-         ProvidedFileSystemInterface::MetadataField::METADATA_FIELD_THUMBNAIL;
-}
-
-bool IsRedundantRequest(ProvidedFileSystemInterface::MetadataFieldMask fields) {
-  // If there isn't at least 1 requestable field there is no point doing a
-  // network request.
-  return (fields & kRequestableFields) == 0;
-}
-
-filesystem::mojom::FsFileType MapEntryType(bool is_directory) {
-  return is_directory ? filesystem::mojom::FsFileType::DIRECTORY
-                      : filesystem::mojom::FsFileType::REGULAR_FILE;
-}
-
-std::unique_ptr<smb_client::TempFileManager> CreateTempFileManager() {
-  return std::make_unique<smb_client::TempFileManager>();
-}
-
-void ConvertEntries(const smbprovider::DirectoryEntryListProto& entries_proto,
-                    storage::AsyncFileUtil::EntryList* out_entries) {
-  DCHECK(out_entries);
-
-  for (const smbprovider::DirectoryEntryProto& entry :
-       entries_proto.entries()) {
-    out_entries->emplace_back(base::FilePath(entry.name()),
-                              MapEntryType(entry.is_directory()));
-  }
-}
-
-}  // namespace
-
 namespace smb_client {
 
 using file_system_provider::AbortCallback;
 
 SmbFileSystem::SmbFileSystem(
     const file_system_provider::ProvidedFileSystemInfo& file_system_info)
-    : file_system_info_(file_system_info), task_queue_(kTaskQueueCapacity) {}
+    : file_system_info_(file_system_info) {}
 
 SmbFileSystem::~SmbFileSystem() {}
 
-int32_t SmbFileSystem::GetMountId() const {
-  // This is just to make unit tests pass.
-  return 4;
-}
-
-std::string SmbFileSystem::GetMountPath() const {
-  return GetSharePathFromFileSystemId(file_system_info_.file_system_id())
-      .value();
-}
-
-SmbProviderClient* SmbFileSystem::GetSmbProviderClient() const {
-  return chromeos::DBusThreadManager::Get()->GetSmbProviderClient();
-}
-
-base::WeakPtr<SmbProviderClient> SmbFileSystem::GetWeakSmbProviderClient()
-    const {
-  return GetSmbProviderClient()->AsWeakPtr();
-}
-
-void SmbFileSystem::EnqueueTask(SmbTask task, OperationId operation_id) {
-  task_queue_.AddTask(std::move(task), operation_id);
-}
-
-OperationId SmbFileSystem::EnqueueTaskAndGetOperationId(SmbTask task) {
-  OperationId operation_id = task_queue_.GetNextOperationId();
-  EnqueueTask(std::move(task), operation_id);
-  return operation_id;
-}
-
-AbortCallback SmbFileSystem::EnqueueTaskAndGetCallback(SmbTask task) {
-  OperationId operation_id = EnqueueTaskAndGetOperationId(std::move(task));
-  return CreateAbortCallback(operation_id);
-}
-
-void SmbFileSystem::Abort(OperationId operation_id) {
-  task_queue_.AbortOperation(operation_id);
-}
-
-AbortCallback SmbFileSystem::CreateAbortCallback(OperationId operation_id) {
-  return base::BindRepeating(&SmbFileSystem::Abort, AsWeakPtr(), operation_id);
-}
-
-AbortCallback SmbFileSystem::CreateAbortCallback() {
-  return base::DoNothing();
-}
-
 AbortCallback SmbFileSystem::RequestUnmount(
     storage::AsyncFileUtil::StatusCallback callback) {
   NOTREACHED();
@@ -175,45 +31,8 @@
     const base::FilePath& entry_path,
     ProvidedFileSystemInterface::MetadataFieldMask fields,
     ProvidedFileSystemInterface::GetMetadataCallback callback) {
-  if (IsRedundantRequest(fields)) {
-    return HandleSyncRedundantGetMetadata(fields, std::move(callback));
-  }
-
-  int32_t mount_id = GetMountId();
-  if (mount_id < 0 && entry_path.value() == "/") {
-    // If the mount process hasn't completed, return a dummy entry for the root
-    // directory. This is needed for the Files app to see the share has been
-    // mounted.
-    std::unique_ptr<file_system_provider::EntryMetadata> metadata =
-        std::make_unique<file_system_provider::EntryMetadata>();
-    if (RequestedIsDirectory(fields)) {
-      metadata->is_directory = std::make_unique<bool>(true);
-    }
-    if (RequestedName(fields)) {
-      metadata->name = std::make_unique<std::string>();
-    }
-    if (RequestedSize(fields)) {
-      metadata->size = std::make_unique<int64_t>(0);
-    }
-    if (RequestedModificationTime(fields)) {
-      metadata->modification_time = std::make_unique<base::Time>();
-    }
-    if (RequestedThumbnail(fields)) {
-      metadata->thumbnail = std::make_unique<std::string>(kUnknownImageDataUri);
-    }
-    // Mime types are not supported.
-    std::move(callback).Run(std::move(metadata), base::File::FILE_OK);
-    return CreateAbortCallback();
-  }
-
-  auto reply =
-      base::BindOnce(&SmbFileSystem::HandleRequestGetMetadataEntryCallback,
-                     AsWeakPtr(), fields, std::move(callback));
-  SmbTask task = base::BindOnce(&SmbProviderClient::GetMetadataEntry,
-                                GetWeakSmbProviderClient(), mount_id,
-                                entry_path, std::move(reply));
-
-  return EnqueueTaskAndGetCallback(std::move(task));
+  NOTREACHED();
+  return base::DoNothing();
 }
 
 AbortCallback SmbFileSystem::GetActions(
@@ -222,7 +41,7 @@
   const std::vector<file_system_provider::Action> actions;
   // No actions are currently supported.
   std::move(callback).Run(actions, base::File::FILE_OK);
-  return CreateAbortCallback();
+  return base::DoNothing();
 }
 
 AbortCallback SmbFileSystem::ExecuteAction(
@@ -230,52 +49,28 @@
     const std::string& action_id,
     storage::AsyncFileUtil::StatusCallback callback) {
   NOTREACHED();
-  return CreateAbortCallback();
+  return base::DoNothing();
 }
 
 AbortCallback SmbFileSystem::ReadDirectory(
     const base::FilePath& directory_path,
     storage::AsyncFileUtil::ReadDirectoryCallback callback) {
-  OperationId operation_id = task_queue_.GetNextOperationId();
-
-  StartReadDirectory(directory_path, operation_id, std::move(callback));
-
-  return CreateAbortCallback(operation_id);
+  NOTREACHED();
+  return base::DoNothing();
 }
 
 AbortCallback SmbFileSystem::OpenFile(const base::FilePath& file_path,
                                       file_system_provider::OpenFileMode mode,
                                       OpenFileCallback callback) {
-  bool writeable =
-      mode == file_system_provider::OPEN_FILE_MODE_WRITE ? true : false;
-
-  auto reply = base::BindOnce(&SmbFileSystem::HandleRequestOpenFileCallback,
-                              AsWeakPtr(), std::move(callback));
-  SmbTask task =
-      base::BindOnce(&SmbProviderClient::OpenFile, GetWeakSmbProviderClient(),
-                     GetMountId(), file_path, writeable, std::move(reply));
-
-  return EnqueueTaskAndGetCallback(std::move(task));
-}
-
-void SmbFileSystem::HandleRequestOpenFileCallback(
-    OpenFileCallback callback,
-    smbprovider::ErrorType error,
-    int32_t file_id) const {
-  task_queue_.TaskFinished();
-  std::move(callback).Run(file_id, TranslateToFileError(error));
+  NOTREACHED();
+  return base::DoNothing();
 }
 
 AbortCallback SmbFileSystem::CloseFile(
     int file_handle,
     storage::AsyncFileUtil::StatusCallback callback) {
-  auto reply = base::BindOnce(&SmbFileSystem::HandleStatusCallback, AsWeakPtr(),
-                              std::move(callback));
-  SmbTask task =
-      base::BindOnce(&SmbProviderClient::CloseFile, GetWeakSmbProviderClient(),
-                     GetMountId(), file_handle, std::move(reply));
-
-  return EnqueueTaskAndGetCallback(std::move(task));
+  NOTREACHED();
+  return base::DoNothing();
 }
 
 AbortCallback SmbFileSystem::ReadFile(int file_handle,
@@ -283,103 +78,55 @@
                                       int64_t offset,
                                       int length,
                                       ReadChunkReceivedCallback callback) {
-  auto reply =
-      base::BindOnce(&SmbFileSystem::HandleRequestReadFileCallback, AsWeakPtr(),
-                     length, scoped_refptr<net::IOBuffer>(buffer), callback);
-
-  SmbTask task = base::BindOnce(&SmbProviderClient::ReadFile,
-                                GetWeakSmbProviderClient(), GetMountId(),
-                                file_handle, offset, length, std::move(reply));
-
-  return EnqueueTaskAndGetCallback(std::move(task));
+  NOTREACHED();
+  return base::DoNothing();
 }
 
 AbortCallback SmbFileSystem::CreateDirectory(
     const base::FilePath& directory_path,
     bool recursive,
     storage::AsyncFileUtil::StatusCallback callback) {
-  auto reply = base::BindOnce(&SmbFileSystem::HandleStatusCallback, AsWeakPtr(),
-                              std::move(callback));
-
-  SmbTask task = base::BindOnce(&SmbProviderClient::CreateDirectory,
-                                GetWeakSmbProviderClient(), GetMountId(),
-                                directory_path, recursive, std::move(reply));
-
-  return EnqueueTaskAndGetCallback(std::move(task));
+  NOTREACHED();
+  return base::DoNothing();
 }
 
 AbortCallback SmbFileSystem::CreateFile(
     const base::FilePath& file_path,
     storage::AsyncFileUtil::StatusCallback callback) {
-  auto reply = base::BindOnce(&SmbFileSystem::HandleStatusCallback, AsWeakPtr(),
-                              std::move(callback));
-  SmbTask task =
-      base::BindOnce(&SmbProviderClient::CreateFile, GetWeakSmbProviderClient(),
-                     GetMountId(), file_path, std::move(reply));
-
-  return EnqueueTaskAndGetCallback(std::move(task));
+  NOTREACHED();
+  return base::DoNothing();
 }
 
 AbortCallback SmbFileSystem::DeleteEntry(
     const base::FilePath& entry_path,
     bool recursive,
     storage::AsyncFileUtil::StatusCallback callback) {
-  OperationId operation_id = task_queue_.GetNextOperationId();
-  SmbTask task;
-
-  if (recursive) {
-    auto reply = base::BindOnce(&SmbFileSystem::HandleGetDeleteListCallback,
-                                AsWeakPtr(), std::move(callback), operation_id);
-    task = base::BindOnce(&SmbProviderClient::GetDeleteList,
-                          GetWeakSmbProviderClient(), GetMountId(), entry_path,
-                          std::move(reply));
-  } else {
-    auto reply = base::BindOnce(&SmbFileSystem::HandleStatusCallback,
-                                AsWeakPtr(), std::move(callback));
-    task = base::BindOnce(&SmbProviderClient::DeleteEntry,
-                          GetWeakSmbProviderClient(), GetMountId(), entry_path,
-                          false /* recursive */, std::move(reply));
-  }
-
-  EnqueueTask(std::move(task), operation_id);
-  return CreateAbortCallback(operation_id);
+  NOTREACHED();
+  return base::DoNothing();
 }
 
 AbortCallback SmbFileSystem::CopyEntry(
     const base::FilePath& source_path,
     const base::FilePath& target_path,
     storage::AsyncFileUtil::StatusCallback callback) {
-  OperationId operation_id = task_queue_.GetNextOperationId();
-
-  StartCopy(source_path, target_path, operation_id, std::move(callback));
-
-  return CreateAbortCallback(operation_id);
+  NOTREACHED();
+  return base::DoNothing();
 }
 
 AbortCallback SmbFileSystem::MoveEntry(
     const base::FilePath& source_path,
     const base::FilePath& target_path,
     storage::AsyncFileUtil::StatusCallback callback) {
-  auto reply = base::BindOnce(&SmbFileSystem::HandleStatusCallback, AsWeakPtr(),
-                              std::move(callback));
-  SmbTask task =
-      base::BindOnce(&SmbProviderClient::MoveEntry, GetWeakSmbProviderClient(),
-                     GetMountId(), source_path, target_path, std::move(reply));
-
-  return EnqueueTaskAndGetCallback(std::move(task));
+  NOTREACHED();
+  return base::DoNothing();
 }
 
 AbortCallback SmbFileSystem::Truncate(
     const base::FilePath& file_path,
     int64_t length,
     storage::AsyncFileUtil::StatusCallback callback) {
-  auto reply = base::BindOnce(&SmbFileSystem::HandleStatusCallback, AsWeakPtr(),
-                              std::move(callback));
-  SmbTask task =
-      base::BindOnce(&SmbProviderClient::Truncate, GetWeakSmbProviderClient(),
-                     GetMountId(), file_path, length, std::move(reply));
-
-  return EnqueueTaskAndGetCallback(std::move(task));
+  NOTREACHED();
+  return base::DoNothing();
 }
 
 AbortCallback SmbFileSystem::WriteFile(
@@ -388,62 +135,8 @@
     int64_t offset,
     int length,
     storage::AsyncFileUtil::StatusCallback callback) {
-  if (length == 0) {
-    std::move(callback).Run(base::File::FILE_OK);
-    return CreateAbortCallback();
-  }
-
-  const std::vector<uint8_t> data(buffer->data(), buffer->data() + length);
-  if (!temp_file_manager_) {
-    SmbTask task = base::BindOnce(
-        base::IgnoreResult(&SmbFileSystem::CallWriteFile), AsWeakPtr(),
-        file_handle, std::move(data), offset, length, std::move(callback));
-    CreateTempFileManagerAndExecuteTask(std::move(task));
-    // The call to init temp_file_manager_ will not be abortable since it is
-    // asynchronous.
-    return CreateAbortCallback();
-  }
-
-  return CallWriteFile(file_handle, data, offset, length, std::move(callback));
-}
-
-void SmbFileSystem::CreateTempFileManagerAndExecuteTask(SmbTask task) {
-  // CreateTempFileManager() has to be called on a separate thread since it
-  // contains a call that requires a blockable thread.
-  constexpr base::TaskTraits kTaskTraits = {
-      base::MayBlock(), base::TaskPriority::USER_BLOCKING,
-      base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN};
-  auto init_task = base::BindOnce(&CreateTempFileManager);
-  auto reply = base::BindOnce(&SmbFileSystem::InitTempFileManagerAndExecuteTask,
-                              AsWeakPtr(), std::move(task));
-  base::ThreadPool::PostTaskAndReplyWithResult(
-      FROM_HERE, kTaskTraits, std::move(init_task), std::move(reply));
-}
-
-void SmbFileSystem::InitTempFileManagerAndExecuteTask(
-    SmbTask task,
-    std::unique_ptr<TempFileManager> temp_file_manager) {
-  DCHECK(!temp_file_manager_);
-  DCHECK(temp_file_manager);
-
-  temp_file_manager_ = std::move(temp_file_manager);
-  std::move(task).Run();
-}
-
-AbortCallback SmbFileSystem::CallWriteFile(
-    int file_handle,
-    const std::vector<uint8_t>& data,
-    int64_t offset,
-    int length,
-    storage::AsyncFileUtil::StatusCallback callback) {
-  base::ScopedFD temp_fd = temp_file_manager_->CreateTempFile(data);
-
-  auto reply = base::BindOnce(&SmbFileSystem::HandleStatusCallback, AsWeakPtr(),
-                              std::move(callback));
-  SmbTask task = base::BindOnce(
-      &SmbProviderClient::WriteFile, GetWeakSmbProviderClient(), GetMountId(),
-      file_handle, offset, length, std::move(temp_fd), std::move(reply));
-  return EnqueueTaskAndGetCallback(std::move(task));
+  NOTREACHED();
+  return base::DoNothing();
 }
 
 AbortCallback SmbFileSystem::AddWatcher(
@@ -456,7 +149,7 @@
   // Watchers are not supported.
   NOTREACHED();
   std::move(callback).Run(base::File::FILE_ERROR_INVALID_OPERATION);
-  return CreateAbortCallback();
+  return base::DoNothing();
 }
 
 void SmbFileSystem::RemoveWatcher(
@@ -515,384 +208,10 @@
   NOTREACHED();
 }
 
-void SmbFileSystem::StartCopy(const base::FilePath& source_path,
-                              const base::FilePath& target_path,
-                              OperationId operation_id,
-                              storage::AsyncFileUtil::StatusCallback callback) {
-  auto reply = base::BindOnce(&SmbFileSystem::HandleStartCopyCallback,
-                              AsWeakPtr(), std::move(callback), operation_id);
-  SmbTask task =
-      base::BindOnce(&SmbProviderClient::StartCopy, GetWeakSmbProviderClient(),
-                     GetMountId(), source_path, target_path, std::move(reply));
-
-  EnqueueTask(std::move(task), operation_id);
-}
-
-void SmbFileSystem::ContinueCopy(
-    OperationId operation_id,
-    int32_t copy_token,
-    storage::AsyncFileUtil::StatusCallback callback) {
-  auto reply =
-      base::BindOnce(&SmbFileSystem::HandleContinueCopyCallback, AsWeakPtr(),
-                     std::move(callback), operation_id, copy_token);
-  SmbTask task = base::BindOnce(&SmbProviderClient::ContinueCopy,
-                                GetWeakSmbProviderClient(), GetMountId(),
-                                copy_token, std::move(reply));
-
-  EnqueueTask(std::move(task), operation_id);
-}
-
-void SmbFileSystem::StartReadDirectory(
-    const base::FilePath& directory_path,
-    OperationId operation_id,
-    storage::AsyncFileUtil::ReadDirectoryCallback callback) {
-  base::ElapsedTimer metrics_timer;
-
-  auto reply = base::BindOnce(&SmbFileSystem::HandleStartReadDirectoryCallback,
-                              AsWeakPtr(), std::move(callback), operation_id,
-                              directory_path, std::move(metrics_timer));
-
-  SmbTask task = base::BindOnce(&SmbProviderClient::StartReadDirectory,
-                                GetWeakSmbProviderClient(), GetMountId(),
-                                directory_path, std::move(reply));
-
-  EnqueueTask(std::move(task), operation_id);
-}
-
-void SmbFileSystem::ContinueReadDirectory(
-    OperationId operation_id,
-    int32_t read_dir_token,
-    storage::AsyncFileUtil::ReadDirectoryCallback callback,
-    int entries_count,
-    base::ElapsedTimer metrics_timer) {
-  auto reply =
-      base::BindOnce(&SmbFileSystem::HandleContinueReadDirectoryCallback,
-                     AsWeakPtr(), std::move(callback), operation_id,
-                     read_dir_token, entries_count, std::move(metrics_timer));
-  SmbTask task = base::BindOnce(&SmbProviderClient::ContinueReadDirectory,
-                                GetWeakSmbProviderClient(), GetMountId(),
-                                read_dir_token, std::move(reply));
-
-  EnqueueTask(std::move(task), operation_id);
-}
-
-void SmbFileSystem::RequestUpdatedCredentials(base::OnceClosure reply) {
-  NOTREACHED();
-}
-
-void SmbFileSystem::RequestUpdatedSharePath(
-    SmbService::StartReadDirIfSuccessfulCallback reply) {
-  NOTREACHED();
-}
-
-void SmbFileSystem::HandleRequestReadDirectoryCallback(
-    storage::AsyncFileUtil::ReadDirectoryCallback callback,
-    const base::ElapsedTimer& metrics_timer,
-    smbprovider::ErrorType error,
-    const smbprovider::DirectoryEntryListProto& entries) const {
-  task_queue_.TaskFinished();
-  uint32_t batch_size = kReadDirectoryInitialBatchSize;
-  storage::AsyncFileUtil::EntryList entry_list;
-
-  // Loop through the entries and send when the desired batch size is hit.
-  for (const smbprovider::DirectoryEntryProto& entry : entries.entries()) {
-    entry_list.emplace_back(base::FilePath(entry.name()),
-                            MapEntryType(entry.is_directory()));
-
-    if (entry_list.size() == batch_size) {
-      callback.Run(base::File::FILE_OK, entry_list, true /* has_more */);
-      entry_list.clear();
-
-      // Double the batch size until it gets to the maximum size.
-      batch_size = std::min(batch_size * 2, kReadDirectoryMaxBatchSize);
-    }
-  }
-
-  callback.Run(TranslateToFileError(error), entry_list, false /* has_more */);
-}
-
-void SmbFileSystem::HandleGetDeleteListCallback(
-    storage::AsyncFileUtil::StatusCallback callback,
-    OperationId operation_id,
-    smbprovider::ErrorType list_error,
-    const smbprovider::DeleteListProto& delete_list) {
-  task_queue_.TaskFinished();
-  if (delete_list.entries_size() == 0) {
-    // There are no entries to delete.
-    DCHECK_NE(smbprovider::ERROR_OK, list_error);
-    std::move(callback).Run(TranslateToFileError(list_error));
-    return;
-  }
-
-  for (int i = 0; i < delete_list.entries_size(); ++i) {
-    const base::FilePath entry_path(delete_list.entries(i));
-    bool is_last_entry = (i == delete_list.entries_size() - 1);
-
-    // The `reply` callbacks will run `callback` only once, but we need to bind
-    // it into each reply callback, so we must SplitOnceCallback() to each
-    // `reply`.
-    auto split_callback = base::SplitOnceCallback(std::move(callback));
-    callback = std::move(split_callback.first);
-
-    auto reply = base::BindOnce(&SmbFileSystem::HandleDeleteEntryCallback,
-                                AsWeakPtr(), std::move(split_callback.second),
-                                list_error, is_last_entry);
-
-    SmbTask task = base::BindOnce(
-        &SmbProviderClient::DeleteEntry, GetWeakSmbProviderClient(),
-        GetMountId(), entry_path, false /* recursive */, std::move(reply));
-    EnqueueTask(std::move(task), operation_id);
-  }
-}
-
-void SmbFileSystem::HandleDeleteEntryCallback(
-    storage::AsyncFileUtil::StatusCallback callback,
-    smbprovider::ErrorType list_error,
-    bool is_last_entry,
-    smbprovider::ErrorType delete_error) const {
-  task_queue_.TaskFinished();
-  if (is_last_entry) {
-    // Only run the callback once.
-    if (list_error != smbprovider::ERROR_OK) {
-      delete_error = list_error;
-    }
-    std::move(callback).Run(TranslateToFileError(delete_error));
-  }
-}
-
-void SmbFileSystem::HandleStartCopyCallback(
-    storage::AsyncFileUtil::StatusCallback callback,
-    OperationId operation_id,
-    smbprovider::ErrorType error,
-    int32_t copy_token) {
-  task_queue_.TaskFinished();
-
-  if (error == smbprovider::ERROR_COPY_PENDING) {
-    // The copy needs to be continued.
-    DCHECK_GE(copy_token, 0);
-
-    ContinueCopy(operation_id, copy_token, std::move(callback));
-    return;
-  }
-
-  std::move(callback).Run(TranslateToFileError(error));
-}
-
-void SmbFileSystem::HandleContinueCopyCallback(
-    storage::AsyncFileUtil::StatusCallback callback,
-    OperationId operation_id,
-    int32_t copy_token,
-    smbprovider::ErrorType error) {
-  task_queue_.TaskFinished();
-
-  if (error == smbprovider::ERROR_COPY_PENDING) {
-    // The copy needs to be continued.
-    ContinueCopy(operation_id, copy_token, std::move(callback));
-    return;
-  }
-
-  std::move(callback).Run(TranslateToFileError(error));
-}
-
-void SmbFileSystem::HandleStartReadDirectoryCallback(
-    storage::AsyncFileUtil::ReadDirectoryCallback callback,
-    OperationId operation_id,
-    const base::FilePath& directory_path,
-    base::ElapsedTimer metrics_timer,
-    smbprovider::ErrorType error,
-    int32_t read_dir_token,
-    const smbprovider::DirectoryEntryListProto& entries) {
-  task_queue_.TaskFinished();
-
-  if (IsRecoverableError(error)) {
-    if (error == smbprovider::ERROR_ACCESS_DENIED) {
-      base::OnceClosure retry =
-          base::BindOnce(&SmbFileSystem::StartReadDirectory, AsWeakPtr(),
-                         directory_path, operation_id, std::move(callback));
-      // Request updated credentials for share, then retry the read directory
-      // from the start.
-      RequestUpdatedCredentials(std::move(retry));
-      return;
-    }
-
-    if (error == smbprovider::ERROR_NOT_FOUND) {
-      // Request updated share path for share, then retry the read directory
-      // from the start.
-      SmbService::StartReadDirIfSuccessfulCallback retry_start_read_dir =
-          base::BindOnce(&SmbFileSystem::RetryStartReadDir, AsWeakPtr(),
-                         directory_path, operation_id, std::move(callback));
-      RequestUpdatedSharePath(std::move(retry_start_read_dir));
-      return;
-    }
-  }
-
-  int entries_count = 0;
-  ProcessReadDirectoryResults(std::move(callback), operation_id, read_dir_token,
-                              error, entries, entries_count,
-                              std::move(metrics_timer));
-}
-
-void SmbFileSystem::HandleContinueReadDirectoryCallback(
-    storage::AsyncFileUtil::ReadDirectoryCallback callback,
-    OperationId operation_id,
-    int32_t read_dir_token,
-    int entries_count,
-    base::ElapsedTimer metrics_timer,
-    smbprovider::ErrorType error,
-    const smbprovider::DirectoryEntryListProto& entries) {
-  task_queue_.TaskFinished();
-
-  ProcessReadDirectoryResults(std::move(callback), operation_id, read_dir_token,
-                              error, entries, entries_count,
-                              std::move(metrics_timer));
-}
-
-void SmbFileSystem::ProcessReadDirectoryResults(
-    storage::AsyncFileUtil::ReadDirectoryCallback callback,
-    OperationId operation_id,
-    int32_t read_dir_token,
-    smbprovider::ErrorType error,
-    const smbprovider::DirectoryEntryListProto& entries,
-    int entries_count,
-    base::ElapsedTimer metrics_timer) {
-  storage::AsyncFileUtil::EntryList entry_list;
-
-  if (error != smbprovider::ERROR_OPERATION_PENDING &&
-      error != smbprovider::ERROR_OK) {
-    callback.Run(TranslateToFileError(error), entry_list, false /* has_more */);
-  }
-
-  ConvertEntries(entries, &entry_list);
-  entries_count += entry_list.size();
-
-  const bool has_more = (error == smbprovider::ERROR_OPERATION_PENDING);
-
-  // Run |callback| with the next batch of results;
-  callback.Run(base::File::FILE_OK, entry_list, has_more);
-
-  if (has_more) {
-    // There are more directory entries to read.
-    ContinueReadDirectory(operation_id, read_dir_token, callback, entries_count,
-                          std::move(metrics_timer));
-    return;
-  }
-}
-
-AbortCallback SmbFileSystem::HandleSyncRedundantGetMetadata(
-    ProvidedFileSystemInterface::MetadataFieldMask fields,
-    ProvidedFileSystemInterface::GetMetadataCallback callback) {
-  auto metadata = std::make_unique<file_system_provider::EntryMetadata>();
-
-  // The fields could be empty or have one or both of thumbnail and metadata.
-  // We completely ignore metadata, but populate the bogus URI for the
-  // thumbnail.
-  if (RequestedThumbnail(fields)) {
-    metadata->thumbnail = std::make_unique<std::string>(kUnknownImageDataUri);
-  }
-
-  std::move(callback).Run(std::move(metadata), base::File::FILE_OK);
-  return CreateAbortCallback();
-}
-
-void SmbFileSystem::HandleRequestGetMetadataEntryCallback(
-    ProvidedFileSystemInterface::MetadataFieldMask fields,
-    ProvidedFileSystemInterface::GetMetadataCallback callback,
-    smbprovider::ErrorType error,
-    const smbprovider::DirectoryEntryProto& entry) const {
-  task_queue_.TaskFinished();
-  if (error != smbprovider::ERROR_OK) {
-    std::move(callback).Run(nullptr, TranslateToFileError(error));
-    return;
-  }
-  std::unique_ptr<file_system_provider::EntryMetadata> metadata =
-      std::make_unique<file_system_provider::EntryMetadata>();
-  if (RequestedIsDirectory(fields)) {
-    metadata->is_directory = std::make_unique<bool>(entry.is_directory());
-  }
-  if (RequestedName(fields)) {
-    metadata->name = std::make_unique<std::string>(entry.name());
-  }
-  if (RequestedSize(fields)) {
-    metadata->size = std::make_unique<int64_t>(entry.size());
-  }
-  if (RequestedModificationTime(fields)) {
-    metadata->modification_time = std::make_unique<base::Time>(
-        base::Time::FromTimeT(entry.last_modified_time()));
-  }
-  if (RequestedThumbnail(fields)) {
-    metadata->thumbnail = std::make_unique<std::string>(kUnknownImageDataUri);
-  }
-  // Mime types are not supported.
-  std::move(callback).Run(std::move(metadata), base::File::FILE_OK);
-}
-
-void SmbFileSystem::HandleRequestReadFileCallback(
-    int32_t length,
-    scoped_refptr<net::IOBuffer> buffer,
-    ReadChunkReceivedCallback callback,
-    smbprovider::ErrorType error,
-    const base::ScopedFD& fd) const {
-  task_queue_.TaskFinished();
-
-  if (error != smbprovider::ERROR_OK) {
-    callback.Run(0 /* chunk_length */, false /* has_more */,
-                 TranslateToFileError(error));
-    return;
-  }
-
-  int32_t total_read = 0;
-  while (total_read < length) {
-    // read() may return less than the requested amount of bytes. If this
-    // happens, try to read the remaining bytes.
-    const int32_t bytes_read = HANDLE_EINTR(
-        read(fd.get(), buffer->data() + total_read, length - total_read));
-    if (bytes_read < 0) {
-      // This is an error case, return an error immediately.
-      callback.Run(0 /* chunk_length */, false /* has_more */,
-                   base::File::FILE_ERROR_IO);
-      return;
-    }
-    if (bytes_read == 0) {
-      break;
-    }
-    total_read += bytes_read;
-  }
-  callback.Run(total_read, false /* has_more */, base::File::FILE_OK);
-}
-
-void SmbFileSystem::HandleStatusCallback(
-    storage::AsyncFileUtil::StatusCallback callback,
-    smbprovider::ErrorType error) const {
-  task_queue_.TaskFinished();
-
-  std::move(callback).Run(TranslateToFileError(error));
-}
-
 base::WeakPtr<file_system_provider::ProvidedFileSystemInterface>
 SmbFileSystem::GetWeakPtr() {
   return AsWeakPtr();
 }
 
-bool SmbFileSystem::IsRecoverableError(smbprovider::ErrorType error) const {
-  return (error == smbprovider::ERROR_NOT_FOUND) ||
-         (error == smbprovider::ERROR_INVALID_OPERATION) ||
-         (error == smbprovider::ERROR_ACCESS_DENIED);
-}
-
-void SmbFileSystem::RetryStartReadDir(
-    const base::FilePath& directory_path,
-    OperationId operation_id,
-    storage::AsyncFileUtil::ReadDirectoryCallback callback,
-    bool should_retry_start_read_dir) {
-  if (should_retry_start_read_dir) {
-    StartReadDirectory(directory_path, operation_id, std::move(callback));
-  } else {
-    // Run |callback| to terminate StartReadDirectory early.
-    std::move(callback).Run(base::File::FILE_ERROR_NOT_FOUND,
-                            storage::AsyncFileUtil::EntryList(),
-                            false /* has_more */);
-  }
-}
-
 }  // namespace smb_client
 }  // namespace ash
diff --git a/chrome/browser/ash/smb_client/smb_file_system.h b/chrome/browser/ash/smb_client/smb_file_system.h
index 0f856f26..88b3d7eb 100644
--- a/chrome/browser/ash/smb_client/smb_file_system.h
+++ b/chrome/browser/ash/smb_client/smb_file_system.h
@@ -14,14 +14,11 @@
 #include "base/callback.h"
 #include "base/files/file.h"
 #include "base/memory/weak_ptr.h"
-#include "base/timer/elapsed_timer.h"
 #include "chrome/browser/ash/file_system_provider/abort_callback.h"
 #include "chrome/browser/ash/file_system_provider/provided_file_system_info.h"
 #include "chrome/browser/ash/file_system_provider/provided_file_system_interface.h"
 #include "chrome/browser/ash/file_system_provider/watcher.h"
 #include "chrome/browser/ash/smb_client/smb_service.h"
-#include "chrome/browser/ash/smb_client/smb_task_queue.h"
-#include "chrome/browser/ash/smb_client/temp_file_manager.h"
 #include "chromeos/dbus/smb_provider_client.h"
 #include "storage/browser/file_system/async_file_util.h"
 #include "storage/browser/file_system/watcher_manager.h"
@@ -169,182 +166,9 @@
   base::WeakPtr<ProvidedFileSystemInterface> GetWeakPtr() override;
 
  private:
-  void Abort(OperationId operation_id);
-
-  // Calls CreateTempFileManager() and executes |task|.
-  void CreateTempFileManagerAndExecuteTask(SmbTask task);
-
-  // Initializes |temp_file_manager_| with |temp_file_manager| and executes
-  // |task|.
-  void InitTempFileManagerAndExecuteTask(
-      SmbTask task,
-      std::unique_ptr<TempFileManager> temp_file_manager);
-
-  // Calls WriteFile in SmbProviderClient.
-  file_system_provider::AbortCallback CallWriteFile(
-      int file_handle,
-      const std::vector<uint8_t>& data,
-      int64_t offset,
-      int length,
-      storage::AsyncFileUtil::StatusCallback callback);
-
-  file_system_provider::AbortCallback CreateAbortCallback(
-      OperationId operation_id);
-
-  file_system_provider::AbortCallback CreateAbortCallback();
-
-  // Starts a copy operation to copy |source_path| to |target_path| with the
-  // OperationId |operation_id|.
-  void StartCopy(const base::FilePath& source_path,
-                 const base::FilePath& target_path,
-                 OperationId operation_id,
-                 storage::AsyncFileUtil::StatusCallback callback);
-
-  // Continues a copy corresponding to |operation_id| and |copy_token|.
-  void ContinueCopy(OperationId operation_id,
-                    int32_t copy_token,
-                    storage::AsyncFileUtil::StatusCallback callback);
-
-  // Starts a ReadDirectory operation for |directory_path| with the OperationId
-  // |operation_id|.
-  void StartReadDirectory(
-      const base::FilePath& directory_path,
-      OperationId operation_id,
-      storage::AsyncFileUtil::ReadDirectoryCallback callback);
-
-  // Continues a ReadDirectory corresponding to |operation_id| and
-  // |read_dir_token|. |entries_count| and |metrics_timer| are used for metrics
-  // recording.
-  void ContinueReadDirectory(
-      OperationId operation_id,
-      int32_t read_dir_token,
-      storage::AsyncFileUtil::ReadDirectoryCallback callback,
-      int entires_count,
-      base::ElapsedTimer metrics_timer);
-
-  // Requests updated credentials for the mount. Once the credentials have been
-  // updated, |reply| is executed.
-  void RequestUpdatedCredentials(base::OnceClosure reply);
-
-  // Requests updated share path for the mount. Once the share path have been,
-  // updated, |reply| is executed.
-  void RequestUpdatedSharePath(
-      SmbService::StartReadDirIfSuccessfulCallback reply);
-
-  void HandleRequestReadDirectoryCallback(
-      storage::AsyncFileUtil::ReadDirectoryCallback callback,
-      const base::ElapsedTimer& metrics_timer,
-      smbprovider::ErrorType error,
-      const smbprovider::DirectoryEntryListProto& entries) const;
-
-  file_system_provider::AbortCallback HandleSyncRedundantGetMetadata(
-      ProvidedFileSystemInterface::MetadataFieldMask fields,
-      ProvidedFileSystemInterface::GetMetadataCallback callback);
-
-  void HandleRequestGetMetadataEntryCallback(
-      ProvidedFileSystemInterface::MetadataFieldMask fields,
-      ProvidedFileSystemInterface::GetMetadataCallback callback,
-      smbprovider::ErrorType error,
-      const smbprovider::DirectoryEntryProto& entry) const;
-
-  void HandleRequestOpenFileCallback(OpenFileCallback callback,
-                                     smbprovider::ErrorType error,
-                                     int32_t file_id) const;
-
-  void HandleStatusCallback(storage::AsyncFileUtil::StatusCallback callback,
-                            smbprovider::ErrorType error) const;
-
-  void HandleRequestReadFileCallback(int32_t length,
-                                     scoped_refptr<net::IOBuffer> buffer,
-                                     ReadChunkReceivedCallback callback,
-                                     smbprovider::ErrorType error,
-                                     const base::ScopedFD& fd) const;
-
-  void HandleGetDeleteListCallback(
-      storage::AsyncFileUtil::StatusCallback callback,
-      OperationId operation_id,
-      smbprovider::ErrorType list_error,
-      const smbprovider::DeleteListProto& delete_list);
-
-  void HandleDeleteEntryCallback(
-      storage::AsyncFileUtil::StatusCallback callback,
-      smbprovider::ErrorType list_error,
-      bool is_last_entry,
-      smbprovider::ErrorType delete_error) const;
-
-  void HandleStartCopyCallback(storage::AsyncFileUtil::StatusCallback callback,
-                               OperationId operation_id,
-                               smbprovider::ErrorType error,
-                               int32_t copy_token);
-
-  void HandleContinueCopyCallback(
-      storage::AsyncFileUtil::StatusCallback callback,
-      OperationId operation_id,
-      int32_t copy_token,
-      smbprovider::ErrorType error);
-
-  void HandleStartReadDirectoryCallback(
-      storage::AsyncFileUtil::ReadDirectoryCallback callback,
-      OperationId operation_id,
-      const base::FilePath& directory_path,
-      base::ElapsedTimer metrics_timer,
-      smbprovider::ErrorType error,
-      int32_t read_dir_token,
-      const smbprovider::DirectoryEntryListProto& entries);
-
-  void HandleContinueReadDirectoryCallback(
-      storage::AsyncFileUtil::ReadDirectoryCallback callback,
-      OperationId operation_id,
-      int32_t read_dir_token,
-      int entries_count,
-      base::ElapsedTimer metrics_timer,
-      smbprovider::ErrorType error,
-      const smbprovider::DirectoryEntryListProto& entries);
-
-  void ProcessReadDirectoryResults(
-      storage::AsyncFileUtil::ReadDirectoryCallback callback,
-      OperationId operation_id,
-      int32_t read_dir_token,
-      smbprovider::ErrorType error,
-      const smbprovider::DirectoryEntryListProto& entries,
-      int entries_count,
-      base::ElapsedTimer metrics_timer);
-
-  int32_t GetMountId() const;
-
-  std::string GetMountPath() const;
-
-  SmbProviderClient* GetSmbProviderClient() const;
-  base::WeakPtr<SmbProviderClient> GetWeakSmbProviderClient() const;
-
-  // Gets a new OperationId and adds |task| to the task_queue_ with it. Returns
-  // an AbortCallback to abort the newly created operation.
-  file_system_provider::AbortCallback EnqueueTaskAndGetCallback(SmbTask task);
-
-  // Adds |task| to the task_queue_ for |operation_id|.
-  void EnqueueTask(SmbTask task, OperationId operation_id);
-
-  // Gets a new OperationId and adds |task| to the task_queue_ with it. Returns
-  // the OperationId for the newly created Operation.
-  OperationId EnqueueTaskAndGetOperationId(SmbTask task);
-
-  // Check if the error can be recovered and handled to continue its original
-  // operation. Returns true if error can be handled.
-  bool IsRecoverableError(smbprovider::ErrorType error) const;
-
-  // Runs the StartReadDirectory if |should_retry_start_read_dir| is true. If
-  // false, |callback| will run instead.
-  void RetryStartReadDir(const base::FilePath& directory_path,
-                         OperationId operation_id,
-                         storage::AsyncFileUtil::ReadDirectoryCallback callback,
-                         bool should_retry_start_read_dir);
-
   const file_system_provider::ProvidedFileSystemInfo file_system_info_;
   // opened_files_ is marked const since is currently unsupported.
   const file_system_provider::OpenedFiles opened_files_;
-
-  std::unique_ptr<TempFileManager> temp_file_manager_;
-  mutable SmbTaskQueue task_queue_;
 };
 
 }  // namespace smb_client
diff --git a/chrome/browser/ash/smb_client/smb_file_system_unittest.cc b/chrome/browser/ash/smb_client/smb_file_system_unittest.cc
deleted file mode 100644
index 8b677b0..0000000
--- a/chrome/browser/ash/smb_client/smb_file_system_unittest.cc
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ash/smb_client/smb_file_system.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/run_loop.h"
-#include "base/test/bind.h"
-#include "chrome/browser/ash/file_system_provider/provided_file_system_info.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_smb_provider_client.h"
-#include "content/public/test/browser_task_environment.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using ::testing::_;
-using ::testing::Invoke;
-using ::testing::WithArg;
-
-namespace ash {
-namespace smb_client {
-namespace {
-
-const file_system_provider::ProviderId kProviderId =
-    file_system_provider::ProviderId::CreateFromNativeId("smb");
-constexpr char kSharePath[] = "\\\\server\\foobar";
-constexpr int32_t kMountId = 4;
-constexpr char kDirectoryPath[] = "foo/bar";
-
-class MockSmbProviderClient : public chromeos::FakeSmbProviderClient {
- public:
-  MockSmbProviderClient()
-      : FakeSmbProviderClient(true /* should_run_synchronously */) {}
-
-  MOCK_METHOD(void,
-              DeleteEntry,
-              (int32_t, const base::FilePath&, bool, StatusCallback),
-              (override));
-};
-
-class SmbFileSystemTest : public testing::Test {
- protected:
-  SmbFileSystemTest()
-      : task_environment_(content::BrowserTaskEnvironment::REAL_IO_THREAD) {}
-
-  void SetUp() override {
-    file_system_provider::ProvidedFileSystemInfo file_system_info(
-        kProviderId, {}, base::FilePath(kSharePath), false /* configurable */,
-        false /* watchable */, extensions::SOURCE_NETWORK,
-        file_system_provider::IconSet());
-    file_system_ = std::make_unique<SmbFileSystem>(file_system_info);
-
-    std::unique_ptr<MockSmbProviderClient> mock_client =
-        std::make_unique<MockSmbProviderClient>();
-    mock_client_ = mock_client.get();
-    // The mock needs to be marked as leaked because ownership is passed to
-    // DBusThreadManager.
-    testing::Mock::AllowLeak(mock_client.get());
-    chromeos::DBusThreadManager::Initialize();
-    chromeos::DBusThreadManager::GetSetterForTesting()->SetSmbProviderClient(
-        std::move(mock_client));
-  }
-
-  void TearDown() override {
-    chromeos::DBusThreadManager::Shutdown();
-    // Because the mock is potentially leaked, expectations needs to be manually
-    // verified.
-    EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(mock_client_));
-  }
-
-  content::BrowserTaskEnvironment task_environment_;
-  MockSmbProviderClient* mock_client_;  // Owned by DBusThreadManager.
-  std::unique_ptr<SmbFileSystem> file_system_;
-};
-
-TEST_F(SmbFileSystemTest, DeleteEntry_NonRecursive) {
-  base::FilePath dir(kDirectoryPath);
-
-  base::RunLoop run_loop;
-  EXPECT_CALL(*mock_client_, DeleteEntry(kMountId, dir, false, _))
-      .WillOnce(WithArg<3>(Invoke([](SmbProviderClient::StatusCallback cb) {
-        std::move(cb).Run(smbprovider::ErrorType::ERROR_OK);
-      })));
-  file_system_->DeleteEntry(
-      dir, false /* recursive */,
-      base::BindLambdaForTesting([&run_loop](base::File::Error error) {
-        EXPECT_EQ(error, base::File::FILE_OK);
-        run_loop.Quit();
-      }));
-  run_loop.Run();
-}
-
-TEST_F(SmbFileSystemTest, DeleteEntry_NonRecursiveFailed) {
-  base::FilePath dir(kDirectoryPath);
-
-  base::RunLoop run_loop;
-  EXPECT_CALL(*mock_client_, DeleteEntry(kMountId, dir, false, _))
-      .WillOnce(WithArg<3>(Invoke([](SmbProviderClient::StatusCallback cb) {
-        std::move(cb).Run(smbprovider::ErrorType::ERROR_NOT_EMPTY);
-      })));
-  file_system_->DeleteEntry(
-      dir, false /* recursive */,
-      base::BindLambdaForTesting([&run_loop](base::File::Error error) {
-        EXPECT_EQ(error, base::File::FILE_ERROR_NOT_EMPTY);
-        run_loop.Quit();
-      }));
-  run_loop.Run();
-}
-
-}  // namespace
-}  // namespace smb_client
-}  // namespace ash
diff --git a/chrome/browser/ash/smb_client/smb_service.h b/chrome/browser/ash/smb_client/smb_service.h
index 8ff07c2..ee886c6 100644
--- a/chrome/browser/ash/smb_client/smb_service.h
+++ b/chrome/browser/ash/smb_client/smb_service.h
@@ -21,7 +21,6 @@
 #include "chrome/browser/ash/smb_client/smb_errors.h"
 #include "chrome/browser/ash/smb_client/smb_persisted_share_registry.h"
 #include "chrome/browser/ash/smb_client/smb_share_finder.h"
-#include "chrome/browser/ash/smb_client/smb_task_queue.h"
 #include "chrome/browser/ash/smb_client/smbfs_share.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chromeos/dbus/smb_provider_client.h"
diff --git a/chrome/browser/ash/smb_client/smb_task_queue.cc b/chrome/browser/ash/smb_client/smb_task_queue.cc
deleted file mode 100644
index d40e66c..0000000
--- a/chrome/browser/ash/smb_client/smb_task_queue.cc
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ash/smb_client/smb_task_queue.h"
-
-#include "base/bind.h"
-#include "base/callback.h"
-
-namespace ash {
-namespace smb_client {
-
-SmbTaskQueue::SmbTaskQueue(size_t max_pending) : max_pending_(max_pending) {}
-SmbTaskQueue::~SmbTaskQueue() {}
-
-OperationId SmbTaskQueue::GetNextOperationId() {
-  return next_operation_id++;
-}
-
-void SmbTaskQueue::AddTask(SmbTask task, OperationId operation_id) {
-  DCHECK(IsValidOperationId(operation_id));
-
-  if (!operation_map_.count(operation_id)) {
-    operations_.push(operation_id);
-  }
-  operation_map_[operation_id].push(std::move(task));
-
-  RunTaskIfNecessary();
-}
-
-void SmbTaskQueue::TaskFinished() {
-  DCHECK_GT(num_pending_, 0u);
-  --num_pending_;
-  RunTaskIfNecessary();
-}
-
-void SmbTaskQueue::AbortOperation(OperationId operation_id) {
-  DCHECK(IsValidOperationId(operation_id));
-
-  operation_map_.erase(operation_id);
-}
-
-void SmbTaskQueue::RunTaskIfNecessary() {
-  PruneOperationQueue();
-  if (IsCapacityToRunTask() && IsTaskToRun()) {
-    RunNextTask();
-
-    // Sanity check that either the maximum number of tasks are running or
-    // nothing is in the queue. If there is anything left in the queue to run,
-    // then the maximum number of tasks should already be running.
-    DCHECK(!IsCapacityToRunTask() || !IsTaskToRun());
-  }
-}
-
-SmbTask SmbTaskQueue::GetNextTask() {
-  DCHECK(IsTaskToRun());
-  const OperationId operation_id = operations_.front();
-
-  DCHECK(operation_map_.count(operation_id));
-  auto& queue = operation_map_.find(operation_id)->second;
-
-  SmbTask next_task = std::move(queue.front());
-  queue.pop();
-
-  if (queue.empty()) {
-    operation_map_.erase(operation_id);
-    operations_.pop();
-  }
-
-  return next_task;
-}
-
-void SmbTaskQueue::RunNextTask() {
-  DCHECK(IsTaskToRun());
-
-  ++num_pending_;
-  GetNextTask().Run();
-}
-
-void SmbTaskQueue::PruneOperationQueue() {
-  while (!IsPruned()) {
-    operations_.pop();
-  }
-}
-
-bool SmbTaskQueue::IsPruned() const {
-  return (operations_.empty() || operation_map_.count(operations_.front()));
-}
-
-bool SmbTaskQueue::IsTaskToRun() const {
-  DCHECK(IsPruned());
-  return !operations_.empty();
-}
-
-bool SmbTaskQueue::IsCapacityToRunTask() const {
-  return num_pending_ < max_pending_;
-}
-
-bool SmbTaskQueue::IsValidOperationId(OperationId operation_id) const {
-  return operation_id < next_operation_id;
-}
-
-}  // namespace smb_client
-}  // namespace ash
diff --git a/chrome/browser/ash/smb_client/smb_task_queue.h b/chrome/browser/ash/smb_client/smb_task_queue.h
deleted file mode 100644
index f9437bb1..0000000
--- a/chrome/browser/ash/smb_client/smb_task_queue.h
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_ASH_SMB_CLIENT_SMB_TASK_QUEUE_H_
-#define CHROME_BROWSER_ASH_SMB_CLIENT_SMB_TASK_QUEUE_H_
-
-#include "base/callback.h"
-#include "base/containers/queue.h"
-#include "chromeos/dbus/smb_provider_client.h"
-
-namespace ash {
-namespace smb_client {
-
-// An SmbTask is a call to SmbProviderClient with a bound SmbFileSystem callback
-// that runs when SmbProviderClient receives a D-Bus message response.
-using SmbTask = base::OnceClosure;
-using OperationId = uint32_t;
-
-// SmbTaskQueue handles the queuing of SmbTasks. Tasks are 'pending' while
-// SmbProviderClient awaits a D-Bus Message Response. Tasks are added to
-// the queue via SmbTaskQueue::AddTask. Upon the SmbFileSystem callback in the
-// task running, the caller must call SmbTaskQueue::TaskFinished to allow the
-// next task to run.
-//
-// Example:
-//
-//  AbortCallback CreateDirectory(FilePath directory_path, bool recursive,
-//                                StatusCallback callback) {
-//    auto reply = base::BindOnce(&SmbFileSystem::HandleStatusCallback,
-//                                AsWeakPtr(), callback);
-//
-//    SmbTask task = base::BindOnce(&SmbProviderClient::CreateDirectory,
-//                                  base::Unretained(GetSmbProviderClient()),
-//                                  GetMountId(),
-//                                  directory_path,
-//                                  recursive,
-//                                  std::move(reply));
-//    OperationId operation_id = 1;
-//    tq_.AddTask(std::move(task));
-//
-//    return CreateAbortCallbackForOperationId(operation_id);
-//  }
-//
-//  void HandleStatusCallback(StatusCallback callback, ErrorType error) {
-//    tq_.TaskFinished();
-//    callback.Run(error);
-//  }
-class SmbTaskQueue {
- public:
-  explicit SmbTaskQueue(size_t max_pending);
-  SmbTaskQueue(const SmbTaskQueue&) = delete;
-  SmbTaskQueue& operator=(const SmbTaskQueue&) = delete;
-  ~SmbTaskQueue();
-
-  // Provides the caller with a new OperationId to associate new tasks with.
-  OperationId GetNextOperationId();
-
-  // Adds the sub-task |task| for the Operation |operation_id| to the task
-  // queue. If fewer that max_pending_ tasks are outstanding, |task| will run
-  // immediately. Otherwise, it will be added to operations_ and run in FIFO
-  // order.
-  void AddTask(SmbTask task, OperationId operation_id);
-
-  // Attempts to abort any outstanding tasks associated with the operation
-  // |operation_id|. Any subtasks that have not been sent over to D-Bus to the
-  // Smb Daemon will be cancelled, and OperationId will be removed from
-  // operation_map_.
-  void AbortOperation(OperationId operation_id);
-
-  // Must be called by the owner of this class to indicate that a response to a
-  // task was received.
-  void TaskFinished();
-
- private:
-  using TaskList = base::queue<SmbTask>;
-
-  // This runs the next task in operations_ if there is capacity to run an
-  // additional task, and a task remaing to run.
-  void RunTaskIfNecessary();
-
-  // Helper method that returns the next task to run.
-  SmbTask GetNextTask();
-
-  // Helper method that runs the next task.
-  void RunNextTask();
-
-  // Prunes operations_ by removing OperationIds from the front of the queue if
-  // there are no tasks associated with them.
-  void PruneOperationQueue();
-
-  // Helper method that returns whether operations_ has been pruned.
-  bool IsPruned() const;
-
-  // Helper method that returns whether there are tasks in operations_ to run.
-  // operations_ must be pruned (i.e. the top Operation in operations_ must have
-  // atleast 1 task associated with it).
-  bool IsTaskToRun() const;
-
-  // Helper method that returns whether there are fewer than max_pending tasks
-  // outstanding.
-  bool IsCapacityToRunTask() const;
-
-  // Helper method that returns whether |operation_id| is valid.
-  bool IsValidOperationId(OperationId operation_id) const;
-
-  const size_t max_pending_;
-  size_t num_pending_ = 0;
-  OperationId next_operation_id = 0;
-  base::queue<OperationId> operations_;
-  std::map<OperationId, TaskList> operation_map_;
-};
-
-}  // namespace smb_client
-}  // namespace ash
-
-#endif  // CHROME_BROWSER_ASH_SMB_CLIENT_SMB_TASK_QUEUE_H_
diff --git a/chrome/browser/ash/smb_client/smb_task_queue_unittest.cc b/chrome/browser/ash/smb_client/smb_task_queue_unittest.cc
deleted file mode 100644
index 3c65a60..0000000
--- a/chrome/browser/ash/smb_client/smb_task_queue_unittest.cc
+++ /dev/null
@@ -1,247 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ash/smb_client/smb_task_queue.h"
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ash {
-namespace smb_client {
-namespace {
-constexpr size_t kTaskQueueCapacity = 3;
-}
-// SmbTaskQueue is used to test SmbTaskQueue. Tasks are added to the task queue
-// with specified |task_id|'s. When a task is run by the task_queue_, it is
-// added to the pending_ map and can be completed by invoking the
-// CompleteTask method.
-class SmbTaskQueueTest : public testing::Test {
- public:
-  SmbTaskQueueTest() : task_queue_(kTaskQueueCapacity) {}
-  SmbTaskQueueTest(const SmbTaskQueueTest&) = delete;
-  SmbTaskQueueTest& operator=(const SmbTaskQueueTest&) = delete;
-  ~SmbTaskQueueTest() override = default;
-
- protected:
-  // Calls SmbTaskQueue::GetNextOperationId().
-  OperationId GetOperationId() { return task_queue_.GetNextOperationId(); }
-
-  // Creates and adds a task with |task_id| and a default operation
-  // id. |task_id| is used for testing to manually control when tasks finish.
-  void CreateAndAddTask(uint32_t task_id) {
-    const OperationId operation_id = task_queue_.GetNextOperationId();
-    CreateAndAddTask(task_id, operation_id);
-  }
-
-  // Creates and adds a task with |task_id| for the corresponding
-  // |operation_id|.
-  void CreateAndAddTask(uint32_t task_id, OperationId operation_id) {
-    base::OnceClosure reply =
-        base::BindOnce(&SmbTaskQueueTest::OnReply, base::Unretained(this));
-    SmbTask task =
-        base::BindOnce(&SmbTaskQueueTest::Start, base::Unretained(this),
-                       task_id, std::move(reply));
-
-    task_queue_.AddTask(std::move(task), operation_id);
-  }
-
-  // Checks whether the task |task_id| is pending.
-  bool IsPending(uint32_t task_id) const { return pending_.count(task_id); }
-
-  // Completes the pending task |task_id|, running its reply.
-  void CompleteTask(uint32_t task_id) {
-    DCHECK(IsPending(task_id));
-
-    SmbTask to_run = std::move(pending_[task_id]);
-    pending_.erase(task_id);
-
-    std::move(to_run).Run();
-  }
-
-  // Returns the number of pending tasks.
-  size_t PendingCount() const { return pending_.size(); }
-
-  // Calls AbortOperation with |operation_id| on task_queue_.
-  void Abort(OperationId operation_id) {
-    task_queue_.AbortOperation(operation_id);
-  }
-
- private:
-  void OnReply() { task_queue_.TaskFinished(); }
-
-  void Start(uint32_t task_id, base::OnceClosure reply) {
-    pending_[task_id] = std::move(reply);
-  }
-
-  SmbTaskQueue task_queue_;
-  std::map<uint32_t, base::OnceClosure> pending_;
-};
-
-// SmbTaskQueue immediately runs a task when less than max_pending are running.
-TEST_F(SmbTaskQueueTest, TaskQueueRunsASingleTask) {
-  const uint32_t task_id = 1;
-
-  CreateAndAddTask(task_id);
-  EXPECT_TRUE(IsPending(task_id));
-
-  CompleteTask(task_id);
-  EXPECT_FALSE(IsPending(task_id));
-}
-
-// SmbTaskQueue runs atleast max_pending_ tasks concurrently.
-TEST_F(SmbTaskQueueTest, TaskQueueRunsMultipleTasks) {
-  const uint32_t task_id_1 = 1;
-  const uint32_t task_id_2 = 2;
-  const uint32_t task_id_3 = 3;
-
-  CreateAndAddTask(task_id_1);
-  CreateAndAddTask(task_id_2);
-  CreateAndAddTask(task_id_3);
-
-  EXPECT_EQ(kTaskQueueCapacity, PendingCount());
-
-  EXPECT_TRUE(IsPending(task_id_1));
-  EXPECT_TRUE(IsPending(task_id_2));
-  EXPECT_TRUE(IsPending(task_id_3));
-
-  CompleteTask(task_id_1);
-  CompleteTask(task_id_2);
-  CompleteTask(task_id_3);
-
-  EXPECT_FALSE(IsPending(task_id_1));
-  EXPECT_FALSE(IsPending(task_id_2));
-  EXPECT_FALSE(IsPending(task_id_3));
-}
-
-// SmbTaskQueue runs at most max_pending_ tasks concurrently.
-TEST_F(SmbTaskQueueTest, TaskQueueDoesNotRunAdditionalTestsWhenFull) {
-  const uint32_t task_id_1 = 1;
-  const uint32_t task_id_2 = 2;
-  const uint32_t task_id_3 = 3;
-  const uint32_t task_id_4 = 4;
-
-  CreateAndAddTask(task_id_1);
-  CreateAndAddTask(task_id_2);
-  CreateAndAddTask(task_id_3);
-  CreateAndAddTask(task_id_4);
-
-  // The first three tasks should run.
-  EXPECT_EQ(kTaskQueueCapacity, PendingCount());
-  EXPECT_TRUE(IsPending(task_id_1));
-  EXPECT_TRUE(IsPending(task_id_2));
-  EXPECT_TRUE(IsPending(task_id_3));
-
-  // The fourth task should wait until another task finishes to run.
-  EXPECT_FALSE(IsPending(task_id_4));
-
-  CompleteTask(task_id_1);
-  EXPECT_FALSE(IsPending(task_id_1));
-
-  // After completing a task, the fourth task should be able to run.
-  EXPECT_TRUE(IsPending(task_id_4));
-}
-
-// AbortOperation removes all the tasks corresponding to an operation that has
-// not begin to run yet.
-TEST_F(SmbTaskQueueTest, AbortOperationRemovesAllTasksOfUnrunOperation) {
-  // Saturate the SmbTaskQueue with tasks.
-  const uint32_t filler_task_1 = 1;
-  const uint32_t filler_task_2 = 2;
-  const uint32_t filler_task_3 = 3;
-  CreateAndAddTask(filler_task_1);
-  CreateAndAddTask(filler_task_2);
-  CreateAndAddTask(filler_task_3);
-
-  // Create some tasks coresponding to a specific operation_id.
-  const OperationId operation_id = GetOperationId();
-  const uint32_t task_to_cancel_1 = 101;
-  const uint32_t task_to_cancel_2 = 102;
-  const uint32_t task_to_cancel_3 = 103;
-
-  CreateAndAddTask(task_to_cancel_1, operation_id);
-  CreateAndAddTask(task_to_cancel_2, operation_id);
-  CreateAndAddTask(task_to_cancel_3, operation_id);
-
-  // The filler tasks should be pending, the tasks to cancel should not be.
-  EXPECT_EQ(kTaskQueueCapacity, PendingCount());
-  EXPECT_TRUE(IsPending(filler_task_1));
-  EXPECT_TRUE(IsPending(filler_task_2));
-  EXPECT_TRUE(IsPending(filler_task_3));
-
-  EXPECT_FALSE(IsPending(task_to_cancel_1));
-  EXPECT_FALSE(IsPending(task_to_cancel_2));
-  EXPECT_FALSE(IsPending(task_to_cancel_3));
-
-  // Aborting operation_id and completeing the filler tasks should not run
-  // the task_to_cancel's.
-  Abort(operation_id);
-
-  EXPECT_EQ(kTaskQueueCapacity, PendingCount());
-
-  CompleteTask(filler_task_1);
-  EXPECT_EQ(2u, PendingCount());
-
-  CompleteTask(filler_task_2);
-  EXPECT_EQ(1u, PendingCount());
-
-  CompleteTask(filler_task_3);
-  EXPECT_EQ(0u, PendingCount());
-
-  EXPECT_FALSE(IsPending(task_to_cancel_1));
-  EXPECT_FALSE(IsPending(task_to_cancel_2));
-  EXPECT_FALSE(IsPending(task_to_cancel_3));
-}
-
-// AbortOperation aborts all the tasks correspoding to an operation that has
-// some running tasks.
-TEST_F(SmbTaskQueueTest, AbortOperationRemovesUnrunTasksOfRunningOperation) {
-  const uint32_t filler_task_1 = 1;
-  const uint32_t filler_task_2 = 2;
-  CreateAndAddTask(filler_task_1);
-  CreateAndAddTask(filler_task_2);
-
-  // Create some tasks coresponding to a specific operation_id.
-  const OperationId operation_id = GetOperationId();
-  const uint32_t task_to_cancel_1 = 101;
-  const uint32_t task_to_cancel_2 = 102;
-  const uint32_t task_to_cancel_3 = 103;
-
-  CreateAndAddTask(task_to_cancel_1, operation_id);
-  CreateAndAddTask(task_to_cancel_2, operation_id);
-  CreateAndAddTask(task_to_cancel_3, operation_id);
-
-  // The task queue should be running the maximum number of pending tasks,
-  // including the first task for operation_id. The remaining tasks for
-  // operation_id are not yet running.
-  EXPECT_EQ(kTaskQueueCapacity, PendingCount());
-  EXPECT_TRUE(IsPending(task_to_cancel_1));
-
-  EXPECT_FALSE(IsPending(task_to_cancel_2));
-  EXPECT_FALSE(IsPending(task_to_cancel_3));
-
-  // Aborting operation_id should not effect the status of task_to_cancel_1
-  // since it was already pending.
-  Abort(operation_id);
-
-  EXPECT_TRUE(IsPending(task_to_cancel_1));
-
-  // task_to_cancel_2 and task_to_cancel_3 should not run when the task queue
-  // has space capacity for them.
-  CompleteTask(filler_task_1);
-  CompleteTask(filler_task_2);
-  CompleteTask(task_to_cancel_1);
-
-  EXPECT_LT(PendingCount(), kTaskQueueCapacity);
-
-  EXPECT_FALSE(IsPending(task_to_cancel_2));
-  EXPECT_FALSE(IsPending(task_to_cancel_3));
-}
-
-}  // namespace smb_client
-}  // namespace ash
diff --git a/chrome/browser/ash/smb_client/temp_file_manager.cc b/chrome/browser/ash/smb_client/temp_file_manager.cc
deleted file mode 100644
index 0f3ace9..0000000
--- a/chrome/browser/ash/smb_client/temp_file_manager.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ash/smb_client/temp_file_manager.h"
-
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/files/file_util.h"
-#include "base/logging.h"
-
-namespace ash {
-namespace smb_client {
-
-TempFileManager::TempFileManager() {
-  CHECK(temp_dir_.CreateUniqueTempDir());
-}
-
-TempFileManager::~TempFileManager() = default;
-
-const base::FilePath& TempFileManager::GetTempDirectoryPath() const {
-  return temp_dir_.GetPath();
-}
-
-base::ScopedFD TempFileManager::CreateTempFile(
-    const std::vector<uint8_t>& data) {
-  base::ScopedFD temp_fd = CreateTempFile();
-
-  // Write the data into the newly created file.
-  if (!base::WriteFileDescriptor(temp_fd.get(), data)) {
-    LOG(ERROR) << "Error writing to temporary file";
-    temp_fd.reset();
-    return temp_fd;
-  }
-
-  // Seek the file descriptor to the start of the file in preparation for
-  // reading.
-  if (lseek(temp_fd.get(), 0, SEEK_SET) < 0) {
-    LOG(ERROR) << "Error seeking to beginning of temporary file";
-    temp_fd.reset();
-    return temp_fd;
-  }
-
-  return temp_fd;
-}
-
-base::ScopedFD TempFileManager::CreateTempFile() {
-  const std::string str = temp_dir_.GetPath().Append("XXXXXX").value();
-  // Make sure that the string we are passing is null-terminated.
-  std::unique_ptr<char[]> file_path = std::make_unique<char[]>(str.size() + 1);
-  memcpy(file_path.get(), str.c_str(), str.size());
-  file_path[str.size()] = '\0';
-
-  // mkstemp() modifies the passed in array.
-  base::ScopedFD temp_fd(HANDLE_EINTR(mkstemp(file_path.get())));
-  if (!temp_fd.is_valid()) {
-    LOG(ERROR) << "mkstemp failed to create a temporary file";
-    temp_fd.reset();
-    return temp_fd;
-  }
-
-  // Unlink causes the file to be deleted when the file descriptor is closed.
-  if (unlink(file_path.get()) != 0) {
-    LOG(ERROR) << "Failed to unlink temporary file: " << file_path.get();
-    temp_fd.reset();
-    return temp_fd;
-  }
-
-  return temp_fd;
-}
-
-}  // namespace smb_client
-}  // namespace ash
diff --git a/chrome/browser/ash/smb_client/temp_file_manager.h b/chrome/browser/ash/smb_client/temp_file_manager.h
deleted file mode 100644
index 7957cef..0000000
--- a/chrome/browser/ash/smb_client/temp_file_manager.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_ASH_SMB_CLIENT_TEMP_FILE_MANAGER_H_
-#define CHROME_BROWSER_ASH_SMB_CLIENT_TEMP_FILE_MANAGER_H_
-
-#include <vector>
-
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/files/scoped_temp_dir.h"
-
-namespace ash {
-namespace smb_client {
-
-// Helper class to handle construction and deletion of a temporary directory
-// containing temporary files.
-class TempFileManager {
- public:
-  TempFileManager();
-  TempFileManager(const TempFileManager&) = delete;
-  TempFileManager& operator=(const TempFileManager&) = delete;
-  ~TempFileManager();
-
-  // Returns the path of the temporary directory.
-  const base::FilePath& GetTempDirectoryPath() const;
-
-  // Creates a temporary file in temp_dir_ path and writes in |data|. Before
-  // returning, this seeks to the beginning of the file in preparation for
-  // reading. This also calls unlink() on the created file. Returns a file
-  // descriptor which will be invalid on failure.
-  base::ScopedFD CreateTempFile(const std::vector<uint8_t>& data);
-
- private:
-  // Creates a temporary file in temp_dir_ path. This also calls unlink() on the
-  // created file. Returns a file descriptor which will be invalid on failure.
-  base::ScopedFD CreateTempFile();
-
-  // Scoped class that handles deletion of the temporary directory.
-  base::ScopedTempDir temp_dir_;
-};
-
-}  // namespace smb_client
-}  // namespace ash
-
-#endif  // CHROME_BROWSER_ASH_SMB_CLIENT_TEMP_FILE_MANAGER_H_
diff --git a/chrome/browser/ash/smb_client/temp_file_manager_unittest.cc b/chrome/browser/ash/smb_client/temp_file_manager_unittest.cc
deleted file mode 100644
index 763b27ac..0000000
--- a/chrome/browser/ash/smb_client/temp_file_manager_unittest.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ash/smb_client/temp_file_manager.h"
-
-#include <string>
-#include <vector>
-
-#include "base/files/file_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ash {
-namespace smb_client {
-
-namespace {
-
-// Helper method to get the current offset of a file descriptor |fd|. Returns
-// the offset from the beginning of the file.
-int64_t GetCurrentOffset(int32_t fd) {
-  return lseek(fd, 0, SEEK_CUR);
-}
-
-}  // namespace
-
-class TempFileManagerTest : public testing::Test {
- public:
-  TempFileManagerTest() = default;
-  TempFileManagerTest(const TempFileManagerTest&) = delete;
-  TempFileManagerTest& operator=(const TempFileManagerTest&) = delete;
-  ~TempFileManagerTest() override = default;
-};
-
-// Should properly create a path when the object is created.
-TEST_F(TempFileManagerTest, ShouldCreatePath) {
-  TempFileManager file_manager;
-  const base::FilePath& path = file_manager.GetTempDirectoryPath();
-  EXPECT_FALSE(path.empty());
-  EXPECT_TRUE(base::PathExists(path));
-}
-
-// Path should be deleted after TempFileManager is cleaned up.
-TEST_F(TempFileManagerTest, PathShouldBeDeleted) {
-  std::string path;
-
-  {
-    TempFileManager file_manager;
-    path = file_manager.GetTempDirectoryPath().value();
-    EXPECT_TRUE(base::PathExists(base::FilePath(path)));
-  }
-
-  EXPECT_FALSE(base::PathExists(base::FilePath(path)));
-}
-
-// Should properly create a file with data and return a valid ScopedFD.
-TEST_F(TempFileManagerTest, ShouldCreateFile) {
-  std::vector<uint8_t> data = {0, 1, 2, 3, 4, 5, 6};
-  TempFileManager file_manager;
-  base::ScopedFD fd = file_manager.CreateTempFile(data);
-
-  EXPECT_TRUE(fd.is_valid());
-}
-
-// Should properly unlink directory path even if a file descriptor is open.
-TEST_F(TempFileManagerTest, FileShouldBeUnlinked) {
-  std::string path;
-
-  {
-    std::vector<uint8_t> data = {0, 1, 2, 3, 4, 5, 6};
-    TempFileManager file_manager;
-    path = file_manager.GetTempDirectoryPath().value();
-    base::ScopedFD fd = file_manager.CreateTempFile(data);
-  }
-
-  // Directory should be unlinked.
-  EXPECT_FALSE(base::PathExists(base::FilePath(path)));
-}
-
-// CreateFile should properly write the data into a file and seek back to the
-// beginning of the file.
-TEST_F(TempFileManagerTest, WriteFileSucceeds) {
-  std::vector<uint8_t> expected = {0, 1, 2, 3, 4, 5, 6};
-  TempFileManager file_manager;
-  base::ScopedFD fd = file_manager.CreateTempFile(expected);
-
-  // Expect the current offset to be at the beginning of the file.
-  EXPECT_EQ(0, GetCurrentOffset(fd.get()));
-
-  // Read back the data written and ensure that it is the same.
-  std::vector<uint8_t> actual(expected.size());
-  EXPECT_TRUE(base::ReadFromFD(fd.get(), reinterpret_cast<char*>(actual.data()),
-                               actual.size()));
-  EXPECT_EQ(expected, actual);
-}
-
-}  // namespace smb_client
-}  // namespace ash
diff --git a/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc b/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc
index aab4d5d..7518deb 100644
--- a/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc
+++ b/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc
@@ -40,6 +40,7 @@
 #include "components/autofill/core/browser/proto/server.pb.h"
 #include "components/autofill/core/common/autofill_features.h"
 #include "components/autofill/core/common/autofill_util.h"
+#include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/variations/variations_switches.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/test_renderer_host.h"
@@ -161,6 +162,11 @@
 
   bool SetupAutofillProfile() override {
     AddTestAutofillData(browser()->profile(), profile(), credit_card());
+    // Disable the Password Manager to prevent password bubbles from occurring.
+    // The password bubbles could overlap with the Autofill popups, in which
+    // case the Autofill popup would not be shown (crbug.com/1223898).
+    browser()->profile()->GetPrefs()->SetBoolean(
+        password_manager::prefs::kCredentialsEnableService, false);
     return true;
   }
 
diff --git a/chrome/browser/autofill/form_structure_browsertest.cc b/chrome/browser/autofill/form_structure_browsertest.cc
index 5d00d86..5decdd8 100644
--- a/chrome/browser/autofill/form_structure_browsertest.cc
+++ b/chrome/browser/autofill/form_structure_browsertest.cc
@@ -55,9 +55,12 @@
 
 const base::FilePath::CharType kTestName[] = FILE_PATH_LITERAL("heuristics");
 
-const std::set<base::FilePath::StringType>& GetFailingTestNames() {
-  static auto* failing_test_names = new std::set<base::FilePath::StringType>{};
-  return *failing_test_names;
+// To disable a data driven test, please add the name of the test file
+// (i.e., "NNN_some_site.html") as a literal to the initializer_list given
+// to the failing_test_names constructor.
+const auto& GetFailingTestNames() {
+  static std::set<base::FilePath::StringType> failing_test_names{};
+  return failing_test_names;
 }
 
 const base::FilePath& GetTestDataDir() {
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 3404babe..81a6345e 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -2314,14 +2314,10 @@
     "../ash/smb_client/smb_share_finder.h",
     "../ash/smb_client/smb_share_info.cc",
     "../ash/smb_client/smb_share_info.h",
-    "../ash/smb_client/smb_task_queue.cc",
-    "../ash/smb_client/smb_task_queue.h",
     "../ash/smb_client/smb_url.cc",
     "../ash/smb_client/smb_url.h",
     "../ash/smb_client/smbfs_share.cc",
     "../ash/smb_client/smbfs_share.h",
-    "../ash/smb_client/temp_file_manager.cc",
-    "../ash/smb_client/temp_file_manager.h",
     "../ash/sync/app_settings_model_type_controller.cc",
     "../ash/sync/app_settings_model_type_controller.h",
     "../ash/sync/apps_model_type_controller.cc",
@@ -2522,6 +2518,8 @@
     "cryptauth/gcm_device_info_provider_impl.h",
     "device_name_store.cc",
     "device_name_store.h",
+    "device_name_store_impl.cc",
+    "device_name_store_impl.h",
     "device_sync/device_sync_client_factory.cc",
     "device_sync/device_sync_client_factory.h",
     "eche_app/eche_app_manager_factory.cc",
@@ -4042,16 +4040,13 @@
     "../ash/smb_client/discovery/network_scanner_unittest.cc",
     "../ash/smb_client/smb_errors_unittest.cc",
     "../ash/smb_client/smb_file_system_id_test.cc",
-    "../ash/smb_client/smb_file_system_unittest.cc",
     "../ash/smb_client/smb_kerberos_credentials_updater_unittest.cc",
     "../ash/smb_client/smb_persisted_share_registry_unittest.cc",
     "../ash/smb_client/smb_service_helper_unittest.cc",
     "../ash/smb_client/smb_service_unittest.cc",
     "../ash/smb_client/smb_share_finder_unittest.cc",
-    "../ash/smb_client/smb_task_queue_unittest.cc",
     "../ash/smb_client/smb_url_unittest.cc",
     "../ash/smb_client/smbfs_share_unittest.cc",
-    "../ash/smb_client/temp_file_manager_unittest.cc",
     "../ash/sync/os_sync_util_unittest.cc",
     "../ash/sync/turn_sync_on_helper_unittest.cc",
     "../ash/system/automatic_reboot_manager_unittest.cc",
@@ -4098,7 +4093,7 @@
     "chrome_content_browser_client_chromeos_part_unittest.cc",
     "concierge_helper_service_unittest.cc",
     "cryptauth/client_app_metadata_provider_service_unittest.cc",
-    "device_name_store_unittest.cc",
+    "device_name_store_impl_unittest.cc",
     "eol_notification_unittest.cc",
     "events/event_rewriter_unittest.cc",
     "extensions/active_tab_permission_granter_delegate_chromeos_unittest.cc",
diff --git a/chrome/browser/chromeos/device_name_store.cc b/chrome/browser/chromeos/device_name_store.cc
index cecb473..c66dca0d 100644
--- a/chrome/browser/chromeos/device_name_store.cc
+++ b/chrome/browser/chromeos/device_name_store.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/chromeos/device_name_store.h"
 
 #include "ash/constants/ash_features.h"
+#include "chrome/browser/chromeos/device_name_store_impl.h"
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
@@ -13,15 +14,11 @@
 namespace chromeos {
 namespace {
 
-const char kDefaultDeviceName[] = "ChromeOS";
-
 // This will point to the singleton instance upon initialization.
 DeviceNameStore* g_instance = nullptr;
 
 }  // namespace
 
-DeviceNameStore::~DeviceNameStore() = default;
-
 // static
 DeviceNameStore* DeviceNameStore::GetInstance() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -40,7 +37,7 @@
   CHECK(base::FeatureList::IsEnabled(features::kEnableHostnameSetting));
   CHECK(!g_instance);
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  g_instance = new DeviceNameStore(prefs);
+  g_instance = new DeviceNameStoreImpl(prefs);
 }
 
 // static
@@ -51,18 +48,8 @@
   }
 }
 
-DeviceNameStore::DeviceNameStore(PrefService* prefs) : prefs_(prefs) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  DCHECK(prefs_);
-  if (prefs_->GetString(prefs::kDeviceName).empty()) {
-    prefs_->SetString(prefs::kDeviceName, kDefaultDeviceName);
-  }
-}
+DeviceNameStore::DeviceNameStore() = default;
 
-std::string DeviceNameStore::GetDeviceName() const {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  DCHECK(prefs_);
-  return prefs_->GetString(prefs::kDeviceName);
-}
+DeviceNameStore::~DeviceNameStore() = default;
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/device_name_store.h b/chrome/browser/chromeos/device_name_store.h
index 1144da5..8415851 100644
--- a/chrome/browser/chromeos/device_name_store.h
+++ b/chrome/browser/chromeos/device_name_store.h
@@ -45,18 +45,17 @@
   // longer need it.
   static void Shutdown();
 
-  std::string GetDeviceName() const;
+  virtual std::string GetDeviceName() const = 0;
 
- private:
+ protected:
   friend class DeviceNameStoreTest;
 
-  explicit DeviceNameStore(PrefService* prefs);
+  DeviceNameStore();
   virtual ~DeviceNameStore();
+
+ private:
   DeviceNameStore(const DeviceNameStore&) = delete;
   DeviceNameStore& operator=(const DeviceNameStore&) = delete;
-
-  // Provides access and persistence for the device name value.
-  PrefService* prefs_;
 };
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/device_name_store_impl.cc b/chrome/browser/chromeos/device_name_store_impl.cc
new file mode 100644
index 0000000..a12cf6bd
--- /dev/null
+++ b/chrome/browser/chromeos/device_name_store_impl.cc
@@ -0,0 +1,32 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/device_name_store_impl.h"
+
+#include "chrome/common/pref_names.h"
+#include "components/prefs/pref_service.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace chromeos {
+namespace {
+const char kDefaultDeviceName[] = "ChromeOS";
+}
+
+DeviceNameStoreImpl::DeviceNameStoreImpl(PrefService* prefs) : prefs_(prefs) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DCHECK(prefs_);
+  if (prefs_->GetString(prefs::kDeviceName).empty()) {
+    prefs_->SetString(prefs::kDeviceName, kDefaultDeviceName);
+  }
+}
+
+DeviceNameStoreImpl::~DeviceNameStoreImpl() = default;
+
+std::string DeviceNameStoreImpl::GetDeviceName() const {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DCHECK(prefs_);
+  return prefs_->GetString(prefs::kDeviceName);
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/device_name_store_impl.h b/chrome/browser/chromeos/device_name_store_impl.h
new file mode 100644
index 0000000..44a1ae9d
--- /dev/null
+++ b/chrome/browser/chromeos/device_name_store_impl.h
@@ -0,0 +1,31 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_DEVICE_NAME_STORE_IMPL_H_
+#define CHROME_BROWSER_CHROMEOS_DEVICE_NAME_STORE_IMPL_H_
+
+#include "chrome/browser/chromeos/device_name_store.h"
+
+class PrefService;
+
+namespace chromeos {
+
+// DeviceNameStore implementation which uses a PrefService to store the device
+// name.
+class DeviceNameStoreImpl : public DeviceNameStore {
+ public:
+  explicit DeviceNameStoreImpl(PrefService* prefs);
+  ~DeviceNameStoreImpl() override;
+
+ private:
+  // DeviceNameStore:
+  std::string GetDeviceName() const override;
+
+  // Provides access and persistence for the device name value.
+  PrefService* prefs_;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_DEVICE_NAME_STORE_IMPL_H_
diff --git a/chrome/browser/chromeos/device_name_store_unittest.cc b/chrome/browser/chromeos/device_name_store_impl_unittest.cc
similarity index 87%
rename from chrome/browser/chromeos/device_name_store_unittest.cc
rename to chrome/browser/chromeos/device_name_store_impl_unittest.cc
index 20a6de70..819273b 100644
--- a/chrome/browser/chromeos/device_name_store_unittest.cc
+++ b/chrome/browser/chromeos/device_name_store_impl_unittest.cc
@@ -14,12 +14,12 @@
 
 namespace chromeos {
 
-class DeviceNameStoreTest : public ::testing::Test {
+class DeviceNameStoreImplTest : public ::testing::Test {
  public:
-  DeviceNameStoreTest() {
+  DeviceNameStoreImplTest() {
     DeviceNameStore::RegisterLocalStatePrefs(local_state_.registry());
   }
-  ~DeviceNameStoreTest() override = default;
+  ~DeviceNameStoreImplTest() override = default;
 
   // testing::Test
   void TearDown() override { DeviceNameStore::Shutdown(); }
@@ -50,13 +50,13 @@
 
 // Check that error is thrown if GetInstance() is called before
 // initialization.
-TEST_F(DeviceNameStoreTest, GetInstanceBeforeInitializeError) {
+TEST_F(DeviceNameStoreImplTest, GetInstanceBeforeInitializeError) {
   EXPECT_DEATH(DeviceNameStore::GetInstance(), "");
 }
 
 // Check that error is thrown upon initialization if kEnableHostnameSetting
 // flag is off.
-TEST_F(DeviceNameStoreTest, EnableHostnameSettingFlagOff) {
+TEST_F(DeviceNameStoreImplTest, EnableHostnameSettingFlagOff) {
   EXPECT_DEATH(
       InitializeDeviceNameStore(/*is_hostname_setting_flag_enabled=*/false),
       "");
@@ -64,7 +64,7 @@
 
 // Verifies the device name is set to 'ChromeOS' by default upon initialization
 // and that the device name is persisted to the local state.
-TEST_F(DeviceNameStoreTest, DefaultDeviceName) {
+TEST_F(DeviceNameStoreImplTest, DefaultDeviceName) {
   // The device name is not set yet.
   EXPECT_TRUE(GetDeviceNameFromPrefs().empty());
 
diff --git a/chrome/browser/chromeos/extensions/wm/wm_desks_private_api.cc b/chrome/browser/chromeos/extensions/wm/wm_desks_private_api.cc
index 9ff8e8d..9cd375d6 100644
--- a/chrome/browser/chromeos/extensions/wm/wm_desks_private_api.cc
+++ b/chrome/browser/chromeos/extensions/wm/wm_desks_private_api.cc
@@ -20,7 +20,7 @@
 api::wm_desks_private::DeskTemplate FromAshDeskTemplate(
     const ash::DeskTemplate& desk_template) {
   api::wm_desks_private::DeskTemplate out_api_template;
-  out_api_template.template_id = desk_template.uuid();
+  out_api_template.template_uuid = desk_template.uuid().AsLowercaseString();
   out_api_template.template_name =
       base::UTF16ToUTF8(desk_template.template_name());
   return out_api_template;
@@ -70,7 +70,7 @@
   EXTENSION_FUNCTION_VALIDATE(params);
 
   DesksClient::Get()->UpdateDeskTemplate(
-      params->desk_template.template_id,
+      params->desk_template.template_uuid,
       base::UTF8ToUTF16(params->desk_template.template_name),
       base::BindOnce(&WmDesksPrivateUpdateDeskTemplateFunction::
                          OnUpdateDeskTemplateCompleted,
@@ -133,7 +133,7 @@
   EXTENSION_FUNCTION_VALIDATE(params);
 
   DesksClient::Get()->DeleteDeskTemplate(
-      params->template_id,
+      params->template_uuid,
       base::BindOnce(&WmDesksPrivateDeleteDeskTemplateFunction::
                          OnDeleteDeskTemplateCompleted,
                      this));
@@ -162,7 +162,7 @@
   EXTENSION_FUNCTION_VALIDATE(params);
 
   DesksClient::Get()->LaunchDeskTemplate(
-      params->template_id,
+      params->template_uuid,
       base::BindOnce(
           &WmDesksPrivateLaunchDeskTemplateFunction::OnLaunchDeskTemplate,
           this));
diff --git a/chrome/browser/enterprise/connectors/connectors_manager.cc b/chrome/browser/enterprise/connectors/connectors_manager.cc
index d0696282..d0610810 100644
--- a/chrome/browser/enterprise/connectors/connectors_manager.cc
+++ b/chrome/browser/enterprise/connectors/connectors_manager.cc
@@ -108,11 +108,10 @@
   return analysis_connector_settings_[connector][0].GetAnalysisSettings(url);
 }
 
-absl::optional<FileSystemSettings> ConnectorsManager::GetFileSystemSettings(
-    const GURL& url,
+FileSystemServiceSettings* ConnectorsManager::GetFileSystemServiceSettings(
     FileSystemConnector connector) {
   if (!IsConnectorEnabled(connector))
-    return absl::nullopt;
+    return nullptr;
 
   if (file_system_connector_settings_.count(connector) == 0)
     CacheFileSystemConnectorPolicy(connector);
@@ -120,11 +119,28 @@
   // If the connector is still not in memory, it means the pref is set to an
   // empty list or that it is not a list.
   if (file_system_connector_settings_.count(connector) == 0)
-    return absl::nullopt;
+    return nullptr;
 
   // While multiple services can be set by the connector policies, only the
   // first one is considered for now.
-  return file_system_connector_settings_[connector][0].GetSettings(url);
+  return &(file_system_connector_settings_[connector][0]);
+}
+
+absl::optional<FileSystemSettings>
+ConnectorsManager::GetFileSystemGlobalSettings(FileSystemConnector connector) {
+  auto* service_settings = GetFileSystemServiceSettings(connector);
+  if (!service_settings)
+    return absl::nullopt;
+  return service_settings->GetGlobalSettings();
+}
+
+absl::optional<FileSystemSettings> ConnectorsManager::GetFileSystemSettings(
+    const GURL& url,
+    FileSystemConnector connector) {
+  auto* service_settings = GetFileSystemServiceSettings(connector);
+  if (!service_settings)
+    return absl::nullopt;
+  return service_settings->GetSettings(url);
 }
 
 void ConnectorsManager::CacheAnalysisConnectorPolicy(
diff --git a/chrome/browser/enterprise/connectors/connectors_manager.h b/chrome/browser/enterprise/connectors/connectors_manager.h
index 04a9c27..54e3c79 100644
--- a/chrome/browser/enterprise/connectors/connectors_manager.h
+++ b/chrome/browser/enterprise/connectors/connectors_manager.h
@@ -49,8 +49,10 @@
       AnalysisConnector connector);
 
   // Validates which settings should be applied to a file system connector
-  // against cached policies. Cache the policy value the first time this is
-  // called for every different connector.
+  // against cached policies.
+  absl::optional<FileSystemSettings> GetFileSystemGlobalSettings(
+      FileSystemConnector connector);
+  // In addition to method above; also validates specifically for an URL.
   absl::optional<FileSystemSettings> GetFileSystemSettings(
       const GURL& url,
       FileSystemConnector connector);
@@ -105,6 +107,12 @@
   absl::optional<ReportingSettings> GetReportingSettingsFromConnectorPolicy(
       ReportingConnector connector);
 
+  // Returns service settings (if there are multiple service providers, only the
+  // first one for now) for |connector|. Cache the policy value the first time
+  // this is called for every different connector.
+  FileSystemServiceSettings* GetFileSystemServiceSettings(
+      FileSystemConnector connector);
+
   // Cached values of available service providers. This information validates
   // the Connector policies have a valid provider.
   ServiceProviderConfig* service_provider_config_;
diff --git a/chrome/browser/enterprise/connectors/connectors_service.cc b/chrome/browser/enterprise/connectors/connectors_service.cc
index cc64ef4..8cd0905 100644
--- a/chrome/browser/enterprise/connectors/connectors_service.cc
+++ b/chrome/browser/enterprise/connectors/connectors_service.cc
@@ -283,6 +283,20 @@
   return settings;
 }
 
+absl::optional<FileSystemSettings>
+ConnectorsService::GetFileSystemGlobalSettings(FileSystemConnector connector) {
+  if (!ConnectorsEnabled())
+    return absl::nullopt;
+
+  absl::optional<FileSystemSettings> settings =
+      connectors_manager_->GetFileSystemGlobalSettings(connector);
+
+  if (!settings.has_value())
+    return absl::nullopt;
+
+  return settings;
+}
+
 absl::optional<FileSystemSettings> ConnectorsService::GetFileSystemSettings(
     const GURL& url,
     FileSystemConnector connector) {
diff --git a/chrome/browser/enterprise/connectors/connectors_service.h b/chrome/browser/enterprise/connectors/connectors_service.h
index a3ca9b3..4f27570 100644
--- a/chrome/browser/enterprise/connectors/connectors_service.h
+++ b/chrome/browser/enterprise/connectors/connectors_service.h
@@ -54,6 +54,8 @@
   absl::optional<AnalysisSettings> GetAnalysisSettings(
       const GURL& url,
       AnalysisConnector connector);
+  absl::optional<FileSystemSettings> GetFileSystemGlobalSettings(
+      FileSystemConnector connector);
   absl::optional<FileSystemSettings> GetFileSystemSettings(
       const GURL& url,
       FileSystemConnector connector);
diff --git a/chrome/browser/enterprise/connectors/file_system/rename_handler.cc b/chrome/browser/enterprise/connectors/file_system/rename_handler.cc
index 3623fa4..4edf09c 100644
--- a/chrome/browser/enterprise/connectors/file_system/rename_handler.cc
+++ b/chrome/browser/enterprise/connectors/file_system/rename_handler.cc
@@ -7,7 +7,6 @@
 #include <utility>
 
 #include "base/files/file_util.h"
-#include "chrome/browser/enterprise/connectors/connectors_service.h"
 #include "chrome/browser/enterprise/connectors/file_system/access_token_fetcher.h"
 #include "chrome/browser/enterprise/connectors/file_system/box_uploader.h"
 #include "chrome/browser/enterprise/connectors/file_system/signin_experience.h"
@@ -38,19 +37,10 @@
   return context ? PrefsFromBrowserContext(context) : nullptr;
 }
 
-bool MimeTypeMatches(const std::set<std::string>& mime_types,
-                     const std::string& mime_type) {
-  return mime_types.count(kWildcardMimeType) != 0 ||
-         mime_types.count(mime_type) != 0;
-}
-
 using download::ConvertNetErrorToInterruptReason;
 
 }  // namespace
 
-const base::Feature kFileSystemConnectorEnabled{
-    "FileSystemConnectorsEnabled", base::FEATURE_DISABLED_BY_DEFAULT};
-
 using InterruptReason = download::DownloadInterruptReason;
 constexpr auto kBrowserFailure = download::DOWNLOAD_INTERRUPT_REASON_CRASH;
 constexpr auto kCredentialUpdateFailure = kBrowserFailure;
@@ -59,34 +49,6 @@
     download::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED;
 
 // static
-absl::optional<FileSystemSettings> FileSystemRenameHandler::IsEnabled(
-    download::DownloadItem* download_item) {
-  if (!base::FeatureList::IsEnabled(kFileSystemConnectorEnabled))
-    return absl::nullopt;
-
-  // Check to see if the download item matches any rules.  If the URL of the
-  // download itself does not match then check the URL of site on which the
-  // download is hosted.
-  ConnectorsService* service = ConnectorsServiceFactory::GetForBrowserContext(
-      content::DownloadItemUtils::GetBrowserContext(download_item));
-  auto settings = service->GetFileSystemSettings(
-      download_item->GetURL(), FileSystemConnector::SEND_DOWNLOAD_TO_CLOUD);
-  if (settings.has_value() &&
-      MimeTypeMatches(settings->mime_types, download_item->GetMimeType())) {
-    return settings;
-  }
-
-  settings = service->GetFileSystemSettings(
-      download_item->GetTabUrl(), FileSystemConnector::SEND_DOWNLOAD_TO_CLOUD);
-  if (settings.has_value() &&
-      MimeTypeMatches(settings->mime_types, download_item->GetMimeType())) {
-    return settings;
-  }
-
-  return absl::nullopt;
-}
-
-// static
 std::unique_ptr<download::DownloadItemRenameHandler>
 FileSystemRenameHandler::CreateIfNeeded(download::DownloadItem* download_item) {
   if (download_item->GetState() == download::DownloadItem::COMPLETE) {
@@ -96,12 +58,11 @@
   }
   // TODO(https://crbug.com/1213761) Resume upload if state is IN_PROGRESS, and
   // perhaps also INTERRUPTED and CANCELLED.
-  absl::optional<FileSystemSettings> settings = IsEnabled(download_item);
-  if (settings.has_value()) {
-    return std::make_unique<FileSystemRenameHandler>(
-        download_item, std::move(settings.value()));
-  }
-  return nullptr;
+  absl::optional<FileSystemSettings> settings =
+      GetFileSystemSettings(download_item);
+  return settings.has_value() ? std::make_unique<FileSystemRenameHandler>(
+                                    download_item, std::move(settings.value()))
+                              : nullptr;
 }
 
 // The only permitted use of |download_item| in this class other than the ctor
@@ -139,7 +100,7 @@
 
 void FileSystemRenameHandler::PromptUserSignInForAuthorization(
     content::WebContents* contents) {
-  StartSigninExperienceForDownloadItem(
+  StartFileSystemConnectorSigninExperienceForDownloadItem(
       contents, settings_,
       base::BindOnce(&FileSystemRenameHandler::OnAuthorization,
                      weak_factory_.GetWeakPtr()));
diff --git a/chrome/browser/enterprise/connectors/file_system/rename_handler.h b/chrome/browser/enterprise/connectors/file_system/rename_handler.h
index 165190f..a1bbc385 100644
--- a/chrome/browser/enterprise/connectors/file_system/rename_handler.h
+++ b/chrome/browser/enterprise/connectors/file_system/rename_handler.h
@@ -6,7 +6,6 @@
 #define CHROME_BROWSER_ENTERPRISE_CONNECTORS_FILE_SYSTEM_RENAME_HANDLER_H_
 
 #include "base/callback.h"
-#include "base/feature_list.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/enterprise/connectors/common.h"
 #include "components/download/public/common/download_interrupt_reasons.h"
@@ -27,9 +26,6 @@
 class AccessTokenFetcher;
 class BoxUploader;
 
-// Experimental flag to enable or disable the file system connector.
-extern const base::Feature kFileSystemConnectorEnabled;
-
 // An implementation of download::DownloadItemRenameHandler that sends a
 // download item file to a cloud-based storage provider as specified in the
 // SendDownloadToCloudEnterpriseConnector policy.
@@ -70,9 +66,6 @@
                             const std::string& refresh_token);
 
  private:
-  static absl::optional<FileSystemSettings> IsEnabled(
-      download::DownloadItem* download_item);
-
   void StartInternal(std::string access_token = std::string());
   scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory(
       content::BrowserContext* context);
diff --git a/chrome/browser/enterprise/connectors/file_system/rename_handler_unittest.cc b/chrome/browser/enterprise/connectors/file_system/rename_handler_unittest.cc
index ac95a1e32..f7f2724 100644
--- a/chrome/browser/enterprise/connectors/file_system/rename_handler_unittest.cc
+++ b/chrome/browser/enterprise/connectors/file_system/rename_handler_unittest.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/enterprise/connectors/connectors_service.h"
 #include "chrome/browser/enterprise/connectors/file_system/access_token_fetcher.h"
 #include "chrome/browser/enterprise/connectors/file_system/box_uploader.h"
+#include "chrome/browser/enterprise/connectors/file_system/signin_experience.h"
 #include "chrome/browser/enterprise/connectors/file_system/test_helper.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "chrome/test/base/testing_browser_process.h"
@@ -98,11 +99,15 @@
 };
 
 TEST_P(RenameHandlerCreateTest, FeatureFlagTest) {
+  // Check the precondition regardless of download item: feature is enabled.
+  auto settings = GetFileSystemSettings(profile());
+  ASSERT_EQ(enable_feature_flag(), settings.has_value());
+
+  // Ensure a RenameHandler can be created with the profile in download item.
   content::FakeDownloadItem item;
   item.SetURL(GURL("https://renameme.com"));
   item.SetMimeType("text/plain");
   content::DownloadItemUtils::AttachInfo(&item, profile(), nullptr);
-
   auto handler = RenameHandler::CreateIfNeeded(&item);
   ASSERT_EQ(enable_feature_flag(), handler.get() != nullptr);
 }
diff --git a/chrome/browser/enterprise/connectors/file_system/service_settings.cc b/chrome/browser/enterprise/connectors/file_system/service_settings.cc
index f9426df..b77cc6c4 100644
--- a/chrome/browser/enterprise/connectors/file_system/service_settings.cc
+++ b/chrome/browser/enterprise/connectors/file_system/service_settings.cc
@@ -9,6 +9,9 @@
 
 namespace enterprise_connectors {
 
+const base::Feature kFileSystemConnectorEnabled{
+    "FileSystemConnectorsEnabled", base::FEATURE_DISABLED_BY_DEFAULT};
+
 FileSystemServiceSettings::FileSystemServiceSettings(
     const base::Value& settings_value,
     const ServiceProviderConfig& service_provider_config) {
@@ -79,20 +82,11 @@
     FileSystemServiceSettings&&) = default;
 FileSystemServiceSettings::~FileSystemServiceSettings() = default;
 
-absl::optional<FileSystemSettings> FileSystemServiceSettings::GetSettings(
-    const GURL& url) const {
+absl::optional<FileSystemSettings>
+FileSystemServiceSettings::GetGlobalSettings() const {
   if (!IsValid())
     return absl::nullopt;
 
-  DCHECK(matcher_);
-  auto matches = matcher_->MatchURL(url);
-  if (matches.empty())
-    return absl::nullopt;
-
-  auto mime_types = GetMimeTypes(matches);
-  if (mime_types.empty())
-    return absl::nullopt;
-
   FileSystemSettings settings;
   settings.service_provider = service_provider_name_;
   settings.home = GURL(service_provider_->fs_home_url());
@@ -105,7 +99,30 @@
   settings.client_secret = service_provider_->fs_client_secret();
   settings.scopes = service_provider_->fs_scopes();
   settings.max_direct_size = service_provider_->fs_max_direct_size();
-  settings.mime_types = std::move(mime_types);
+
+  return settings;
+}
+
+absl::optional<FileSystemSettings> FileSystemServiceSettings::GetSettings(
+    const GURL& url) const {
+  if (!IsValid())
+    return absl::nullopt;
+
+  DCHECK(url.is_valid()) << "URL: " << url;
+
+  auto settings = GetGlobalSettings();
+  if (settings.has_value()) {
+    DCHECK(matcher_);
+    std::set<std::string> mime_types;
+    auto matches = matcher_->MatchURL(url);
+    if (matches.empty())
+      return absl::nullopt;
+    mime_types = GetMimeTypes(matches);
+    if (mime_types.empty())
+      return absl::nullopt;
+
+    settings->mime_types = std::move(mime_types);
+  }
 
   return settings;
 }
diff --git a/chrome/browser/enterprise/connectors/file_system/service_settings.h b/chrome/browser/enterprise/connectors/file_system/service_settings.h
index 335afe4..2bce7405 100644
--- a/chrome/browser/enterprise/connectors/file_system/service_settings.h
+++ b/chrome/browser/enterprise/connectors/file_system/service_settings.h
@@ -8,6 +8,7 @@
 #include <set>
 #include <string>
 
+#include "base/feature_list.h"
 #include "base/values.h"
 #include "chrome/browser/enterprise/connectors/common.h"
 #include "chrome/browser/enterprise/connectors/service_provider_config.h"
@@ -16,6 +17,9 @@
 
 namespace enterprise_connectors {
 
+// Experimental flag to enable or disable the file system connector.
+extern const base::Feature kFileSystemConnectorEnabled;
+
 // The settings for a report service obtained from a connector policy.
 class FileSystemServiceSettings {
  public:
@@ -26,6 +30,7 @@
   ~FileSystemServiceSettings();
 
   // Get the settings to apply. absl::nullopt implies no file system settings.
+  absl::optional<FileSystemSettings> GetGlobalSettings() const;
   absl::optional<FileSystemSettings> GetSettings(const GURL& url) const;
 
  private:
diff --git a/chrome/browser/enterprise/connectors/file_system/signin_experience.cc b/chrome/browser/enterprise/connectors/file_system/signin_experience.cc
index 23896d9..81c68de 100644
--- a/chrome/browser/enterprise/connectors/file_system/signin_experience.cc
+++ b/chrome/browser/enterprise/connectors/file_system/signin_experience.cc
@@ -4,11 +4,16 @@
 
 #include "chrome/browser/enterprise/connectors/file_system/signin_experience.h"
 
+#include "chrome/browser/enterprise/connectors/common.h"
+#include "chrome/browser/enterprise/connectors/connectors_service.h"
+#include "chrome/browser/enterprise/connectors/file_system/access_token_fetcher.h"
+#include "chrome/browser/enterprise/connectors/file_system/service_settings.h"
 #include "chrome/browser/enterprise/connectors/file_system/signin_confirmation_modal.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/grit/generated_resources.h"
+#include "content/public/browser/download_item_utils.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -39,10 +44,61 @@
   return browser->window()->GetNativeWindow();
 }
 
+namespace ec = enterprise_connectors;
+
+bool MimeTypeMatches(const std::set<std::string>& mime_types,
+                     const std::string& mime_type) {
+  return mime_types.count(ec::kWildcardMimeType) != 0 ||
+         mime_types.count(mime_type) != 0;
+}
+
+ec::ConnectorsService* GetConnectorsService(content::BrowserContext* context) {
+  if (!base::FeatureList::IsEnabled(ec::kFileSystemConnectorEnabled))
+    return nullptr;
+
+  // Check to see if the download item matches any rules.  If the URL of the
+  // download itself does not match then check the URL of site on which the
+  // download is hosted.
+  DCHECK(context);
+  return ec::ConnectorsServiceFactory::GetForBrowserContext(context);
+}
+
 }  // namespace
 
 namespace enterprise_connectors {
 
+absl::optional<FileSystemSettings> GetFileSystemSettings(Profile* profile) {
+  auto* service = GetConnectorsService(profile);
+  if (!service)
+    return absl::nullopt;
+  return service->GetFileSystemGlobalSettings(
+      FileSystemConnector::SEND_DOWNLOAD_TO_CLOUD);
+}
+
+absl::optional<FileSystemSettings> GetFileSystemSettings(
+    download::DownloadItem* download_item) {
+  auto* context = content::DownloadItemUtils::GetBrowserContext(download_item);
+  auto* service = GetConnectorsService(context);
+  if (!service)
+    return absl::nullopt;
+
+  auto settings = service->GetFileSystemSettings(
+      download_item->GetURL(), FileSystemConnector::SEND_DOWNLOAD_TO_CLOUD);
+  if (settings.has_value() &&
+      MimeTypeMatches(settings->mime_types, download_item->GetMimeType())) {
+    return settings;
+  }
+
+  settings = service->GetFileSystemSettings(
+      download_item->GetTabUrl(), FileSystemConnector::SEND_DOWNLOAD_TO_CLOUD);
+  if (settings.has_value() &&
+      MimeTypeMatches(settings->mime_types, download_item->GetMimeType())) {
+    return settings;
+  }
+
+  return absl::nullopt;
+}
+
 void OnConfirmationModalClosed(gfx::NativeWindow context,
                                content::BrowserContext* browser_context,
                                const FileSystemSettings& settings,
@@ -65,7 +121,7 @@
   widget->Show();
 }
 
-void StartSigninExperienceForDownloadItem(
+void StartFileSystemConnectorSigninExperienceForDownloadItem(
     content::WebContents* web_contents,
     const FileSystemSettings& settings,
     AuthorizationCompletedCallback callback) {
@@ -75,6 +131,10 @@
   DCHECK_EQ(settings.service_provider, kBoxProviderName);
   std::u16string provider =
       l10n_util::GetStringUTF16(IDS_FILE_SYSTEM_CONNECTOR_BOX);
+
+  base::OnceCallback<void(bool)> confirmed_to_sign_in = base::BindOnce(
+      &OnConfirmationModalClosed, context, web_contents->GetBrowserContext(),
+      settings, std::move(callback));
   FileSystemConfirmationModal::Show(
       context,
       l10n_util::GetStringFUTF16(
@@ -85,9 +145,61 @@
           IDS_FILE_SYSTEM_CONNECTOR_SIGNIN_REQUIRED_CANCEL_BUTTON),
       l10n_util::GetStringUTF16(
           IDS_FILE_SYSTEM_CONNECTOR_SIGNIN_REQUIRED_ACCEPT_BUTTON),
-      base::BindOnce(&OnConfirmationModalClosed, context,
-                     web_contents->GetBrowserContext(), settings,
-                     std::move(callback)));
+      std::move(confirmed_to_sign_in));
+}
+
+void OnConfirmationModalClosedForSettingsPage(
+    gfx::NativeWindow context,
+    content::BrowserContext* browser_context,
+    const FileSystemSettings& settings,
+    base::OnceCallback<void(bool)> settings_page_callback,
+    bool user_confirmed_to_proceed) {
+  AuthorizationCompletedCallback converted_cb = base::BindOnce(
+      [](base::OnceCallback<void(bool)> cb,
+         const GoogleServiceAuthError& status, const std::string& access_token,
+         const std::string& refresh_token) {
+        std::move(cb).Run(status.state() ==
+                          GoogleServiceAuthError::State::NONE);
+      },
+      std::move(settings_page_callback));
+  OnConfirmationModalClosed(context, browser_context, settings,
+                            std::move(converted_cb), user_confirmed_to_proceed);
+}
+
+void StartFileSystemConnectorSigninExperienceForSettingsPage(
+    Profile* profile,
+    base::OnceCallback<void(bool)> callback) {
+  gfx::NativeWindow context = FindMostRelevantContextWindow(nullptr);
+  DCHECK(context);
+
+  auto settings = GetFileSystemSettings(profile);
+  if (!settings.has_value())
+    return std::move(callback).Run(false);
+
+  DCHECK_EQ(settings->service_provider, kBoxProviderName);
+  std::u16string provider =
+      l10n_util::GetStringUTF16(IDS_FILE_SYSTEM_CONNECTOR_BOX);
+
+  base::OnceCallback<void(bool)> confirmed_to_sign_in =
+      base::BindOnce(&OnConfirmationModalClosedForSettingsPage, context,
+                     profile, settings.value(), std::move(callback));
+  FileSystemConfirmationModal::Show(
+      context,
+      l10n_util::GetStringFUTF16(IDS_FILE_SYSTEM_CONNECTOR_SIGNIN_CONFIRM_TITLE,
+                                 provider),
+      l10n_util::GetStringUTF16(
+          IDS_FILE_SYSTEM_CONNECTOR_SIGNIN_CONFIRM_MESSAGE),
+      l10n_util::GetStringUTF16(
+          IDS_FILE_SYSTEM_CONNECTOR_SIGNIN_CONFIRM_CANCEL_BUTTON),
+      l10n_util::GetStringUTF16(
+          IDS_FILE_SYSTEM_CONNECTOR_SIGNIN_CONFIRM_ACCEPT_BUTTON),
+      std::move(confirmed_to_sign_in));
+}
+
+bool ClearFileSystemConnectorLinkedAccount(const FileSystemSettings& settings,
+                                           PrefService* prefs) {
+  CHECK_EQ(settings.service_provider, kBoxProviderName);
+  return ClearFileSystemOAuth2Tokens(prefs, kBoxProviderName);
 }
 
 void ReturnCancellation(AuthorizationCompletedCallback callback) {
diff --git a/chrome/browser/enterprise/connectors/file_system/signin_experience.h b/chrome/browser/enterprise/connectors/file_system/signin_experience.h
index 43e24790..0b860f25 100644
--- a/chrome/browser/enterprise/connectors/file_system/signin_experience.h
+++ b/chrome/browser/enterprise/connectors/file_system/signin_experience.h
@@ -14,14 +14,33 @@
 
 namespace enterprise_connectors {
 
+// Retrieve FileSystemSettings for |profile|; null if connector is disabled.
+absl::optional<FileSystemSettings> GetFileSystemSettings(Profile* profile);
+
+// Retrieve FileSystemSettings for |download_item|, considering its associated
+// profile and originating URL; null if connector is disabled.
+absl::optional<FileSystemSettings> GetFileSystemSettings(
+    download::DownloadItem* download_item);
+
 using AuthorizationCompletedCallback =
     FileSystemSigninDialogDelegate::AuthorizationCompletedCallback;
 
-void StartSigninExperienceForDownloadItem(
+// Start the sign in experience as triggered by a download item.
+void StartFileSystemConnectorSigninExperienceForDownloadItem(
     content::WebContents* web_contents,
     const FileSystemSettings& settings,
     AuthorizationCompletedCallback callback);
 
+// Start the sign in experience as triggered by the settings page.
+void StartFileSystemConnectorSigninExperienceForSettingsPage(
+    Profile* profile,
+    base::OnceCallback<void(bool)> callback);
+
+// Clear authentication tokens.
+bool ClearFileSystemConnectorLinkedAccount(const FileSystemSettings& settings,
+                                           PrefService* prefs);
+
+// Run |callback| with a GoogleServiceAuthError that indicates cancellation.
 void ReturnCancellation(AuthorizationCompletedCallback callback);
 
 }  // namespace enterprise_connectors
diff --git a/chrome/browser/enterprise/reporting/extension_info.cc b/chrome/browser/enterprise/reporting/extension_info.cc
index 817a7e1..76f4598 100644
--- a/chrome/browser/enterprise/reporting/extension_info.cc
+++ b/chrome/browser/enterprise/reporting/extension_info.cc
@@ -110,6 +110,8 @@
       return em::Extension_ExtensionType_TYPE_PLATFORM_APP;
     case extensions::Manifest::TYPE_LOGIN_SCREEN_EXTENSION:
       return em::Extension_ExtensionType_TYPE_LOGIN_SCREEN_EXTENSION;
+    case extensions::Manifest::TYPE_CHROMEOS_SYSTEM_EXTENSION:
+      return em::Extension_ExtensionType_TYPE_CHROMEOS_SYSTEM_EXTENSION;
     case extensions::Manifest::NUM_LOAD_TYPES:
       NOTREACHED();
       return em::Extension_ExtensionType_TYPE_UNKNOWN;
diff --git a/chrome/browser/extensions/api/developer_private/extension_info_generator.cc b/chrome/browser/extensions/api/developer_private/extension_info_generator.cc
index 9a85f72..eae8954 100644
--- a/chrome/browser/extensions/api/developer_private/extension_info_generator.cc
+++ b/chrome/browser/extensions/api/developer_private/extension_info_generator.cc
@@ -100,6 +100,9 @@
     case Manifest::TYPE_SHARED_MODULE:
       type = developer::EXTENSION_TYPE_SHARED_MODULE;
       break;
+    case Manifest::TYPE_CHROMEOS_SYSTEM_EXTENSION:
+      type = developer::EXTENSION_TYPE_EXTENSION;
+      break;
     default:
       NOTREACHED();
   }
diff --git a/chrome/browser/extensions/content_script_apitest.cc b/chrome/browser/extensions/content_script_apitest.cc
index 8132538..a285dea 100644
--- a/chrome/browser/extensions/content_script_apitest.cc
+++ b/chrome/browser/extensions/content_script_apitest.cc
@@ -597,10 +597,9 @@
   void SetUpInProcessBrowserTestFixture() override {
     ExtensionApiTest::SetUpInProcessBrowserTestFixture();
 
-    ON_CALL(policy_provider_, IsInitializationComplete(testing::_))
-        .WillByDefault(testing::Return(true));
-    ON_CALL(policy_provider_, IsFirstPolicyLoadComplete(testing::_))
-        .WillByDefault(testing::Return(true));
+    policy_provider_.SetDefaultReturns(
+        /*is_initialization_complete_return=*/true,
+        /*is_first_policy_load_complete_return=*/true);
 
     policy::BrowserPolicyConnector::SetPolicyProviderForTesting(
         &policy_provider_);
diff --git a/chrome/browser/extensions/content_verifier_browsertest.cc b/chrome/browser/extensions/content_verifier_browsertest.cc
index b808c136..8ce077ab 100644
--- a/chrome/browser/extensions/content_verifier_browsertest.cc
+++ b/chrome/browser/extensions/content_verifier_browsertest.cc
@@ -832,10 +832,9 @@
   void SetUpInProcessBrowserTestFixture() override {
     ContentVerifierTest::SetUpInProcessBrowserTestFixture();
 
-    ON_CALL(policy_provider_, IsInitializationComplete(testing::_))
-        .WillByDefault(testing::Return(true));
-    ON_CALL(policy_provider_, IsFirstPolicyLoadComplete(testing::_))
-        .WillByDefault(testing::Return(true));
+    policy_provider_.SetDefaultReturns(
+        /*is_initialization_complete_return=*/true,
+        /*is_first_policy_load_complete_return=*/true);
 
     policy::BrowserPolicyConnector::SetPolicyProviderForTesting(
         &policy_provider_);
diff --git a/chrome/browser/extensions/corb_and_cors_extension_browsertest.cc b/chrome/browser/extensions/corb_and_cors_extension_browsertest.cc
index ec01c1f..a76198e 100644
--- a/chrome/browser/extensions/corb_and_cors_extension_browsertest.cc
+++ b/chrome/browser/extensions/corb_and_cors_extension_browsertest.cc
@@ -175,10 +175,9 @@
   CorbAndCorsExtensionBrowserTest() = default;
 
   void SetUpInProcessBrowserTestFixture() override {
-    ON_CALL(policy_provider_, IsInitializationComplete(testing::_))
-        .WillByDefault(testing::Return(true));
-    ON_CALL(policy_provider_, IsFirstPolicyLoadComplete(testing::_))
-        .WillByDefault(testing::Return(true));
+    policy_provider_.SetDefaultReturns(
+        /*is_initialization_complete_return=*/true,
+        /*is_first_policy_load_complete_return=*/true);
     policy_provider_.SetAutoRefresh();
     policy::BrowserPolicyConnector::SetPolicyProviderForTesting(
         &policy_provider_);
diff --git a/chrome/browser/extensions/extension_management_constants.cc b/chrome/browser/extensions/extension_management_constants.cc
index d6f34b8..438c1e8 100644
--- a/chrome/browser/extensions/extension_management_constants.cc
+++ b/chrome/browser/extensions/extension_management_constants.cc
@@ -41,14 +41,15 @@
 const char kDefaultUnpinned[] = "default_unpinned";
 
 const AllowedTypesMapEntry kAllowedTypesMap[] = {
-  { "extension",           Manifest::TYPE_EXTENSION },
-  { "theme",               Manifest::TYPE_THEME },
-  { "user_script",         Manifest::TYPE_USER_SCRIPT },
-  { "hosted_app",          Manifest::TYPE_HOSTED_APP },
-  { "legacy_packaged_app", Manifest::TYPE_LEGACY_PACKAGED_APP },
-  { "platform_app",        Manifest::TYPE_PLATFORM_APP },
-  // TODO(binjin): Add shared_module type here and update ExtensionAllowedTypes
-  // policy.
+    {"extension", Manifest::TYPE_EXTENSION},
+    {"theme", Manifest::TYPE_THEME},
+    {"user_script", Manifest::TYPE_USER_SCRIPT},
+    {"hosted_app", Manifest::TYPE_HOSTED_APP},
+    {"legacy_packaged_app", Manifest::TYPE_LEGACY_PACKAGED_APP},
+    {"platform_app", Manifest::TYPE_PLATFORM_APP},
+    {"chromeos_system_extension", Manifest::TYPE_CHROMEOS_SYSTEM_EXTENSION},
+    // TODO(binjin): Add shared_module type here and update
+    // ExtensionAllowedTypes policy.
 };
 
 const size_t kAllowedTypesMapSize = base::size(kAllowedTypesMap);
diff --git a/chrome/browser/extensions/extension_with_management_policy_apitest.cc b/chrome/browser/extensions/extension_with_management_policy_apitest.cc
index 6c50dd9d..0631ad3 100644
--- a/chrome/browser/extensions/extension_with_management_policy_apitest.cc
+++ b/chrome/browser/extensions/extension_with_management_policy_apitest.cc
@@ -16,10 +16,9 @@
   embedded_test_server()->RegisterRequestMonitor(base::BindRepeating(
       &ExtensionApiTestWithManagementPolicy::MonitorRequestHandler,
       base::Unretained(this)));
-  ON_CALL(policy_provider_, IsInitializationComplete(testing::_))
-      .WillByDefault(testing::Return(true));
-  ON_CALL(policy_provider_, IsFirstPolicyLoadComplete(testing::_))
-      .WillByDefault(testing::Return(true));
+  policy_provider_.SetDefaultReturns(
+      /*is_initialization_complete_return=*/true,
+      /*is_first_policy_load_complete_return=*/true);
   policy_provider_.SetAutoRefresh();
   policy::BrowserPolicyConnector::SetPolicyProviderForTesting(
       &policy_provider_);
diff --git a/chrome/browser/extensions/extension_with_management_policy_apitest.h b/chrome/browser/extensions/extension_with_management_policy_apitest.h
index 1e8223d0..baea1d8 100644
--- a/chrome/browser/extensions/extension_with_management_policy_apitest.h
+++ b/chrome/browser/extensions/extension_with_management_policy_apitest.h
@@ -29,7 +29,7 @@
   void SetUpOnMainThread() override;
 
  protected:
-  policy::MockConfigurationPolicyProvider policy_provider_;
+  testing::NiceMock<policy::MockConfigurationPolicyProvider> policy_provider_;
   bool BrowsedTo(const std::string& test_host);
   void ClearRequestLog();
   void MonitorRequestHandler(const net::test_server::HttpRequest& request);
diff --git a/chrome/browser/extensions/forced_extensions/force_installed_test_base.cc b/chrome/browser/extensions/forced_extensions/force_installed_test_base.cc
index 8d2cfe8a..851eca9 100644
--- a/chrome/browser/extensions/forced_extensions/force_installed_test_base.cc
+++ b/chrome/browser/extensions/forced_extensions/force_installed_test_base.cc
@@ -37,10 +37,9 @@
 ForceInstalledTestBase::~ForceInstalledTestBase() = default;
 
 void ForceInstalledTestBase::SetUp() {
-  ON_CALL(policy_provider_, IsInitializationComplete(testing::_))
-      .WillByDefault(testing::Return(false));
-  ON_CALL(policy_provider_, IsFirstPolicyLoadComplete(testing::_))
-      .WillByDefault(testing::Return(false));
+  policy_provider_.SetDefaultReturns(
+      /*is_initialization_complete_return=*/false,
+      /*is_first_policy_load_complete_return=*/false);
 
   auto policy_service = std::make_unique<policy::PolicyServiceImpl>(
       std::vector<policy::ConfigurationPolicyProvider*>{&policy_provider_});
diff --git a/chrome/browser/extensions/forced_extensions/force_installed_test_base.h b/chrome/browser/extensions/forced_extensions/force_installed_test_base.h
index 8a9d714..9308af6 100644
--- a/chrome/browser/extensions/forced_extensions/force_installed_test_base.h
+++ b/chrome/browser/extensions/forced_extensions/force_installed_test_base.h
@@ -83,7 +83,7 @@
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
 
  private:
-  policy::MockConfigurationPolicyProvider policy_provider_;
+  testing::NiceMock<policy::MockConfigurationPolicyProvider> policy_provider_;
   std::unique_ptr<TestingProfileManager> profile_manager_;
   TestingProfile* profile_;
   sync_preferences::TestingPrefServiceSyncable* prefs_;
diff --git a/chrome/browser/extensions/standard_management_policy_provider.cc b/chrome/browser/extensions/standard_management_policy_provider.cc
index 326579a5..fe478de0 100644
--- a/chrome/browser/extensions/standard_management_policy_provider.cc
+++ b/chrome/browser/extensions/standard_management_policy_provider.cc
@@ -115,7 +115,8 @@
     case Manifest::TYPE_LEGACY_PACKAGED_APP:
     case Manifest::TYPE_PLATFORM_APP:
     case Manifest::TYPE_SHARED_MODULE:
-    case Manifest::TYPE_LOGIN_SCREEN_EXTENSION: {
+    case Manifest::TYPE_LOGIN_SCREEN_EXTENSION:
+    case Manifest::TYPE_CHROMEOS_SYSTEM_EXTENSION: {
       if (!settings_->IsAllowedManifestType(extension->GetType(),
                                             extension->id()))
         return ReturnLoadError(extension, error);
diff --git a/chrome/browser/extensions/updater/update_service_browsertest.cc b/chrome/browser/extensions/updater/update_service_browsertest.cc
index 88e6ca3..fca6609 100644
--- a/chrome/browser/extensions/updater/update_service_browsertest.cc
+++ b/chrome/browser/extensions/updater/update_service_browsertest.cc
@@ -404,10 +404,9 @@
   void SetUpInProcessBrowserTestFixture() override {
     ExtensionUpdateClientBaseTest::SetUpInProcessBrowserTestFixture();
 
-    ON_CALL(policy_provider_, IsInitializationComplete(testing::_))
-        .WillByDefault(testing::Return(true));
-    ON_CALL(policy_provider_, IsFirstPolicyLoadComplete(testing::_))
-        .WillByDefault(testing::Return(true));
+    policy_provider_.SetDefaultReturns(
+        /*is_initialization_complete_return=*/true,
+        /*is_first_policy_load_complete_return=*/true);
 
     policy::BrowserPolicyConnector::SetPolicyProviderForTesting(
         &policy_provider_);
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 5e3f802..69c390d 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -4444,6 +4444,11 @@
     "expiry_milestone": 100
   },
   {
+    "name": "performant-split-view-resizing",
+    "owners": [ "dandersson", "riomat" ],
+    "expiry_milestone": 100
+  },
+  {
     "name": "permission-chip",
     "owners": [ "bsep", "engedy", "olesiamarukhno" ],
     "expiry_milestone": 94
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 273053d..b469bd4 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -4985,6 +4985,11 @@
 const char kNearbySharingWebRtcDescription[] =
     "Enables use of WebRTC in Nearby Share.";
 
+const char kPerformantSplitViewResizing[] = "Performant Split View Resizing";
+const char kPerformantSplitViewResizingDescription[] =
+    "If enabled, windows may be moved instead of scaled when resizing split "
+    "view in tablet mode.";
+
 const char kPhoneHubCameraRollName[] = "Camera Roll in Phone Hub";
 const char kPhoneHubCameraRollDescription[] =
     "Enables the Camera Roll feature in Phone Hub, which allows users to "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index bffd4e9..4fe5daecd 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -2877,6 +2877,9 @@
 extern const char kNearbySharingWebRtcName[];
 extern const char kNearbySharingWebRtcDescription[];
 
+extern const char kPerformantSplitViewResizing[];
+extern const char kPerformantSplitViewResizingDescription[];
+
 extern const char kPhoneHubCameraRollName[];
 extern const char kPhoneHubCameraRollDescription[];
 
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFieldTrialParameter.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFieldTrialParameter.java
index f742bfc2..0437c22 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFieldTrialParameter.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFieldTrialParameter.java
@@ -8,7 +8,7 @@
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.annotations.CheckDiscard;
-import org.chromium.base.annotations.RemovableInRelease;
+import org.chromium.build.BuildConfig;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 
 import java.lang.annotation.Retention;
@@ -55,8 +55,9 @@
         registerInstance();
     }
 
-    @RemovableInRelease
     private void registerInstance() {
+        if (!BuildConfig.ENABLE_ASSERTS) return;
+
         if (sAllInstances == null) {
             sAllInstances = new HashSet<>();
         }
diff --git a/chrome/browser/history_clusters/history_clusters_tab_helper_unittest.cc b/chrome/browser/history_clusters/history_clusters_tab_helper_unittest.cc
index e363a4f..7c33fb9 100644
--- a/chrome/browser/history_clusters/history_clusters_tab_helper_unittest.cc
+++ b/chrome/browser/history_clusters/history_clusters_tab_helper_unittest.cc
@@ -47,12 +47,6 @@
   base::OnceCallback<void()> callback_;
 };
 
-// Returns a Time that's `seconds` seconds after Windows epoch.
-base::Time IntToTime(int seconds) {
-  return base::Time::FromDeltaSinceWindowsEpoch(
-      base::TimeDelta::FromSeconds(seconds));
-}
-
 class HistoryClustersTabHelperTest : public ChromeRenderViewHostTestHarness {
  protected:
   HistoryClustersTabHelperTest() = default;
@@ -92,13 +86,12 @@
     return history_clusters_service_test_api_->GetVisits();
   }
 
-  void AddToHistory(const GURL& url,
-                    std::u16string title = u"Title",
-                    base::Time time = IntToTime(0)) {
+  void AddToHistory(const GURL& url, int time_seconds) {
     history::HistoryAddPageArgs add_page_args;
     add_page_args.url = url;
-    add_page_args.title = title;
-    add_page_args.time = time;
+    add_page_args.title = u"Fake Title";
+    add_page_args.time = base::Time::FromDeltaSinceWindowsEpoch(
+        base::TimeDelta::FromSeconds(time_seconds));
     history_service_->AddPage(add_page_args);
   }
 
@@ -149,7 +142,7 @@
 // 2) `WebContentsDestroyed()` is invoked.
 // Then: 0 visits should be committed.
 TEST_F(HistoryClustersTabHelperTest, NavigationWith0HistoryVisits) {
-  AddToHistory(GURL{"https://google.com"});
+  AddToHistory(GURL{"https://google.com"}, 1);
   helper_->OnUpdatedHistoryForNavigation(0, GURL{"https://github.com"});
   history::BlockUntilHistoryProcessesPendingRequests(history_service_);
   DeleteContents();
@@ -163,7 +156,7 @@
 // 2) `WebContentsDestroyed()` is invoked.
 // Then: 1 visit should be committed w/o `duration_since_last_visit`.
 TEST_F(HistoryClustersTabHelperTest, NavigationWith1HistoryVisits) {
-  AddToHistory(GURL{"https://github.com"});
+  AddToHistory(GURL{"https://github.com"}, 1);
   helper_->OnUpdatedHistoryForNavigation(0, GURL{"https://github.com"});
   history::BlockUntilHistoryProcessesPendingRequests(history_service_);
   EXPECT_TRUE(GetVisits().empty());
@@ -185,8 +178,8 @@
 // 2) `WebContentsDestroyed()` is invoked.
 // Then: 1 visit should be committed.
 TEST_F(HistoryClustersTabHelperTest, NavigationWith2HistoryVisits) {
-  AddToHistory(GURL{"https://github.com"}, u"Title", IntToTime(19));
-  AddToHistory(GURL{"https://github.com"}, u"Title", IntToTime(23));
+  AddToHistory(GURL{"https://github.com"}, 19);
+  AddToHistory(GURL{"https://github.com"}, 23);
   helper_->OnUpdatedHistoryForNavigation(0, GURL{"https://github.com"});
   history::BlockUntilHistoryProcessesPendingRequests(history_service_);
   EXPECT_TRUE(GetVisits().empty());
@@ -225,10 +218,10 @@
 // 3) `WebContentsDestroyed()` is invoked.
 // Then: 2 visits should be committed.
 TEST_F(HistoryClustersTabHelperTest, TwoNavigationsWith2HistoryVisits) {
-  AddToHistory(GURL{"https://github.com"});
-  AddToHistory(GURL{"https://github.com"});
-  AddToHistory(GURL{"https://google.com"});
-  AddToHistory(GURL{"https://google.com"});
+  AddToHistory(GURL{"https://github.com"}, 1);
+  AddToHistory(GURL{"https://github.com"}, 2);
+  AddToHistory(GURL{"https://google.com"}, 3);
+  AddToHistory(GURL{"https://google.com"}, 4);
   helper_->OnUpdatedHistoryForNavigation(0, GURL{"https://github.com"});
   history::BlockUntilHistoryProcessesPendingRequests(history_service_);
   EXPECT_TRUE(GetVisits().empty());
@@ -240,8 +233,8 @@
 
   DeleteContents();
   ASSERT_EQ(GetVisits().size(), 2u);
-  EXPECT_EQ(GetVisits()[0].url_row.url(), GURL{"https://github.com"});
-  EXPECT_EQ(GetVisits()[1].url_row.url(), GURL{"https://google.com"});
+  EXPECT_EQ(GetVisits()[0].url_row.url(), GURL{"https://google.com"});
+  EXPECT_EQ(GetVisits()[1].url_row.url(), GURL{"https://github.com"});
 }
 
 // For the remaining tests, all navigations will have at least 1 history visit.
@@ -253,7 +246,7 @@
 //    resolved.
 // Then: 0 visits should be committed.
 TEST_F(HistoryClustersTabHelperTest, HistoryResolvedAfterDestroy) {
-  AddToHistory(GURL{"https://github.com"});
+  AddToHistory(GURL{"https://github.com"}, 1);
   helper_->OnUpdatedHistoryForNavigation(0, GURL{"https://github.com"});
   DeleteContents();
   history::BlockUntilHistoryProcessesPendingRequests(history_service_);
@@ -268,8 +261,8 @@
 // 3) `WebContentsDestroyed()` is invoked.
 // Then: 2 visits should be committed.
 TEST_F(HistoryClustersTabHelperTest, HistoryResolvedAfter2ndNavigation) {
-  AddToHistory(GURL{"https://google.com"});
-  AddToHistory(GURL{"https://github.com"});
+  AddToHistory(GURL{"https://google.com"}, 1);
+  AddToHistory(GURL{"https://github.com"}, 2);
   helper_->OnUpdatedHistoryForNavigation(0, GURL{"https://google.com"});
   helper_->OnUpdatedHistoryForNavigation(1, GURL{"https://github.com"});
 
@@ -282,10 +275,10 @@
   AddBookmark(GURL{"https://github.com"});
   auto visits = GetVisits();
   ASSERT_EQ(visits.size(), 2u);
-  EXPECT_EQ(visits[0].url_row.url(), GURL{"https://google.com"});
-  EXPECT_TRUE(visits[0].context_annotations.is_new_bookmark);
-  EXPECT_EQ(visits[1].url_row.url(), GURL{"https://github.com"});
-  EXPECT_FALSE(visits[1].context_annotations.is_new_bookmark);
+  EXPECT_EQ(visits[0].url_row.url(), GURL{"https://github.com"});
+  EXPECT_FALSE(visits[0].context_annotations.is_new_bookmark);
+  EXPECT_EQ(visits[1].url_row.url(), GURL{"https://google.com"});
+  EXPECT_TRUE(visits[1].context_annotations.is_new_bookmark);
 }
 
 // History -> copy -> history resolve -> history -> history -> copy -> destroy
@@ -301,9 +294,9 @@
 // Then: 3 visits should be committed; the 1st and 3rd should have
 //       `omnibox_url_copied` true.
 TEST_F(HistoryClustersTabHelperTest, UrlsCopied) {
-  AddToHistory(GURL{"https://github.com"});
-  AddToHistory(GURL{"https://google.com"});
-  AddToHistory(GURL{"https://gmail.com"});
+  AddToHistory(GURL{"https://github.com"}, 1);
+  AddToHistory(GURL{"https://google.com"}, 2);
+  AddToHistory(GURL{"https://gmail.com"}, 3);
   helper_->OnUpdatedHistoryForNavigation(0, GURL{"https://github.com"});
   helper_->OnOmniboxUrlCopied();
   history::BlockUntilHistoryProcessesPendingRequests(history_service_);
@@ -312,21 +305,23 @@
   helper_->OnUpdatedHistoryForNavigation(1, GURL{"https://google.com"});
   history::BlockUntilHistoryProcessesPendingRequests(history_service_);
   ASSERT_EQ(GetVisits().size(), 1u);
+  EXPECT_EQ(GetVisits()[0].url_row.url(), GURL{"https://github.com"});
   EXPECT_TRUE(GetVisits()[0].context_annotations.omnibox_url_copied);
 
   helper_->OnUpdatedHistoryForNavigation(2, GURL{"https://gmail.com"});
   history::BlockUntilHistoryProcessesPendingRequests(history_service_);
   helper_->OnOmniboxUrlCopied();
   ASSERT_EQ(GetVisits().size(), 2u);
-  EXPECT_FALSE(GetVisits()[1].context_annotations.omnibox_url_copied);
+  EXPECT_EQ(GetVisits()[0].url_row.url(), GURL{"https://google.com"});
+  EXPECT_FALSE(GetVisits()[0].context_annotations.omnibox_url_copied);
 
   DeleteContents();
   ASSERT_EQ(GetVisits().size(), 3u);
-  EXPECT_EQ(GetVisits()[0].url_row.url(), GURL{"https://github.com"});
+  EXPECT_EQ(GetVisits()[0].url_row.url(), GURL{"https://gmail.com"});
   EXPECT_TRUE(GetVisits()[0].context_annotations.omnibox_url_copied);
   EXPECT_EQ(GetVisits()[1].url_row.url(), GURL{"https://google.com"});
   EXPECT_FALSE(GetVisits()[1].context_annotations.omnibox_url_copied);
-  EXPECT_EQ(GetVisits()[2].url_row.url(), GURL{"https://gmail.com"});
+  EXPECT_EQ(GetVisits()[2].url_row.url(), GURL{"https://github.com"});
   EXPECT_TRUE(GetVisits()[2].context_annotations.omnibox_url_copied);
 }
 
@@ -338,7 +333,7 @@
 // 4) `WebContentsDestroyed()` is invoked.
 // Then: 1 visit should be committed after step 3 w/ a `page_end_reason`.
 TEST_F(HistoryClustersTabHelperTest, NavigationWithUkmBeforeDestroy) {
-  AddToHistory(GURL{"https://github.com"});
+  AddToHistory(GURL{"https://github.com"}, 1);
   helper_->OnUpdatedHistoryForNavigation(0, GURL{"https://github.com"});
   history::BlockUntilHistoryProcessesPendingRequests(history_service_);
   helper_->TagNavigationAsExpectingUkmNavigationComplete(0);
@@ -360,7 +355,7 @@
 // 4) `OnUkmNavigationComplete()` is invoked.
 // Then: 1 visit should be committed after step 4 w/ a `page_end_reason`.
 TEST_F(HistoryClustersTabHelperTest, NavigationWithUkmAfterDestroy) {
-  AddToHistory(GURL{"https://github.com"});
+  AddToHistory(GURL{"https://github.com"}, 1);
   helper_->OnUpdatedHistoryForNavigation(0, GURL{"https://github.com"});
   history::BlockUntilHistoryProcessesPendingRequests(history_service_);
   helper_->TagNavigationAsExpectingUkmNavigationComplete(0);
@@ -393,7 +388,7 @@
 // Then: 1 visit should be committed after step 3 w/ a `page_end_reason`.
 TEST_F(HistoryClustersTabHelperTest,
        NavigationAfterUkmExpectAndWithUkmBeforeDestroy) {
-  AddToHistory(GURL{"https://github.com"});
+  AddToHistory(GURL{"https://github.com"}, 1);
   helper_->TagNavigationAsExpectingUkmNavigationComplete(0);
   helper_->OnUpdatedHistoryForNavigation(0, GURL{"https://github.com"});
   history::BlockUntilHistoryProcessesPendingRequests(history_service_);
@@ -417,7 +412,7 @@
 // Then: 1 visit should be committed after step 4 w/ a `page_end_reason`.
 TEST_F(HistoryClustersTabHelperTest,
        NavigationWithUkmBeforeDestroyAndHistoryResolvedAfterDestroy) {
-  AddToHistory(GURL{"https://github.com"});
+  AddToHistory(GURL{"https://github.com"}, 1);
   helper_->OnUpdatedHistoryForNavigation(0, GURL{"https://github.com"});
   helper_->TagNavigationAsExpectingUkmNavigationComplete(0);
   AddBookmark(GURL{"https://github.com"});
@@ -454,8 +449,8 @@
 //       `page_end_reason`.
 TEST_F(HistoryClustersTabHelperTest,
        TwoNavigationsWith1stUkmBefore2ndNavigation) {
-  AddToHistory(GURL{"https://google.com"});
-  AddToHistory(GURL{"https://github.com"});
+  AddToHistory(GURL{"https://google.com"}, 1);
+  AddToHistory(GURL{"https://github.com"}, 2);
   helper_->OnUpdatedHistoryForNavigation(0, GURL{"https://github.com"});
   history::BlockUntilHistoryProcessesPendingRequests(history_service_);
   helper_->TagNavigationAsExpectingUkmNavigationComplete(0);
@@ -474,11 +469,11 @@
 
   DeleteContents();
   ASSERT_EQ(GetVisits().size(), 2u);
-  EXPECT_EQ(GetVisits()[0].url_row.url(), GURL{"https://google.com"});
-  EXPECT_EQ(GetVisits()[0].context_annotations.page_end_reason, 0);
-  EXPECT_EQ(GetVisits()[1].url_row.url(), GURL{"https://github.com"});
-  EXPECT_EQ(GetVisits()[1].context_annotations.page_end_reason,
+  EXPECT_EQ(GetVisits()[0].url_row.url(), GURL{"https://github.com"});
+  EXPECT_EQ(GetVisits()[0].context_annotations.page_end_reason,
             page_load_metrics::PageEndReason::END_OTHER);
+  EXPECT_EQ(GetVisits()[1].url_row.url(), GURL{"https://google.com"});
+  EXPECT_EQ(GetVisits()[1].context_annotations.page_end_reason, 0);
 }
 
 // Expect History -> Expect UKM 1 -> history -> UKM 1 -> destroy
@@ -493,8 +488,8 @@
 //       `page_end_reason`.
 TEST_F(HistoryClustersTabHelperTest,
        TwoNavigationsWith1stUkmAfter2ndNavigation) {
-  AddToHistory(GURL{"https://google.com"});
-  AddToHistory(GURL{"https://github.com"});
+  AddToHistory(GURL{"https://google.com"}, 1);
+  AddToHistory(GURL{"https://github.com"}, 2);
   helper_->OnUpdatedHistoryForNavigation(0, GURL{"https://github.com"});
   history::BlockUntilHistoryProcessesPendingRequests(history_service_);
   helper_->TagNavigationAsExpectingUkmNavigationComplete(0);
@@ -511,11 +506,11 @@
 
   DeleteContents();
   ASSERT_EQ(GetVisits().size(), 2u);
-  EXPECT_EQ(GetVisits()[0].url_row.url(), GURL{"https://google.com"});
-  EXPECT_EQ(GetVisits()[0].context_annotations.page_end_reason, 0);
-  EXPECT_EQ(GetVisits()[1].url_row.url(), GURL{"https://github.com"});
-  EXPECT_EQ(GetVisits()[1].context_annotations.page_end_reason,
+  EXPECT_EQ(GetVisits()[0].url_row.url(), GURL{"https://github.com"});
+  EXPECT_EQ(GetVisits()[0].context_annotations.page_end_reason,
             page_load_metrics::PageEndReason::END_OTHER);
+  EXPECT_EQ(GetVisits()[1].url_row.url(), GURL{"https://google.com"});
+  EXPECT_EQ(GetVisits()[1].context_annotations.page_end_reason, 0);
 }
 
 // Expect History -> Expect UKM 2 -> history -> destroy -> UKM 2
@@ -529,8 +524,8 @@
 // Then: 2 visits should be committed after steps 2 and 5; the 2nd should have a
 //       `page_end_reason`.
 TEST_F(HistoryClustersTabHelperTest, TwoNavigations2ndUkmBefore2ndNavigation) {
-  AddToHistory(GURL{"https://google.com"});
-  AddToHistory(GURL{"https://github.com"});
+  AddToHistory(GURL{"https://google.com"}, 1);
+  AddToHistory(GURL{"https://github.com"}, 2);
   helper_->OnUpdatedHistoryForNavigation(0, GURL{"https://github.com"});
   history::BlockUntilHistoryProcessesPendingRequests(history_service_);
   EXPECT_TRUE(GetVisits().empty());
@@ -556,11 +551,11 @@
 
   DeleteContents();
   ASSERT_EQ(GetVisits().size(), 2u);
-  EXPECT_EQ(GetVisits()[0].url_row.url(), GURL{"https://google.com"});
-  EXPECT_EQ(GetVisits()[0].context_annotations.page_end_reason,
+  EXPECT_EQ(GetVisits()[0].url_row.url(), GURL{"https://github.com"});
+  EXPECT_EQ(GetVisits()[0].context_annotations.page_end_reason, 0);
+  EXPECT_EQ(GetVisits()[1].url_row.url(), GURL{"https://google.com"});
+  EXPECT_EQ(GetVisits()[1].context_annotations.page_end_reason,
             page_load_metrics::PageEndReason::END_OTHER);
-  EXPECT_EQ(GetVisits()[1].url_row.url(), GURL{"https://github.com"});
-  EXPECT_EQ(GetVisits()[1].context_annotations.page_end_reason, 0);
 }
 
 }  // namespace
diff --git a/chrome/browser/metrics/extensions_metrics_provider.cc b/chrome/browser/metrics/extensions_metrics_provider.cc
index 30b1c9f..8e0fcaf 100644
--- a/chrome/browser/metrics/extensions_metrics_provider.cc
+++ b/chrome/browser/metrics/extensions_metrics_provider.cc
@@ -150,6 +150,9 @@
       return ExtensionInstallProto::SHARED_MODULE;
     case Manifest::TYPE_LOGIN_SCREEN_EXTENSION:
       return ExtensionInstallProto::LOGIN_SCREEN_EXTENSION;
+    case Manifest::TYPE_CHROMEOS_SYSTEM_EXTENSION:
+      // TODO(mgawad): introduce new CHROMEOS_SYSTEM_EXTENSION type.
+      return ExtensionInstallProto::EXTENSION;
     case Manifest::NUM_LOAD_TYPES:
       NOTREACHED();
       // Fall through.
diff --git a/chrome/browser/metrics/power/power_metrics_reporter.cc b/chrome/browser/metrics/power/power_metrics_reporter.cc
index d1002c1df..eeb8fc8 100644
--- a/chrome/browser/metrics/power/power_metrics_reporter.cc
+++ b/chrome/browser/metrics/power/power_metrics_reporter.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
@@ -25,7 +26,6 @@
     "Power.BatteryDischargeRate2";
 constexpr const char* kBatteryDischargeModeHistogramName =
     "Power.BatteryDischargeMode";
-constexpr const char* kZeroWindowSuffix = ".ZeroWindow";
 constexpr const char* kBatterySamplingDelayHistogramName =
     "Power.BatterySamplingDelay";
 constexpr const char* kMainScreenBrightnessHistogramName =
@@ -49,6 +49,46 @@
       kOverflowBucket);
 }
 
+// Returns the scenario-specific suffix to use for metrics captured during an
+// interval described by |interval_data|.
+const char* GetScenarioSuffix(
+    const UsageScenarioDataStore::IntervalData& interval_data) {
+  // Important: The order of the conditions is important. See the full
+  // description of each scenario in the histograms.xml file.
+  if (interval_data.max_tab_count == 0)
+    return ".ZeroWindow";
+  if (interval_data.max_visible_window_count == 0)
+    return ".AllTabsHidden";
+  if (!interval_data.time_capturing_video.is_zero())
+    return ".VideoCapture";
+  if (!interval_data.time_playing_video_full_screen_single_monitor.is_zero())
+    return ".FullscreenVideo";
+  if (!interval_data.time_playing_video_in_visible_tab.is_zero()) {
+    // Note: UKM data reveals that navigations are infrequent when a video is
+    // playing in fullscreen, when video is captured or when audio is playing.
+    // For that reason, there is no distinct suffix for navigation vs. no
+    // navigation in these cases.
+    if (interval_data.top_level_navigation_count == 0)
+      return ".EmbeddedVideo_NoNavigation";
+    return ".EmbeddedVideo_WithNavigation";
+  }
+  if (!interval_data.time_playing_audio.is_zero())
+    return ".Audio";
+  if (interval_data.top_level_navigation_count > 0)
+    return ".Navigation";
+  if (interval_data.user_interaction_count > 0)
+    return ".Interaction";
+  return ".Passive";
+}
+
+// Returns the histogram suffixes to use for metrics captured during an interval
+// described by |interval_data|.
+std::vector<const char*> GetSuffixes(
+    const UsageScenarioDataStore::IntervalData& interval_data) {
+  // Histograms are recorded without suffix and with a scenario-specific suffix.
+  return std::vector<const char*>{"", GetScenarioSuffix(interval_data)};
+}
+
 }  // namespace
 
 PowerMetricsReporter::PowerMetricsReporter(
@@ -97,46 +137,46 @@
                      /* scheduled_time=*/base::TimeTicks::Now()));
 }
 
-// Returns all usage scenario suffixes that apply to |interval_data|.
-std::vector<const char*> GetSuffixes(
-    const UsageScenarioDataStore::IntervalData& interval_data) {
-  std::vector<const char*> suffixes;
-  if (interval_data.max_tab_count == 0) {
-    suffixes.push_back(kZeroWindowSuffix);
-  }
-  return suffixes;
-}
-
 std::vector<const char*> PowerMetricsReporter::GetSuffixesForTesting(
     const UsageScenarioDataStore::IntervalData& interval_data) {
-  std::vector<const char*> suffixes = GetSuffixes(interval_data);
-  // Always at least record the unsuffixed version for tested histograms.
-  suffixes.push_back("");
-  return suffixes;
+  return GetSuffixes(interval_data);
+}
+
+void PowerMetricsReporter::ReportHistograms(
+    const UsageScenarioDataStore::IntervalData& interval_data,
+    const performance_monitor::ProcessMonitor::Metrics& metrics,
+    base::TimeDelta interval_duration,
+    BatteryDischargeMode discharge_mode,
+    absl::optional<int64_t> discharge_rate_during_interval) {
+  const std::vector<const char*> suffixes = GetSuffixes(interval_data);
+  ReportCPUHistograms(metrics, suffixes);
+  ReportBatteryHistograms(interval_duration, discharge_mode,
+                          discharge_rate_during_interval, suffixes);
 }
 
 void PowerMetricsReporter::ReportBatteryHistograms(
-    const UsageScenarioDataStore::IntervalData& interval_data,
-    base::TimeDelta sampling_interval,
     base::TimeDelta interval_duration,
     BatteryDischargeMode discharge_mode,
     absl::optional<int64_t> discharge_rate_during_interval,
     const std::vector<const char*>& suffixes) {
-  // Ratio by which the time elapsed can deviate from |recording_interval|
-  // without invalidating this sample.
+  // Ratio by which the time elapsed can deviate from
+  // |performance_monitor::ProcessMonitor::kGatherInterval| without invalidating
+  // this sample.
   constexpr double kTolerableTimeElapsedRatio = 0.10;
   constexpr double kTolerablePositiveDrift = (1. + kTolerableTimeElapsedRatio);
   constexpr double kTolerableNegativeDrift = (1. - kTolerableTimeElapsedRatio);
 
   if (discharge_mode == BatteryDischargeMode::kDischarging &&
-      interval_duration > sampling_interval * kTolerablePositiveDrift) {
+      interval_duration > performance_monitor::ProcessMonitor::kGatherInterval *
+                              kTolerablePositiveDrift) {
     // Too much time passed since the last record. Either the task took
     // too long to get executed or system sleep took place.
     discharge_mode = BatteryDischargeMode::kInvalidInterval;
   }
 
   if (discharge_mode == BatteryDischargeMode::kDischarging &&
-      interval_duration < sampling_interval * kTolerableNegativeDrift) {
+      interval_duration < performance_monitor::ProcessMonitor::kGatherInterval *
+                              kTolerableNegativeDrift) {
     // The recording task executed too early after the previous one, possibly
     // because the previous task took too long to execute.
     discharge_mode = BatteryDischargeMode::kInvalidInterval;
@@ -221,28 +261,16 @@
   ReportUKMs(interval_data, metrics, interval_duration, discharge_mode,
              discharge_rate_during_interval, main_screen_brightness);
 
-  std::vector<const char*> suffixes = GetSuffixes(interval_data);
-  ReportCPUHistograms(interval_data, metrics, suffixes);
-
-  // Always at least record the unsuffixed version for the remaining histograms.
-  suffixes.push_back("");
-
-  auto* process_monitor = performance_monitor::ProcessMonitor::Get();
-  base::TimeDelta sampling_interval =
-      process_monitor->GetScheduledSamplingInterval();
-
-  ReportBatteryHistograms(interval_data, sampling_interval, interval_duration,
-                          discharge_mode, discharge_rate_during_interval,
-                          suffixes);
+  ReportHistograms(interval_data, metrics, interval_duration, discharge_mode,
+                   discharge_rate_during_interval);
 }
 
 // static
 void PowerMetricsReporter::ReportCPUHistograms(
-    const UsageScenarioDataStore::IntervalData& interval_data,
     const performance_monitor::ProcessMonitor::Metrics& metrics,
     const std::vector<const char*>& suffixes) {
   for (const char* suffix : suffixes) {
-    std::string complete_suffix = base::JoinString({"Total", suffix}, "");
+    std::string complete_suffix = base::StrCat({"Total", suffix});
     performance_monitor::RecordProcessHistograms(complete_suffix.c_str(),
                                                  metrics);
   }
diff --git a/chrome/browser/metrics/power/power_metrics_reporter.h b/chrome/browser/metrics/power/power_metrics_reporter.h
index c9e282d..5c00b723 100644
--- a/chrome/browser/metrics/power/power_metrics_reporter.h
+++ b/chrome/browser/metrics/power/power_metrics_reporter.h
@@ -69,21 +69,24 @@
     kMaxValue = kInvalidInterval
   };
 
-  // Report the histograms for the past interval, with |sampling_interval| the
-  // expected sampling interval, and |interval_duration| the actual duration
-  // since the beginning of the interval.
-  static void ReportBatteryHistograms(
+  // Report battery and CPU metrics to generic histograms and histograms with a
+  // scenario suffix derived from |interval_data|.
+  static void ReportHistograms(
       const UsageScenarioDataStore::IntervalData& interval_data,
-      base::TimeDelta sampling_interval,
+      const performance_monitor::ProcessMonitor::Metrics& metrics,
+      base::TimeDelta interval_duration,
+      BatteryDischargeMode discharge_mode,
+      absl::optional<int64_t> discharge_rate_during_interval);
+
+  // Report battery metrics to histograms with |suffixes|.
+  static void ReportBatteryHistograms(
       base::TimeDelta interval_duration,
       BatteryDischargeMode discharge_mode,
       absl::optional<int64_t> discharge_rate_during_interval,
       const std::vector<const char*>& suffixes);
 
-  // Report CPU histograms based on data in |metrics| and suffixed based on
-  // scenarios inferred from |interval_data|.
+  // Report CPU histograms to histograms with |suffixes|.
   static void ReportCPUHistograms(
-      const UsageScenarioDataStore::IntervalData& interval_data,
       const performance_monitor::ProcessMonitor::Metrics& metrics,
       const std::vector<const char*>& suffixes);
 
diff --git a/chrome/browser/metrics/power/power_metrics_reporter_unittest.cc b/chrome/browser/metrics/power/power_metrics_reporter_unittest.cc
index d66b953..0f1a4a9 100644
--- a/chrome/browser/metrics/power/power_metrics_reporter_unittest.cc
+++ b/chrome/browser/metrics/power/power_metrics_reporter_unittest.cc
@@ -26,7 +26,6 @@
     "Power.BatteryDischargeRate2";
 constexpr const char* kBatteryDischargeModeHistogramName =
     "Power.BatteryDischargeMode";
-constexpr const char* kZeroWindowSuffix = ".ZeroWindow";
 constexpr const char* kMainScreenBrightnessHistogramName =
     "Power.MainScreenBrightness2";
 constexpr const char* kMainScreenBrightnessAvailableHistogramName =
@@ -38,22 +37,21 @@
 constexpr double kTolerablePositiveDrift = 1 + kTolerableTimeElapsedRatio;
 constexpr double kTolerableNegativeDrift = 1 - kTolerableTimeElapsedRatio;
 
+performance_monitor::ProcessMonitor::Metrics GetFakeProcessMetrics() {
+  performance_monitor::ProcessMonitor::Metrics metrics;
+  metrics.cpu_usage = 5;
+  return metrics;
+}
+
 using UkmEntry = ukm::builders::PowerUsageScenariosIntervalData;
 
 class PowerMetricsReporterAccess : public PowerMetricsReporter {
  public:
+  // Expose members of PowerMetricsReporter publicly on
+  // PowerMetricsReporterAccess.
   using PowerMetricsReporter::BatteryDischargeMode;
-  static void ReportBatteryHistograms(
-      const UsageScenarioDataStore::IntervalData& interval_data,
-      base::TimeDelta sampling_interval,
-      base::TimeDelta interval_duration,
-      BatteryDischargeMode discharge_mode,
-      absl::optional<int64_t> discharge_rate_during_interval,
-      const std::vector<const char*>& suffixes) {
-    PowerMetricsReporter::ReportBatteryHistograms(
-        interval_data, sampling_interval, interval_duration, discharge_mode,
-        std::move(discharge_rate_during_interval), suffixes);
-  }
+  using PowerMetricsReporter::ReportBatteryHistograms;
+  using PowerMetricsReporter::ReportHistograms;
 };
 
 // TODO(sebmarchand|etiennep): Move this to a test util file.
@@ -88,10 +86,6 @@
     for (auto& obs : GetObserversForTesting())
       obs.OnAggregatedMetricsSampled(metrics);
   }
-
-  base::TimeDelta GetScheduledSamplingInterval() const override {
-    return kExpectedMetricsCollectionInterval;
-  }
 };
 
 class TestUsageScenarioDataStoreImpl : public UsageScenarioDataStoreImpl {
@@ -517,68 +511,398 @@
       1);
 }
 
-TEST_F(PowerMetricsReporterUnitTest, BatteryDischargeCaptureZeroWindow) {
-  // Default value for interval_data.max_tab_count is zero.
+TEST_F(PowerMetricsReporterUnitTest, SuffixedHistograms_ZeroWindow) {
   UsageScenarioDataStore::IntervalData interval_data;
+  interval_data.max_tab_count = 0;
 
-  PowerMetricsReporterAccess::ReportBatteryHistograms(
-      interval_data, kExpectedMetricsCollectionInterval,
+  PowerMetricsReporterAccess::ReportHistograms(
+      interval_data, GetFakeProcessMetrics(),
       kExpectedMetricsCollectionInterval,
-      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 2500,
-      PowerMetricsReporter::GetSuffixesForTesting(interval_data));
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 2500);
 
-  histogram_tester_.ExpectUniqueSample(kBatteryDischargeRateHistogramName, 2500,
-                                       1);
+  // Non-suffixed histograms.
+  histogram_tester_.ExpectUniqueSample("Power.BatteryDischargeRate2", 2500, 1);
   histogram_tester_.ExpectUniqueSample(
-      kBatteryDischargeModeHistogramName,
+      "Power.BatteryDischargeMode",
       PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 1);
+  histogram_tester_.ExpectUniqueSample("PerformanceMonitor.AverageCPU2.Total",
+                                       500, 1);
 
-  // There were no tabs shown during the interval so no windows either.
-  // ZeroWindow suffix should be recorded.
+  // Suffixed histograms.
+  histogram_tester_.ExpectUniqueSample("Power.BatteryDischargeRate2.ZeroWindow",
+                                       2500, 1);
   histogram_tester_.ExpectUniqueSample(
-      base::JoinString({kBatteryDischargeRateHistogramName, kZeroWindowSuffix},
-                       ""),
-      2500, 1);
-  histogram_tester_.ExpectUniqueSample(
-      base::JoinString({kBatteryDischargeModeHistogramName, kZeroWindowSuffix},
-                       ""),
+      "Power.BatteryDischargeMode.ZeroWindow",
       PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "PerformanceMonitor.AverageCPU2.Total.ZeroWindow", 500, 1);
+
+  // Note: For simplicity, this test only verifies that one of the
+  // PerformanceMonitor.* histograms is recorded correctly.
 }
 
-TEST_F(PowerMetricsReporterUnitTest, BatteryDischargeCaptureMultipleWindows) {
-  // Tabs were shown during interval so windows too.
+TEST_F(PowerMetricsReporterUnitTest, SuffixedHistograms_AllTabsHidden) {
   UsageScenarioDataStore::IntervalData interval_data;
   interval_data.max_tab_count = 1;
+  interval_data.max_visible_window_count = 0;
+  // Values below should be ignored.
+  interval_data.time_capturing_video = base::TimeDelta::FromSeconds(1);
+  interval_data.time_playing_video_full_screen_single_monitor =
+      base::TimeDelta::FromSeconds(1);
+  interval_data.time_playing_video_in_visible_tab =
+      base::TimeDelta::FromSeconds(1);
+  interval_data.time_playing_audio = base::TimeDelta::FromSeconds(1);
+  interval_data.top_level_navigation_count = 1;
+  interval_data.user_interaction_count = 1;
 
-  PowerMetricsReporterAccess::ReportBatteryHistograms(
-      interval_data, kExpectedMetricsCollectionInterval,
+  PowerMetricsReporterAccess::ReportHistograms(
+      interval_data, GetFakeProcessMetrics(),
       kExpectedMetricsCollectionInterval,
-      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 2500,
-      PowerMetricsReporter::GetSuffixesForTesting(interval_data));
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 2500);
 
-  histogram_tester_.ExpectUniqueSample(kBatteryDischargeRateHistogramName, 2500,
-                                       1);
+  // Non-suffixed histograms.
+  histogram_tester_.ExpectUniqueSample("Power.BatteryDischargeRate2", 2500, 1);
   histogram_tester_.ExpectUniqueSample(
-      kBatteryDischargeModeHistogramName,
+      "Power.BatteryDischargeMode",
       PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 1);
+  histogram_tester_.ExpectUniqueSample("PerformanceMonitor.AverageCPU2.Total",
+                                       500, 1);
 
-  // Tabs were shown during the interval so windows too. ZeroWindow
-  // suffix should not be recorded.
-  histogram_tester_.ExpectTotalCount(
-      base::JoinString({kBatteryDischargeRateHistogramName, kZeroWindowSuffix},
-                       ""),
-      0);
-  histogram_tester_.ExpectTotalCount(
-      base::JoinString({kBatteryDischargeModeHistogramName, kZeroWindowSuffix},
-                       ""),
-      0);
+  // Suffixed histograms.
+  histogram_tester_.ExpectUniqueSample(
+      "Power.BatteryDischargeRate2.AllTabsHidden", 2500, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "Power.BatteryDischargeMode.AllTabsHidden",
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "PerformanceMonitor.AverageCPU2.Total.AllTabsHidden", 500, 1);
+
+  // Note: For simplicity, this test only verifies that one of the
+  // PerformanceMonitor.* histograms is recorded correctly.
+}
+
+TEST_F(PowerMetricsReporterUnitTest, SuffixedHistograms_VideoCapture) {
+  UsageScenarioDataStore::IntervalData interval_data;
+  interval_data.max_tab_count = 1;
+  interval_data.max_visible_window_count = 1;
+  interval_data.time_capturing_video = base::TimeDelta::FromSeconds(1);
+  // Values below should be ignored.
+  interval_data.time_playing_video_full_screen_single_monitor =
+      base::TimeDelta::FromSeconds(1);
+  interval_data.time_playing_video_in_visible_tab =
+      base::TimeDelta::FromSeconds(1);
+  interval_data.time_playing_audio = base::TimeDelta::FromSeconds(1);
+  interval_data.top_level_navigation_count = 1;
+  interval_data.user_interaction_count = 1;
+
+  PowerMetricsReporterAccess::ReportHistograms(
+      interval_data, GetFakeProcessMetrics(),
+      kExpectedMetricsCollectionInterval,
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 2500);
+
+  // Non-suffixed histograms.
+  histogram_tester_.ExpectUniqueSample("Power.BatteryDischargeRate2", 2500, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "Power.BatteryDischargeMode",
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 1);
+  histogram_tester_.ExpectUniqueSample("PerformanceMonitor.AverageCPU2.Total",
+                                       500, 1);
+
+  // Suffixed histograms.
+  histogram_tester_.ExpectUniqueSample(
+      "Power.BatteryDischargeRate2.VideoCapture", 2500, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "Power.BatteryDischargeMode.VideoCapture",
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "PerformanceMonitor.AverageCPU2.Total.VideoCapture", 500, 1);
+
+  // Note: For simplicity, this test only verifies that one of the
+  // PerformanceMonitor.* histograms is recorded correctly.
+}
+
+TEST_F(PowerMetricsReporterUnitTest, SuffixedHistograms_FullscreenVideo) {
+  UsageScenarioDataStore::IntervalData interval_data;
+  interval_data.max_tab_count = 1;
+  interval_data.max_visible_window_count = 1;
+  interval_data.time_capturing_video = base::TimeDelta();
+  interval_data.time_playing_video_full_screen_single_monitor =
+      base::TimeDelta::FromSeconds(1);
+  // Values below should be ignored.
+  interval_data.time_playing_video_in_visible_tab =
+      base::TimeDelta::FromSeconds(1);
+  interval_data.time_playing_audio = base::TimeDelta::FromSeconds(1);
+  interval_data.top_level_navigation_count = 1;
+  interval_data.user_interaction_count = 1;
+
+  PowerMetricsReporterAccess::ReportHistograms(
+      interval_data, GetFakeProcessMetrics(),
+      kExpectedMetricsCollectionInterval,
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 2500);
+
+  // Non-suffixed histograms.
+  histogram_tester_.ExpectUniqueSample("Power.BatteryDischargeRate2", 2500, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "Power.BatteryDischargeMode",
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 1);
+  histogram_tester_.ExpectUniqueSample("PerformanceMonitor.AverageCPU2.Total",
+                                       500, 1);
+
+  // Suffixed histograms.
+  histogram_tester_.ExpectUniqueSample(
+      "Power.BatteryDischargeRate2.FullscreenVideo", 2500, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "Power.BatteryDischargeMode.FullscreenVideo",
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "PerformanceMonitor.AverageCPU2.Total.FullscreenVideo", 500, 1);
+
+  // Note: For simplicity, this test only verifies that one of the
+  // PerformanceMonitor.* histograms is recorded correctly.
+}
+
+TEST_F(PowerMetricsReporterUnitTest,
+       SuffixedHistograms_EmbeddedVideo_NoNavigation) {
+  UsageScenarioDataStore::IntervalData interval_data;
+  interval_data.max_tab_count = 1;
+  interval_data.max_visible_window_count = 1;
+  interval_data.time_capturing_video = base::TimeDelta();
+  interval_data.time_playing_video_full_screen_single_monitor =
+      base::TimeDelta();
+  interval_data.top_level_navigation_count = 0;
+  interval_data.time_playing_video_in_visible_tab =
+      base::TimeDelta::FromSeconds(1);
+  // Values below should be ignored.
+  interval_data.time_playing_audio = base::TimeDelta::FromSeconds(1);
+  interval_data.user_interaction_count = 1;
+
+  PowerMetricsReporterAccess::ReportHistograms(
+      interval_data, GetFakeProcessMetrics(),
+      kExpectedMetricsCollectionInterval,
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 2500);
+
+  // Non-suffixed histograms.
+  histogram_tester_.ExpectUniqueSample("Power.BatteryDischargeRate2", 2500, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "Power.BatteryDischargeMode",
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 1);
+  histogram_tester_.ExpectUniqueSample("PerformanceMonitor.AverageCPU2.Total",
+                                       500, 1);
+
+  // Suffixed histograms.
+  histogram_tester_.ExpectUniqueSample(
+      "Power.BatteryDischargeRate2.EmbeddedVideo_NoNavigation", 2500, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "Power.BatteryDischargeMode.EmbeddedVideo_NoNavigation",
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "PerformanceMonitor.AverageCPU2.Total.EmbeddedVideo_NoNavigation", 500,
+      1);
+
+  // Note: For simplicity, this test only verifies that one of the
+  // PerformanceMonitor.* histograms is recorded correctly.
+}
+
+TEST_F(PowerMetricsReporterUnitTest,
+       SuffixedHistograms_EmbeddedVideo_WithNavigation) {
+  UsageScenarioDataStore::IntervalData interval_data;
+  interval_data.max_tab_count = 1;
+  interval_data.max_visible_window_count = 1;
+  interval_data.time_capturing_video = base::TimeDelta();
+  interval_data.time_playing_video_full_screen_single_monitor =
+      base::TimeDelta();
+  interval_data.top_level_navigation_count = 1;
+  interval_data.time_playing_video_in_visible_tab =
+      base::TimeDelta::FromSeconds(1);
+  // Values below should be ignored.
+  interval_data.time_playing_audio = base::TimeDelta::FromSeconds(1);
+  interval_data.user_interaction_count = 1;
+
+  PowerMetricsReporterAccess::ReportHistograms(
+      interval_data, GetFakeProcessMetrics(),
+      kExpectedMetricsCollectionInterval,
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 2500);
+
+  // Non-suffixed histograms.
+  histogram_tester_.ExpectUniqueSample("Power.BatteryDischargeRate2", 2500, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "Power.BatteryDischargeMode",
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 1);
+  histogram_tester_.ExpectUniqueSample("PerformanceMonitor.AverageCPU2.Total",
+                                       500, 1);
+
+  // Suffixed histograms.
+  histogram_tester_.ExpectUniqueSample(
+      "Power.BatteryDischargeRate2.EmbeddedVideo_WithNavigation", 2500, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "Power.BatteryDischargeMode.EmbeddedVideo_WithNavigation",
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "PerformanceMonitor.AverageCPU2.Total.EmbeddedVideo_WithNavigation", 500,
+      1);
+
+  // Note: For simplicity, this test only verifies that one of the
+  // PerformanceMonitor.* histograms is recorded correctly.
+}
+
+TEST_F(PowerMetricsReporterUnitTest, SuffixedHistograms_Audio) {
+  UsageScenarioDataStore::IntervalData interval_data;
+  interval_data.max_tab_count = 1;
+  interval_data.max_visible_window_count = 1;
+  interval_data.time_capturing_video = base::TimeDelta();
+  interval_data.time_playing_video_full_screen_single_monitor =
+      base::TimeDelta();
+  interval_data.time_playing_video_in_visible_tab = base::TimeDelta();
+  interval_data.time_playing_audio = base::TimeDelta::FromSeconds(1);
+  // Values below should be ignored.
+  interval_data.user_interaction_count = 1;
+  interval_data.top_level_navigation_count = 1;
+
+  PowerMetricsReporterAccess::ReportHistograms(
+      interval_data, GetFakeProcessMetrics(),
+      kExpectedMetricsCollectionInterval,
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 2500);
+
+  // Non-suffixed histograms.
+  histogram_tester_.ExpectUniqueSample("Power.BatteryDischargeRate2", 2500, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "Power.BatteryDischargeMode",
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 1);
+  histogram_tester_.ExpectUniqueSample("PerformanceMonitor.AverageCPU2.Total",
+                                       500, 1);
+
+  // Suffixed histograms.
+  histogram_tester_.ExpectUniqueSample("Power.BatteryDischargeRate2.Audio",
+                                       2500, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "Power.BatteryDischargeMode.Audio",
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "PerformanceMonitor.AverageCPU2.Total.Audio", 500, 1);
+
+  // Note: For simplicity, this test only verifies that one of the
+  // PerformanceMonitor.* histograms is recorded correctly.
+}
+
+TEST_F(PowerMetricsReporterUnitTest, SuffixedHistograms_Navigation) {
+  UsageScenarioDataStore::IntervalData interval_data;
+  interval_data.max_tab_count = 1;
+  interval_data.max_visible_window_count = 1;
+  interval_data.time_capturing_video = base::TimeDelta();
+  interval_data.time_playing_video_full_screen_single_monitor =
+      base::TimeDelta();
+  interval_data.time_playing_video_in_visible_tab = base::TimeDelta();
+  interval_data.time_playing_audio = base::TimeDelta();
+  interval_data.top_level_navigation_count = 1;
+  // Values below should be ignored.
+  interval_data.user_interaction_count = 1;
+
+  PowerMetricsReporterAccess::ReportHistograms(
+      interval_data, GetFakeProcessMetrics(),
+      kExpectedMetricsCollectionInterval,
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 2500);
+
+  // Non-suffixed histograms.
+  histogram_tester_.ExpectUniqueSample("Power.BatteryDischargeRate2", 2500, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "Power.BatteryDischargeMode",
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 1);
+  histogram_tester_.ExpectUniqueSample("PerformanceMonitor.AverageCPU2.Total",
+                                       500, 1);
+
+  // Suffixed histograms.
+  histogram_tester_.ExpectUniqueSample("Power.BatteryDischargeRate2.Navigation",
+                                       2500, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "Power.BatteryDischargeMode.Navigation",
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "PerformanceMonitor.AverageCPU2.Total.Navigation", 500, 1);
+
+  // Note: For simplicity, this test only verifies that one of the
+  // PerformanceMonitor.* histograms is recorded correctly.
+}
+
+TEST_F(PowerMetricsReporterUnitTest, SuffixedHistograms_Interaction) {
+  UsageScenarioDataStore::IntervalData interval_data;
+  interval_data.max_tab_count = 1;
+  interval_data.max_visible_window_count = 1;
+  interval_data.time_capturing_video = base::TimeDelta();
+  interval_data.time_playing_video_full_screen_single_monitor =
+      base::TimeDelta();
+  interval_data.time_playing_video_in_visible_tab = base::TimeDelta();
+  interval_data.time_playing_audio = base::TimeDelta();
+  interval_data.top_level_navigation_count = 0;
+  interval_data.user_interaction_count = 1;
+
+  PowerMetricsReporterAccess::ReportHistograms(
+      interval_data, GetFakeProcessMetrics(),
+      kExpectedMetricsCollectionInterval,
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 2500);
+
+  // Non-suffixed histograms.
+  histogram_tester_.ExpectUniqueSample("Power.BatteryDischargeRate2", 2500, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "Power.BatteryDischargeMode",
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 1);
+  histogram_tester_.ExpectUniqueSample("PerformanceMonitor.AverageCPU2.Total",
+                                       500, 1);
+
+  // Suffixed histograms.
+  histogram_tester_.ExpectUniqueSample(
+      "Power.BatteryDischargeRate2.Interaction", 2500, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "Power.BatteryDischargeMode.Interaction",
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "PerformanceMonitor.AverageCPU2.Total.Interaction", 500, 1);
+
+  // Note: For simplicity, this test only verifies that one of the
+  // PerformanceMonitor.* histograms is recorded correctly.
+}
+
+TEST_F(PowerMetricsReporterUnitTest, SuffixedHistograms_Passive) {
+  UsageScenarioDataStore::IntervalData interval_data;
+  interval_data.max_tab_count = 1;
+  interval_data.max_visible_window_count = 1;
+  interval_data.time_capturing_video = base::TimeDelta();
+  interval_data.time_playing_video_full_screen_single_monitor =
+      base::TimeDelta();
+  interval_data.time_playing_video_in_visible_tab = base::TimeDelta();
+  interval_data.time_playing_audio = base::TimeDelta();
+  interval_data.top_level_navigation_count = 0;
+  interval_data.user_interaction_count = 0;
+
+  PowerMetricsReporterAccess::ReportHistograms(
+      interval_data, GetFakeProcessMetrics(),
+      kExpectedMetricsCollectionInterval,
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 2500);
+
+  // Non-suffixed histograms.
+  histogram_tester_.ExpectUniqueSample("Power.BatteryDischargeRate2", 2500, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "Power.BatteryDischargeMode",
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 1);
+  histogram_tester_.ExpectUniqueSample("PerformanceMonitor.AverageCPU2.Total",
+                                       500, 1);
+
+  // Suffixed histograms.
+  histogram_tester_.ExpectUniqueSample("Power.BatteryDischargeRate2.Passive",
+                                       2500, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "Power.BatteryDischargeMode.Passive",
+      PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 1);
+  histogram_tester_.ExpectUniqueSample(
+      "PerformanceMonitor.AverageCPU2.Total.Passive", 500, 1);
+
+  // Note: For simplicity, this test only verifies that one of the
+  // PerformanceMonitor.* histograms is recorded correctly.
 }
 
 TEST_F(PowerMetricsReporterUnitTest, BatteryDischargeCaptureIsTooEarly) {
   UsageScenarioDataStore::IntervalData interval_data;
 
   PowerMetricsReporterAccess::ReportBatteryHistograms(
-      interval_data, kExpectedMetricsCollectionInterval,
       (kExpectedMetricsCollectionInterval * kTolerableNegativeDrift) -
           base::TimeDelta::FromSeconds(1),
       PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 2500,
@@ -594,7 +918,6 @@
   UsageScenarioDataStore::IntervalData interval_data;
 
   PowerMetricsReporterAccess::ReportBatteryHistograms(
-      interval_data, kExpectedMetricsCollectionInterval,
       (kExpectedMetricsCollectionInterval * kTolerableNegativeDrift) +
           base::TimeDelta::FromSeconds(1),
       PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 2500,
@@ -611,7 +934,6 @@
   UsageScenarioDataStore::IntervalData interval_data;
 
   PowerMetricsReporterAccess::ReportBatteryHistograms(
-      interval_data, kExpectedMetricsCollectionInterval,
       (kExpectedMetricsCollectionInterval * kTolerablePositiveDrift) +
           base::TimeDelta::FromSeconds(1),
       PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 2500,
@@ -627,7 +949,6 @@
   UsageScenarioDataStore::IntervalData interval_data;
 
   PowerMetricsReporterAccess::ReportBatteryHistograms(
-      interval_data, kExpectedMetricsCollectionInterval,
       (kExpectedMetricsCollectionInterval * kTolerablePositiveDrift) -
           base::TimeDelta::FromSeconds(1),
       PowerMetricsReporterAccess::BatteryDischargeMode::kDischarging, 2500,
@@ -654,10 +975,7 @@
 
   data_store_.SetIntervalDataToReturn(fake_interval_data);
 
-  performance_monitor::ProcessMonitor::Metrics fake_metrics = {};
-  fake_metrics.cpu_usage = 0.5;
-
-  WaitForNextSample(fake_metrics);
+  WaitForNextSample(GetFakeProcessMetrics());
 
   auto entries = test_ukm_recorder_.GetEntriesByName(
       ukm::builders::PowerUsageScenariosIntervalData::kEntryName);
@@ -681,9 +999,7 @@
       1, 1, 0.50, true, base::TimeTicks::Now()});
   data_store_.SetIntervalDataToReturn(fake_interval_data);
 
-  performance_monitor::ProcessMonitor::Metrics fake_metrics = {};
-  fake_metrics.cpu_usage = 0.5;
-  WaitForNextSample(fake_metrics);
+  WaitForNextSample(GetFakeProcessMetrics());
 
   auto entries = test_ukm_recorder_.GetEntriesByName(
       ukm::builders::PowerUsageScenariosIntervalData::kEntryName);
@@ -752,8 +1068,8 @@
       1, 1, 0.50, true, base::TimeTicks::Now()});
   data_store_.SetIntervalDataToReturn(fake_interval_data);
 
-  performance_monitor::ProcessMonitor::Metrics fake_metrics = {};
-  fake_metrics.cpu_usage = 0.5;
+  performance_monitor::ProcessMonitor::Metrics fake_metrics =
+      GetFakeProcessMetrics();
   WaitForNextSample(fake_metrics);
 
   histogram_tester_.ExpectTotalCount(kMainScreenBrightnessHistogramName, 0);
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
index 3f5d7c7..d4c92e2 100644
--- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
+++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
@@ -105,6 +105,18 @@
          chromeos::features::IsBluetoothAdvertisementMonitoringEnabled();
 }
 
+// Background scanning filter values.
+constexpr int16_t kBackgroundScanningDeviceFoundRSSIThreshold = -80;
+constexpr int16_t kBackgroundScanningDeviceLostRSSIThreshold = -100;
+constexpr base::TimeDelta kBackgroundScanningDeviceFoundTimeout =
+    base::TimeDelta::FromSeconds(1);
+constexpr base::TimeDelta kBackgroundScanningDeviceLostTimeout =
+    base::TimeDelta::FromSeconds(5);
+// This pattern value encodes the Fast Initiation service ID of 0xfe2c and the
+// model ID of 0xfc128e.
+constexpr uint8_t kBackgroundScanningFilterPatternValue[] = {0x2c, 0xfe, 0xfc,
+                                                             0x12, 0x8e};
+
 std::string ReceiveSurfaceStateToString(
     NearbySharingService::ReceiveSurfaceState state) {
   switch (state) {
@@ -2186,13 +2198,20 @@
 void NearbySharingServiceImpl::StartBackgroundScanning() {
   DCHECK(!background_scan_session_);
   NS_LOG(VERBOSE) << __func__ << ": Starting background scanning.";
-  auto filter = std::make_unique<device::BluetoothLowEnergyScanFilter>(
-      /*device_found_threshold=*/-80, /*device_found_timeout=*/1,
-      /*device_lost_threshold=*/-100, /*device_lost_timeout=*/5);
-  filter->AddPattern(
+
+  auto pattern_value =
+      std::vector<uint8_t>(std::begin(kBackgroundScanningFilterPatternValue),
+                           std::end(kBackgroundScanningFilterPatternValue));
+  device::BluetoothLowEnergyScanFilter::Pattern pattern(
       /*start_position=*/0,
       device::BluetoothLowEnergyScanFilter::AdvertisementDataType::kServiceData,
-      /*value=*/std::vector<uint8_t>{0x2c, 0xfe, 0xfc, 0x12, 0x8e});
+      std::move(pattern_value));
+  auto filter = device::BluetoothLowEnergyScanFilter::Create(
+      kBackgroundScanningDeviceFoundRSSIThreshold,
+      kBackgroundScanningDeviceLostRSSIThreshold,
+      kBackgroundScanningDeviceFoundTimeout,
+      kBackgroundScanningDeviceLostTimeout, {pattern});
+
   background_scan_session_ = bluetooth_adapter_->StartLowEnergyScanSession(
       std::move(filter), /*delegate=*/weak_ptr_factory_.GetWeakPtr());
 }
diff --git a/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer.cc
index 1079749..250df99e 100644
--- a/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer.cc
@@ -680,6 +680,16 @@
     builder.SetInteractiveTiming_FirstScrollDelay(
         first_scroll_delay.InMilliseconds());
   }
+  if (timing.interactive_timing->first_scroll_timestamp &&
+      WasStartedInForegroundOptionalEventInForeground(
+          timing.interactive_timing->first_scroll_timestamp, GetDelegate())) {
+    base::TimeDelta first_scroll_timestamp =
+        timing.interactive_timing->first_scroll_timestamp.value();
+    builder.SetInteractiveTiming_FirstScrollTimestamp(
+        ukm::GetExponentialBucketMinForUserTiming(
+            first_scroll_timestamp.InMilliseconds()));
+  }
+
   if (timing.interactive_timing->first_input_processing_time &&
       WasStartedInForegroundOptionalEventInForeground(
           timing.interactive_timing->first_input_timestamp, GetDelegate())) {
diff --git a/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer_unittest.cc
index baba9a444..44f9408e 100644
--- a/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer_unittest.cc
@@ -1105,7 +1105,7 @@
   }
 }
 
-TEST_F(UkmPageLoadMetricsObserverTest, FirstScrollDelay) {
+TEST_F(UkmPageLoadMetricsObserverTest, FirstScrollDelayAndTimestamp) {
   page_load_metrics::mojom::PageLoadTiming timing;
   page_load_metrics::InitPageLoadTimingForTest(&timing);
   timing.navigation_start = base::Time::FromDoubleT(1);
@@ -1131,6 +1131,9 @@
                                                           GURL(kTestUrl1));
     tester()->test_ukm_recorder().ExpectEntryMetric(
         kv.second.get(), PageLoad::kInteractiveTiming_FirstScrollDelayName, 50);
+    tester()->test_ukm_recorder().ExpectEntryMetric(
+        kv.second.get(), PageLoad::kInteractiveTiming_FirstScrollTimestampName,
+        64);
   }
 }
 
diff --git a/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheckReferrer.java b/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheckReferrer.java
index 5fd961de..d55ca676 100644
--- a/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheckReferrer.java
+++ b/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheckReferrer.java
@@ -4,31 +4,31 @@
 package org.chromium.chrome.browser.password_check;
 
 import androidx.annotation.IntDef;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * These values are persisted to logs. Entries should not be renumbered and
- * numeric values should never be reused. To be kept in sync with PasswordCheckReferrerAndroid in
- * enums.xml.
+ * These values are persisted to logs. Entries should not be renumbered and numeric values should
+ * never be reused. To be kept in sync with PasswordCheckReferrerAndroid in enums.xml.
  */
 @IntDef({PasswordCheckReferrer.PASSWORD_SETTINGS, PasswordCheckReferrer.SAFETY_CHECK,
-        PasswordCheckReferrer.LEAK_DIALOG})
+        PasswordCheckReferrer.LEAK_DIALOG, PasswordCheckReferrer.PHISHED_WARNING_DIALOG})
 @Retention(RetentionPolicy.SOURCE)
 public @interface PasswordCheckReferrer {
-    /**
-     * Corresponds to the Settings > Passwords page.
-     */
+    /** Corresponds to the Settings > Passwords page. */
     int PASSWORD_SETTINGS = 0;
-    /**
-     * Corresponds to the safety check settings page.
-     */
+    /** Corresponds to the safety check settings page. */
     int SAFETY_CHECK = 1;
     /**
-     * Represents the leak dialog prompted to the user when they sign in with a credential
-     * which was part of a data breach;
+     * Represents the leak dialog prompted to the user when they sign in with a credential which was
+     * part of a data breach;
      */
     int LEAK_DIALOG = 2;
-    int COUNT = 3;
+    /**
+     * Represents the PhishGuard password reuse warning dialog prompted to the user when they enter
+     * a saved password into a 'phishing' or 'low reputation' site.
+     */
+    int PHISHED_WARNING_DIALOG = 3;
+
+    int COUNT = 4;
 }
diff --git a/chrome/browser/password_manager/android/password_checkup_launcher_helper.cc b/chrome/browser/password_manager/android/password_checkup_launcher_helper.cc
index 66a4fa9..96f2fe5 100644
--- a/chrome/browser/password_manager/android/password_checkup_launcher_helper.cc
+++ b/chrome/browser/password_manager/android/password_checkup_launcher_helper.cc
@@ -23,6 +23,15 @@
 }
 
 // static
+void PasswordCheckupLauncherHelper::
+    LaunchLocalCheckupFromPhishGuardWarningDialog(
+        JNIEnv* env,
+        const base::android::JavaRef<jobject>& windowAndroid) {
+  Java_PasswordCheckupLauncher_launchLocalCheckupFromPhishGuardWarningDialog(
+      env, windowAndroid);
+}
+
+// static
 void PasswordCheckupLauncherHelper::LaunchCheckupInAccountWithActivity(
     JNIEnv* env,
     const base::android::JavaRef<jstring>& checkupUrl,
diff --git a/chrome/browser/password_manager/android/password_checkup_launcher_helper.h b/chrome/browser/password_manager/android/password_checkup_launcher_helper.h
index 9f242b2..bc359a3 100644
--- a/chrome/browser/password_manager/android/password_checkup_launcher_helper.h
+++ b/chrome/browser/password_manager/android/password_checkup_launcher_helper.h
@@ -23,6 +23,12 @@
       JNIEnv* env,
       const base::android::JavaRef<jobject>& windowAndroid);
 
+  // Launch the bulk password check locally from a PhishGuard password reuse
+  // warning dialog
+  static void LaunchLocalCheckupFromPhishGuardWarningDialog(
+      JNIEnv* env,
+      const base::android::JavaRef<jobject>& windowAndroid);
+
   // Launch the bulk password check in the Google Account using an activity
   // rather than a WindowAndroid
   static void LaunchCheckupInAccountWithActivity(
diff --git a/chrome/browser/performance_monitor/process_metrics_recorder.cc b/chrome/browser/performance_monitor/process_metrics_recorder.cc
index d92c226..f33834dd 100644
--- a/chrome/browser/performance_monitor/process_metrics_recorder.cc
+++ b/chrome/browser/performance_monitor/process_metrics_recorder.cc
@@ -55,9 +55,4 @@
   }
 }
 
-void ProcessMetricsRecorder::OnAggregatedMetricsSampled(
-    const ProcessMonitor::Metrics& metrics) {
-  RecordProcessHistograms("Total", metrics);
-}
-
 }  // namespace performance_monitor
diff --git a/chrome/browser/performance_monitor/process_metrics_recorder.h b/chrome/browser/performance_monitor/process_metrics_recorder.h
index b392699..e6a144290 100644
--- a/chrome/browser/performance_monitor/process_metrics_recorder.h
+++ b/chrome/browser/performance_monitor/process_metrics_recorder.h
@@ -21,11 +21,9 @@
   ProcessMetricsRecorder& operator=(const ProcessMetricsRecorder&) = delete;
 
  private:
-  // ProcessMonitorObserver:
+  // ProcessMonitor::Observer:
   void OnMetricsSampled(const ProcessMetadata& process_metadata,
                         const ProcessMonitor::Metrics& metrics) override;
-  void OnAggregatedMetricsSampled(
-      const ProcessMonitor::Metrics& metrics) override;
 
   base::ScopedObservation<ProcessMonitor, ProcessMonitor::Observer>
       process_monitor_observation_{this};
diff --git a/chrome/browser/performance_monitor/process_monitor.cc b/chrome/browser/performance_monitor/process_monitor.cc
index 5710230f..895f13f 100644
--- a/chrome/browser/performance_monitor/process_monitor.cc
+++ b/chrome/browser/performance_monitor/process_monitor.cc
@@ -36,10 +36,6 @@
 
 namespace {
 
-// The default interval at which ProcessMonitor performs its timed
-// collections.
-constexpr base::TimeDelta kGatherInterval = base::TimeDelta::FromSeconds(120);
-
 // The global instance.
 ProcessMonitor* g_process_monitor = nullptr;
 
@@ -95,6 +91,8 @@
 
 }  // namespace
 
+constexpr base::TimeDelta ProcessMonitor::kGatherInterval;
+
 // static
 std::unique_ptr<ProcessMonitor> ProcessMonitor::Create() {
   DCHECK(!g_process_monitor);
@@ -117,10 +115,6 @@
                          &ProcessMonitor::GatherProcesses);
 }
 
-base::TimeDelta ProcessMonitor::GetScheduledSamplingInterval() const {
-  return kGatherInterval;
-}
-
 void ProcessMonitor::AddObserver(Observer* observer) {
   observer_list_.AddObserver(observer);
 }
diff --git a/chrome/browser/performance_monitor/process_monitor.h b/chrome/browser/performance_monitor/process_monitor.h
index c4c3ecc..45fd13ab 100644
--- a/chrome/browser/performance_monitor/process_monitor.h
+++ b/chrome/browser/performance_monitor/process_monitor.h
@@ -38,6 +38,10 @@
 // upon noticing serious performance degradation.
 class ProcessMonitor {
  public:
+  // The interval at which ProcessMonitor performs its timed collections.
+  static constexpr base::TimeDelta kGatherInterval =
+      base::TimeDelta::FromMinutes(2);
+
   struct Metrics {
     // The percentage of time spent executing, across all threads of the
     // process, in the interval since the last time the metric was sampled. This
@@ -91,10 +95,6 @@
   // Start the cycle of metrics gathering.
   void StartGatherCycle();
 
-  // Returns the expected sampling interval according to how it's scheduled.
-  // This might vary from the actual interval. Virtual for testing.
-  virtual base::TimeDelta GetScheduledSamplingInterval() const;
-
   // Adds/removes an observer.
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
diff --git a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc
index 99d736b..09a8f5c 100644
--- a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc
+++ b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc
@@ -21,6 +21,7 @@
 #include "net/http/http_util.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "services/network/public/cpp/constants.h"
+#include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/mojom/early_hints.mojom.h"
@@ -205,7 +206,8 @@
   options.struct_size = sizeof(MojoCreateDataPipeOptions);
   options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
   options.element_num_bytes = 1;
-  options.capacity_num_bytes = network::kDataPipeDefaultAllocationSize;
+  options.capacity_num_bytes =
+      network::features::GetDataPipeDefaultAllocationSize();
 
   MojoResult rv =
       mojo::CreateDataPipe(&options, producer_handle_, consumer_handle);
diff --git a/chrome/browser/printing/print_job.cc b/chrome/browser/printing/print_job.cc
index ccaff12..bca04dc 100644
--- a/chrome/browser/printing/print_job.cc
+++ b/chrome/browser/printing/print_job.cc
@@ -499,22 +499,15 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   switch (event_details.type()) {
-    case JobEventDetails::FAILED: {
+    case JobEventDetails::FAILED:
       // No need to cancel since the worker already canceled itself.
       Stop();
       break;
-    }
-    case JobEventDetails::NEW_DOC:
-    case JobEventDetails::JOB_DONE: {
-      // Don't care.
-      break;
-    }
-    case JobEventDetails::DOC_DONE: {
+    case JobEventDetails::DOC_DONE:
       // This will call `Stop()` and broadcast a `JOB_DONE` message.
       content::GetUIThreadTaskRunner({})->PostTask(
           FROM_HERE, base::BindOnce(&PrintJob::OnDocumentDone, this));
       break;
-    }
 #if defined(OS_WIN)
     case JobEventDetails::PAGE_DONE:
       if (pdf_conversion_state_) {
@@ -524,10 +517,8 @@
       document_->DropPage(event_details.page());
       break;
 #endif  // defined(OS_WIN)
-    default: {
-      NOTREACHED();
+    default:
       break;
-    }
   }
 }
 
diff --git a/chrome/browser/printing/print_job_manager.cc b/chrome/browser/printing/print_job_manager.cc
index 842bced..a1be2e6 100644
--- a/chrome/browser/printing/print_job_manager.cc
+++ b/chrome/browser/printing/print_job_manager.cc
@@ -140,21 +140,11 @@
       DCHECK_EQ(1U, erased);
       break;
     }
-    case JobEventDetails::FAILED: {
+    case JobEventDetails::FAILED:
       current_jobs_.erase(print_job);
       break;
-    }
-#if defined(OS_WIN)
-    case JobEventDetails::PAGE_DONE:
-#endif
-    case JobEventDetails::DOC_DONE: {
-      // Don't care.
+    default:
       break;
-    }
-    default: {
-      NOTREACHED();
-      break;
-    }
   }
 }
 
diff --git a/chrome/browser/printing/print_view_manager_base.cc b/chrome/browser/printing/print_view_manager_base.cc
index e39b90a..8672276 100644
--- a/chrome/browser/printing/print_view_manager_base.cc
+++ b/chrome/browser/printing/print_view_manager_base.cc
@@ -775,13 +775,6 @@
       TerminatePrintJob(true);
       break;
     }
-#if defined(OS_WIN)
-    case JobEventDetails::PAGE_DONE:
-#endif
-    case JobEventDetails::NEW_DOC: {
-      // Don't care about the actual printing process.
-      break;
-    }
     case JobEventDetails::DOC_DONE: {
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
       chromeos::LacrosChromeServiceImpl* service =
@@ -801,18 +794,15 @@
 #endif
       break;
     }
-    case JobEventDetails::JOB_DONE: {
+    case JobEventDetails::JOB_DONE:
       // Printing is done, we don't need it anymore.
       // print_job_->is_job_pending() may still be true, depending on the order
       // of object registration.
       printing_succeeded_ = true;
       ReleasePrintJob();
       break;
-    }
-    default: {
-      NOTREACHED();
+    default:
       break;
-    }
   }
 }
 
diff --git a/chrome/browser/resources/chromeos/add_supervision/add_supervision_ui.html b/chrome/browser/resources/chromeos/add_supervision/add_supervision_ui.html
index 927fb34..6d62385 100644
--- a/chrome/browser/resources/chromeos/add_supervision/add_supervision_ui.html
+++ b/chrome/browser/resources/chromeos/add_supervision/add_supervision_ui.html
@@ -26,6 +26,11 @@
     height: 100vh;
   }
 
+  #webview {
+    display: flex;
+    height: 100%;
+  }
+
   #offlineContentDiv {
     padding-inline-start: 32px;
   }
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_related_info.html b/chrome/browser/resources/chromeos/assistant_optin/assistant_related_info.html
index c8b20b1..00d3dba0 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_related_info.html
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_related_info.html
@@ -63,10 +63,10 @@
     </h1>
     <div slot="subtitle" id="subtitle-container"
         hidden$="[[skipActivityControl_]]">
-      <div hidden$="[[!!childName_]]">
+      <div hidden="[[childName_]]">
         [[i18nDynamic(locale, 'assistantScreenContextDesc')]]
       </div>
-      <div hidden$="[[!childName_]]">
+      <div hidden="[[!childName_]]">
         [[i18nDynamic(
             locale, 'assistantScreenContextDescForChild', childName_)]]
       </div>
@@ -77,10 +77,10 @@
     </div>
     <div slot="content" class="flex layout vertical center center-justified"
         hidden$="[[skipActivityControl_]]">
-      <div class="example-text" hidden$="[[!!childName_]]">
+      <div class="example-text" hidden="[[childName_]]">
         [[i18nDynamic(locale, 'assistantRelatedInfoExample')]]
       </div>
-      <div class="example-text" hidden$="[[!childName_]]">
+      <div class="example-text" hidden="[[!childName_]]">
         [[i18nDynamic(locale, 'assistantRelatedInfoExampleForChild')]]
       </div>
       <img id="relatedInfoImg" class="oobe-illustration" aria-hidden="true"
@@ -88,10 +88,10 @@
     </div>
     <div slot="content" id="content-container" class="landscape-header-aligned"
         hidden$="[[!skipActivityControl_]]">
-      <div class="content" hidden$="[[!!childName_]]">
+      <div class="content" hidden="[[childName_]]">
         [[i18nDynamic(locale, 'assistantRelatedInfoReturnedUserMessage')]]
       </div>
-      <div class="content" hidden$="[[!childName_]]">
+      <div class="content" hidden="[[!childName_]]">
         [[i18nDynamic(locale,
             'assistantRelatedInfoReturnedUserMessageForChild', childName_)]]
       </div>
@@ -101,11 +101,11 @@
           [[i18nDynamic(locale, 'assistantScreenContextTitle')]]
         </div>
         <div slot="content" aria-hidden="true"
-            hidden$="[[!!childName_]]">
+            hidden="[[childName_]]">
           [[i18nDynamic(locale, 'assistantScreenContextDesc')]]
         </div>
         <div slot="content" aria-hidden="true"
-            hidden$="[[!childName_]]">
+            hidden="[[!childName_]]">
           [[i18nDynamic(locale,
               'assistantScreenContextDescForChild', childName_)]]
         </div>
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html
index 49337d13..799e398e4 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html
@@ -65,10 +65,10 @@
       <h1 slot="title">
         [[getDialogTitle_(locale, uiStep, childName_)]]
       </h1>
-      <div slot="subtitle" hidden$="[[!!childName_]]">
+      <div slot="subtitle" hidden="[[childName_]]">
         [[i18nDynamic(locale, 'assistantVoiceMatchFooter')]]
       </div>
-      <div slot="subtitle" hidden$="[[!childName_]]"
+      <div slot="subtitle" hidden="[[!childName_]]"
           inner-h-t-m-l="[[getSubtitleMessage_(locale, uiStep, childName_)]]">
       </div>
       <div slot="content" class="landscape-header-aligned
@@ -117,10 +117,10 @@
       <h1 slot="title">
         [[i18nDynamic(locale, 'assistantVoiceMatchAlreadySetupTitle')]]
       </h1>
-      <div slot="subtitle" hidden$="[[!!childName_]]">
+      <div slot="subtitle" hidden="[[childName_]]">
         [[i18nDynamic(locale, 'assistantVoiceMatchAlreadySetupMessage')]]
       </div>
-      <div slot="subtitle" hidden$="[[!childName_]]">
+      <div slot="subtitle" hidden="[[!childName_]]">
         [[i18nDynamic(locale,
             'assistantVoiceMatchAlreadySetupMessageForChild', childName_)]]
       </div>
diff --git a/chrome/browser/resources/memories/BUILD.gn b/chrome/browser/resources/memories/BUILD.gn
index 9bfbc872..2221663 100644
--- a/chrome/browser/resources/memories/BUILD.gn
+++ b/chrome/browser/resources/memories/BUILD.gn
@@ -114,6 +114,7 @@
 
 generate_grd("build_grd") {
   grd_prefix = "history_clusters"
+  resource_path_prefix = "history_clusters"
   out_grd = "$target_gen_dir/resources.grd"
   input_files = [ "history_clusters.html" ]
   input_files_base_dir = rebase_path(".", "//")
diff --git a/chrome/browser/resources/memories/app.html b/chrome/browser/resources/memories/app.html
index b82d668..e9a4e03d 100644
--- a/chrome/browser/resources/memories/app.html
+++ b/chrome/browser/resources/memories/app.html
@@ -50,13 +50,13 @@
   <template>
     <cr-dialog consume-keydown-event on-cancel="onConfirmationDialogCancel_">
       <div slot="title">$i18n{removeSelected}</div>
-      <div slot="body">$i18n{removeWarning}</div>
+      <div slot="body">$i18n{deleteWarning}</div>
       <div slot="button-container">
         <cr-button class="cancel-button" on-click="onCancelButtonClick_">
           $i18n{cancel}
         </cr-button>
         <cr-button class="action-button" on-click="onRemoveButtonClick_">
-          $i18n{remove}
+          $i18n{deleteConfirm}
         </cr-button>
       </div>
     </cr-dialog>
diff --git a/chrome/browser/resources/memories/app.ts b/chrome/browser/resources/memories/app.ts
index 62eb910..9f8c83e 100644
--- a/chrome/browser/resources/memories/app.ts
+++ b/chrome/browser/resources/memories/app.ts
@@ -5,7 +5,6 @@
 import './cluster.js';
 import './router.js';
 import './shared_style.js';
-import './strings.m.js';
 import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
 import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
 import 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.m.js';
diff --git a/chrome/browser/resources/memories/cluster.ts b/chrome/browser/resources/memories/cluster.ts
index 3d84df7..4ce41c7 100644
--- a/chrome/browser/resources/memories/cluster.ts
+++ b/chrome/browser/resources/memories/cluster.ts
@@ -4,7 +4,6 @@
 
 import './page_favicon.js';
 import './shared_vars.js';
-import './strings.m.js';
 import './top_visit.js';
 
 import {assert} from 'chrome://resources/js/assert.m.js';
diff --git a/chrome/browser/resources/memories/history_clusters.html b/chrome/browser/resources/memories/history_clusters.html
index 0ea201d..24feb7f 100644
--- a/chrome/browser/resources/memories/history_clusters.html
+++ b/chrome/browser/resources/memories/history_clusters.html
@@ -24,7 +24,8 @@
   </style>
 </head>
 <body>
-  <script type="module" src="history_clusters.js"></script>
+  <script type="module" src="strings.m.js"></script>
+  <script type="module" src="history_clusters/history_clusters.js"></script>
   <clusters-app></clusters-app>
 </body>
 </html>
diff --git a/chrome/browser/resources/memories/visit_row.html b/chrome/browser/resources/memories/visit_row.html
index ed0b8d5..dfc041b 100644
--- a/chrome/browser/resources/memories/visit_row.html
+++ b/chrome/browser/resources/memories/visit_row.html
@@ -117,7 +117,7 @@
   <template>
     <cr-action-menu role-description="$i18n{actionMenuDescription}">
       <button class="dropdown-item" on-click="onRemoveSelfButtonClick_">
-        $i18n{removeSelfFromHistory}
+        $i18n{removeFromHistory}
       </button>
       <button class="dropdown-item" on-click="onRemoveAllButtonClick_"
           hidden="[[!hasRelatedVisits_]]">
diff --git a/chrome/browser/safe_browsing/android/password_reuse_controller_android.cc b/chrome/browser/safe_browsing/android/password_reuse_controller_android.cc
index ea6f285..c76c1498 100644
--- a/chrome/browser/safe_browsing/android/password_reuse_controller_android.cc
+++ b/chrome/browser/safe_browsing/android/password_reuse_controller_android.cc
@@ -53,7 +53,7 @@
 void PasswordReuseControllerAndroid::ShowCheckPasswords() {
   JNIEnv* env = base::android::AttachCurrentThread();
 
-  PasswordCheckupLauncherHelper::LaunchLocalCheckup(
+  PasswordCheckupLauncherHelper::LaunchLocalCheckupFromPhishGuardWarningDialog(
       env, window_android_->GetJavaObject());
 
   if (done_callback_)
diff --git a/chrome/browser/signin/signin_global_error.cc b/chrome/browser/signin/signin_global_error.cc
index b128e06..d02d7ad 100644
--- a/chrome/browser/signin/signin_global_error.cc
+++ b/chrome/browser/signin/signin_global_error.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/signin/signin_global_error.h"
 
 #include "base/logging.h"
-#include "base/metrics/histogram_macros.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
@@ -87,9 +86,6 @@
     return;
   }
 
-  UMA_HISTOGRAM_ENUMERATION("Signin.Reauth",
-                            signin_metrics::HISTOGRAM_REAUTH_SHOWN,
-                            signin_metrics::HISTOGRAM_REAUTH_MAX);
   browser->window()->ShowAvatarBubbleFromAvatarButton(
       BrowserWindow::AVATAR_BUBBLE_MODE_REAUTH,
       signin_metrics::AccessPoint::ACCESS_POINT_MENU, false);
diff --git a/chrome/browser/ui/android/quickactionsearchwidget/java/src/org/chromium/chrome/browser/ui/quickactionsearchwidget/QuickActionSearchWidgetReceiverDelegateTest.java b/chrome/browser/ui/android/quickactionsearchwidget/java/src/org/chromium/chrome/browser/ui/quickactionsearchwidget/QuickActionSearchWidgetReceiverDelegateTest.java
index 2f6ade6..ab448bd3 100644
--- a/chrome/browser/ui/android/quickactionsearchwidget/java/src/org/chromium/chrome/browser/ui/quickactionsearchwidget/QuickActionSearchWidgetReceiverDelegateTest.java
+++ b/chrome/browser/ui/android/quickactionsearchwidget/java/src/org/chromium/chrome/browser/ui/quickactionsearchwidget/QuickActionSearchWidgetReceiverDelegateTest.java
@@ -76,6 +76,7 @@
 
     @Test
     @SmallTest
+    @FlakyTest(message = "https://crbug.com/1229132")
     public void testHandleStartVoiceQueryAction() {
         Intent startVoiceQueryIntent =
                 new Intent(QuickActionSearchWidgetReceiverDelegate.ACTION_START_VOICE_QUERY);
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index 44e113f3..1fe92fe 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -4405,7 +4405,7 @@
       </message>
 
       <message name="IDS_QR_CODE_SHARE_TAB_LABEL" desc="Share tab label for QR Code sharing activity."
-        meaning="Sharing QR code">
+        meaning="Sharing QR Code">
         Share
       </message>
 
@@ -4413,22 +4413,22 @@
         Scan
       </message>
 
-      <message name="IDS_QR_CODE_SHARE_DESCRIPTION" desc="Text on QR code sharing tab describing how to use the QR code.">
-        To share with people nearby, let them scan this QR code
+      <message name="IDS_QR_CODE_SHARE_DESCRIPTION" desc="Text on QR Code sharing tab describing how to use the QR Code.">
+        To share with people nearby, let them scan this QR Code
       </message>
 
-      <message name="IDS_QR_CODE_DOWNLOAD" desc="Text on QR code download button.">
+      <message name="IDS_QR_CODE_DOWNLOAD" desc="Text on QR Code download button.">
         Download
       </message>
 
       <message name="IDS_QR_CODE_ERROR_TOO_LONG"
-          desc="Error message displayed when a URL exceeds the limit for which we can generate a QR code.">
-          Can't create QR code. URL is more than <ph name="CHARACTER_LIMIT">%1$d<ex>300</ex></ph> characters.
+          desc="Error message displayed when a URL exceeds the limit for which we can generate a QR Code.">
+          Can't create QR Code. URL is more than <ph name="CHARACTER_LIMIT">%1$d<ex>300</ex></ph> characters.
       </message>
 
       <message name="IDS_QR_CODE_ERROR_UNKNOWN"
           desc="Error message displayed when an unknown error occurs.">
-          Can't create QR code
+          Can't create QR Code
       </message>
 
       <!-- Sharing Hub -->
@@ -4507,24 +4507,24 @@
         Image Copied
       </message>
 
-      <message name="IDS_QR_CODE_CAMERA_FRAMING_RECT_DESCRIPTION" desc="Text under the framing rectangle in QR code camera preview.">
-        Position QR/barcode in this frame.
+      <message name="IDS_QR_CODE_CAMERA_FRAMING_RECT_DESCRIPTION" desc="Text under the framing rectangle in QR Code camera preview.">
+        Position QR Code/barcode in this frame.
       </message>
 
-      <message name="IDS_QR_CODE_PERMISSION_DESCRIPTION" desc="Text on QR code sharing tab indicating that permissions need to be given.">
-        To scan a QR code, let Chrome use your camera
+      <message name="IDS_QR_CODE_PERMISSION_DESCRIPTION" desc="Text on QR Code sharing tab indicating that permissions need to be given.">
+        To scan a QR Code, let Chrome use your camera
       </message>
 
-      <message name="IDS_QR_CODE_OPEN_SETTINGS_DESCRIPTION" desc="Text on QR code sharing tab indicating that user needs to open settings to give camera permission.">
-        To scan a QR code, change your settings so that Chrome can use your camera
+      <message name="IDS_QR_CODE_OPEN_SETTINGS_DESCRIPTION" desc="Text on QR Code sharing tab indicating that user needs to open settings to give camera permission.">
+        To scan a QR Code, change your settings so that Chrome can use your camera
       </message>
 
-      <message name="IDS_QR_CODE_PERMISSION_CONTINUE_LABEL" desc="Text on button on QR code sharing tab triggering camera permission dialog.">
+      <message name="IDS_QR_CODE_PERMISSION_CONTINUE_LABEL" desc="Text on button on QR Code sharing tab triggering camera permission dialog.">
         Continue
       </message>
 
       <message name="IDS_QR_CODE_NO_CAMERA_ERROR" desc="Error text shown when no camera is found.">
-        To scan a QR code, use a device with a camera.
+        To scan a QR Code, use a device with a camera.
       </message>
 
       <message name="IDS_QR_CODE_DISABLED_CAMERA_ERROR" desc="Error text shown when the camera is disabled by the device policy manager.">
@@ -4539,11 +4539,11 @@
         Can't open your camera. Something went wrong.
       </message>
 
-      <message name="IDS_QR_CODE_OPEN_SETTINGS_LABEL" desc="Text on button on QR code sharing tab triggering Android settings.">
+      <message name="IDS_QR_CODE_OPEN_SETTINGS_LABEL" desc="Text on button on QR Code sharing tab triggering Android settings.">
         Open Settings
       </message>
 
-      <message name="IDS_QR_CODE_NOT_A_URL_LABEL" desc="Text on toast on QR code scanning tab indicating that the QR Code does not correspond to a URL and can not be opened.">
+      <message name="IDS_QR_CODE_NOT_A_URL_LABEL" desc="Text on toast on QR Code scanning tab indicating that the QR Code does not correspond to a URL and can not be opened.">
         This QR Code is not a URL: <ph name="QrCodeValue">%1$s<ex>QR Code Text</ex></ph>
       </message>
 
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/VoiceToolbarButtonControllerUnitTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/VoiceToolbarButtonControllerUnitTest.java
index 1a4cdd3..de2104e 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/VoiceToolbarButtonControllerUnitTest.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/VoiceToolbarButtonControllerUnitTest.java
@@ -72,8 +72,6 @@
         }
     }
 
-    private static final int WIDTH_DELTA = 50;
-
     @Rule
     public TestRule mProcessor = new Features.JUnitProcessor();
 
@@ -104,8 +102,7 @@
         MockitoAnnotations.initMocks(this);
         ShadowChromeFeatureList.reset();
 
-        mConfiguration.screenWidthDp =
-                VoiceToolbarButtonController.DEFAULT_MIN_WIDTH_DP + WIDTH_DELTA;
+        mConfiguration.screenWidthDp = VoiceToolbarButtonController.DEFAULT_MIN_WIDTH_DP;
         doReturn(mConfiguration).when(mResources).getConfiguration();
         doReturn(mResources).when(mContext).getResources();
 
@@ -138,15 +135,13 @@
         assertTrue(mVoiceToolbarButtonController.get(mTab).canShow());
 
         // Screen width shrinks below the threshold (e.g. screen rotated).
-        mConfiguration.screenWidthDp =
-                VoiceToolbarButtonController.DEFAULT_MIN_WIDTH_DP - WIDTH_DELTA;
+        mConfiguration.screenWidthDp = VoiceToolbarButtonController.DEFAULT_MIN_WIDTH_DP - 1;
         mVoiceToolbarButtonController.onConfigurationChanged(mConfiguration);
 
         assertFalse(mVoiceToolbarButtonController.get(mTab).canShow());
 
         // Make sure the opposite works as well.
-        mConfiguration.screenWidthDp =
-                VoiceToolbarButtonController.DEFAULT_MIN_WIDTH_DP + WIDTH_DELTA;
+        mConfiguration.screenWidthDp = VoiceToolbarButtonController.DEFAULT_MIN_WIDTH_DP;
         mVoiceToolbarButtonController.onConfigurationChanged(mConfiguration);
 
         assertTrue(mVoiceToolbarButtonController.get(mTab).canShow());
diff --git a/chrome/browser/ui/ash/desks_client.cc b/chrome/browser/ui/ash/desks_client.cc
index 73fa657..c7e34a8 100644
--- a/chrome/browser/ui/ash/desks_client.cc
+++ b/chrome/browser/ui/ash/desks_client.cc
@@ -9,6 +9,7 @@
 #include "ash/public/cpp/desk_template.h"
 #include "ash/public/cpp/desks_helper.h"
 #include "base/bind.h"
+#include "base/guid.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -43,16 +44,16 @@
   std::move(callback).Run(/*success=*/true, std::move(desk_template));
 }
 
-void DesksClient::UpdateDeskTemplate(double template_uuid,
+void DesksClient::UpdateDeskTemplate(const std::string& template_uuid,
                                      const std::u16string& template_name,
                                      UpdateDeskTemplateCallback callback) {}
 
-void DesksClient::DeleteDeskTemplate(double template_uuid,
+void DesksClient::DeleteDeskTemplate(const std::string& template_uuid,
                                      DeleteDeskTemplateCallback callback) {}
 
 void DesksClient::GetDeskTemplates(GetDeskTemplatesCallback callback) {}
 
-void DesksClient::LaunchDeskTemplate(double template_uuid,
+void DesksClient::LaunchDeskTemplate(const std::string& template_uuid,
                                      LaunchDeskTemplateCallback callback) {
   MaybeCreateAppLaunchHandler();
   if (!app_launch_handler_) {
@@ -62,7 +63,8 @@
 
   // TODO: Find the saved template associated with `template_uuid` from storage.
   if (!launch_template_for_test_ ||
-      launch_template_for_test_->uuid() != template_uuid) {
+      launch_template_for_test_->uuid() !=
+          base::GUID::ParseLowercase(template_uuid)) {
     std::move(callback).Run(/*success=*/false);
     return;
   }
diff --git a/chrome/browser/ui/ash/desks_client.h b/chrome/browser/ui/ash/desks_client.h
index 7294c72..10a29bb66 100644
--- a/chrome/browser/ui/ash/desks_client.h
+++ b/chrome/browser/ui/ash/desks_client.h
@@ -48,7 +48,7 @@
   // the id of an existing desk template that was previously-saved in the
   // storage. If no such existing desk template can be found or the file
   // operation has failed, |callback| will be invoked with |false| result.
-  void UpdateDeskTemplate(double template_uuid,
+  void UpdateDeskTemplate(const std::string& template_uuid,
                           const std::u16string& template_name,
                           UpdateDeskTemplateCallback callback);
 
@@ -57,7 +57,7 @@
   // deleted, |callback| will be invoked with |false| result. If it can be
   // deleted successfully, or there is no such |template_uuid| to be removed,
   // |callback| will be invoked with |true| result.
-  void DeleteDeskTemplate(double template_uuid,
+  void DeleteDeskTemplate(const std::string& template_uuid,
                           DeleteDeskTemplateCallback callback);
 
   using TemplateList = std::vector<ash::DeskTemplate*>;
@@ -72,7 +72,7 @@
   // no such id can be found or we are at the max desk limit (currently is 8)
   // so can't create new desk for the desk template, |callback| will be invoked
   // with |false| result.
-  void LaunchDeskTemplate(double template_uuid,
+  void LaunchDeskTemplate(const std::string& template_uuid,
                           LaunchDeskTemplateCallback callback);
 
  private:
diff --git a/chrome/browser/ui/ash/desks_client_browsertest.cc b/chrome/browser/ui/ash/desks_client_browsertest.cc
index 685701e..4776c24 100644
--- a/chrome/browser/ui/ash/desks_client_browsertest.cc
+++ b/chrome/browser/ui/ash/desks_client_browsertest.cc
@@ -343,7 +343,7 @@
 
 // Tests that launching a desk template creates a desk with the given name.
 IN_PROC_BROWSER_TEST_F(DesksClientTest, LaunchEmptyDeskTemplate) {
-  const double kDeskUuid = 40.0;
+  const base::GUID kDeskUuid = base::GUID::GenerateRandomV4();
   const std::u16string kDeskName(u"Test Desk Name");
 
   DesksClient* desks_client = DesksClient::Get();
@@ -355,7 +355,8 @@
   desk_template->set_template_name(kDeskName);
   SetLaunchTemplate(std::move(desk_template));
   ash::DeskSwitchAnimationWaiter waiter;
-  desks_client->LaunchDeskTemplate(kDeskUuid, base::DoNothing());
+  desks_client->LaunchDeskTemplate(kDeskUuid.AsLowercaseString(),
+                                   base::DoNothing());
   waiter.Wait();
 
   EXPECT_EQ(1, desks_helper->GetActiveDeskIndex());
@@ -365,7 +366,7 @@
 // Tests that launching the same desk template multiple times creates desks with
 // different/incremented names.
 IN_PROC_BROWSER_TEST_F(DesksClientTest, LaunchMultipleEmptyDeskTemplates) {
-  const double kDeskUuid = 40.0;
+  const base::GUID kDeskUuid = base::GUID::GenerateRandomV4();
   const std::u16string kDeskName(u"Test Desk Name");
 
   auto* desks_controller = ash::DesksController::Get();
@@ -379,7 +380,8 @@
   auto check_launch_template_desk_name =
       [kDeskUuid, desks_controller](const std::u16string& desk_name) {
         ash::DeskSwitchAnimationWaiter waiter;
-        DesksClient::Get()->LaunchDeskTemplate(kDeskUuid, base::DoNothing());
+        DesksClient::Get()->LaunchDeskTemplate(kDeskUuid.AsLowercaseString(),
+                                               base::DoNothing());
         waiter.Wait();
 
         EXPECT_EQ(desk_name, desks_controller->GetDeskName(
@@ -462,8 +464,8 @@
   ash::DeskTemplate* desk_template_ptr = desk_template.get();
   SetLaunchTemplate(std::move(desk_template));
   ash::DeskSwitchAnimationWaiter waiter;
-  DesksClient::Get()->LaunchDeskTemplate(desk_template_ptr->uuid(),
-                                         base::DoNothing());
+  DesksClient::Get()->LaunchDeskTemplate(
+      desk_template_ptr->uuid().AsLowercaseString(), base::DoNothing());
   waiter.Wait();
 
   // Verify that the settings window has been launched on the new desk (desk B).
@@ -549,8 +551,8 @@
   ash::DeskTemplate* desk_template_ptr = desk_template.get();
   SetLaunchTemplate(std::move(desk_template));
   ash::DeskSwitchAnimationWaiter waiter;
-  DesksClient::Get()->LaunchDeskTemplate(desk_template_ptr->uuid(),
-                                         base::DoNothing());
+  DesksClient::Get()->LaunchDeskTemplate(
+      desk_template_ptr->uuid().AsLowercaseString(), base::DoNothing());
   waiter.Wait();
 }
 
@@ -601,8 +603,8 @@
   ash::DeskTemplate* desk_template_ptr = desk_template.get();
   SetLaunchTemplate(std::move(desk_template));
   ash::DeskSwitchAnimationWaiter waiter;
-  DesksClient::Get()->LaunchDeskTemplate(desk_template_ptr->uuid(),
-                                         base::DoNothing());
+  DesksClient::Get()->LaunchDeskTemplate(
+      desk_template_ptr->uuid().AsLowercaseString(), base::DoNothing());
   waiter.Wait();
 
   // Verify that the browser was launched with the correct urls and active tab.
diff --git a/chrome/browser/ui/popup_browsertest.cc b/chrome/browser/ui/popup_browsertest.cc
index c3b0051..3c27e2f 100644
--- a/chrome/browser/ui/popup_browsertest.cc
+++ b/chrome/browser/ui/popup_browsertest.cc
@@ -157,7 +157,13 @@
 }
 
 // Ensure popups cannot be moved beyond the available display space by script.
-IN_PROC_BROWSER_TEST_P(PopupBrowserTest, MoveClampedToCurrentDisplay) {
+// TODO(crbug.com/1228795): Flaking on Linux Ozone
+#if defined(OS_LINUX) && defined(USE_OZONE)
+#define Maybe_MoveClampedToCurrentDisplay DISABLED_MoveClampedToCurrentDisplay
+#else
+#define Maybe_MoveClampedToCurrentDisplay MoveClampedToCurrentDisplay
+#endif
+IN_PROC_BROWSER_TEST_P(PopupBrowserTest, Maybe_MoveClampedToCurrentDisplay) {
   const auto display = GetDisplayNearestBrowser(browser());
   const char kOpenPopup[] =
       "open('.', '', 'left=' + (screen.availLeft + 50) + "
diff --git a/chrome/browser/ui/ui_features.cc b/chrome/browser/ui/ui_features.cc
index e482b61..b09c231 100644
--- a/chrome/browser/ui/ui_features.cc
+++ b/chrome/browser/ui/ui_features.cc
@@ -148,6 +148,8 @@
 const char kTabHoverCardImagesLoadingDelayParameterName[] =
     "page_loading_delay";
 const char kTabHoverCardImagesLoadedDelayParameterName[] = "page_loaded_delay";
+const char kTabHoverCardImagesCrossfadePreviewAtParameterName[] =
+    "crossfade_preview_at";
 
 // Enables tab outlines in additional situations for accessibility.
 const base::Feature kTabOutlinesInLowContrastThemes{
diff --git a/chrome/browser/ui/ui_features.h b/chrome/browser/ui/ui_features.h
index 6688b58e..349c41ea 100644
--- a/chrome/browser/ui/ui_features.h
+++ b/chrome/browser/ui/ui_features.h
@@ -92,6 +92,7 @@
 extern const char kTabHoverCardImagesNotReadyDelayParameterName[];
 extern const char kTabHoverCardImagesLoadingDelayParameterName[];
 extern const char kTabHoverCardImagesLoadedDelayParameterName[];
+extern const char kTabHoverCardImagesCrossfadePreviewAtParameterName[];
 
 extern const base::Feature kTabOutlinesInLowContrastThemes;
 
diff --git a/chrome/browser/ui/views/permission_bubble/file_handling_permission_request_dialog.cc b/chrome/browser/ui/views/permission_bubble/file_handling_permission_request_dialog.cc
index d12e2da..02dd899 100644
--- a/chrome/browser/ui/views/permission_bubble/file_handling_permission_request_dialog.cc
+++ b/chrome/browser/ui/views/permission_bubble/file_handling_permission_request_dialog.cc
@@ -72,13 +72,13 @@
       ->SetOrientation(views::LayoutOrientation::kHorizontal)
       .SetCrossAxisAlignment(views::LayoutAlignment::kStart);
 
-  // File icon.
-  auto checkbox = std::make_unique<views::Checkbox>();
+  // TODO(tluk): We should be sourcing the size of the file icon from the layout
+  // provider rather than relying on hardcoded constants.
+  constexpr int kIconSize = 16;
   auto* icon = files_view->AddChildView(
       std::make_unique<views::ImageView>(ui::ImageModel::FromVectorIcon(
           vector_icons::kDescriptionIcon,
-          ui::NativeTheme::kColorId_DefaultIconColor,
-          checkbox->GetImage(views::Button::STATE_NORMAL).width())));
+          ui::NativeTheme::kColorId_DefaultIconColor, kIconSize)));
   const int icon_margin = views::LayoutProvider::Get()->GetDistanceMetric(
       views::DISTANCE_RELATED_LABEL_HORIZONTAL);
   icon->SetProperty(views::kMarginsKey, gfx::Insets(0, 0, 0, icon_margin));
@@ -117,6 +117,7 @@
   files_label->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT);
 
   // Permanency checkbox.
+  auto checkbox = std::make_unique<views::Checkbox>();
   bool multiple_associations = false;
   std::u16string associations =
       web_app::GetFileTypeAssociationsHandledByWebAppsForDisplay(
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
index 83b25192..7f1032f 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
@@ -10,12 +10,14 @@
 #include "base/containers/mru_cache.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/numerics/ranges.h"
 #include "build/build_config.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/tabs/tab_renderer_data.h"
 #include "chrome/browser/ui/tabs/tab_style.h"
 #include "chrome/browser/ui/thumbnails/thumbnail_image.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
 #include "chrome/browser/ui/views/chrome_typography.h"
 #include "chrome/browser/ui/views/tabs/tab.h"
@@ -27,10 +29,12 @@
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/base/theme_provider.h"
+#include "ui/compositor/layer.h"
 #include "ui/gfx/animation/linear_animation.h"
 #include "ui/gfx/animation/slide_animation.h"
 #include "ui/gfx/animation/tween.h"
 #include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/rounded_corners_f.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/gfx/text_constants.h"
@@ -41,6 +45,7 @@
 #include "ui/views/bubble/bubble_frame_view.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
+#include "ui/views/layout/fill_layout.h"
 #include "ui/views/layout/flex_layout.h"
 #include "ui/views/layout/layout_provider.h"
 #include "ui/views/view_class_properties.h"
@@ -140,11 +145,234 @@
 BEGIN_METADATA(TabHoverCardBubbleView, FadeLabel, views::Label)
 END_METADATA
 
+// Represents the preview image on the hover card. Allows for a new image to be
+// faded in over the old image.
+class TabHoverCardBubbleView::ThumbnailView
+    : public views::View,
+      public views::AnimationDelegateViews {
+ public:
+  // Specifies which (if any) of the corners of the preview image will be
+  // rounded. See SetRoundedCorners() below for more information.
+  enum RoundedCorners { kNone, kTopCorners, kBottomCorners };
+
+  ThumbnailView()
+      : AnimationDelegateViews(this), image_transition_animation_(this) {
+    constexpr base::TimeDelta kImageTransitionDuration =
+        kHoverCardSlideDuration;
+    image_transition_animation_.SetDuration(kImageTransitionDuration);
+
+    // Set a reasonable preview size so that ThumbnailView() is given an
+    // appropriate amount of space in the layout.
+    target_tab_image_ = AddChildView(CreateImageView());
+    image_fading_out_ = AddChildView(CreateImageView());
+    image_fading_out_->SetPaintToLayer();
+    image_fading_out_->layer()->SetOpacity(0.0f);
+
+    // Because all preview images should be the same size, we can just set the
+    // preferred size of this view and then use a FillLayout to force the to
+    // ImageViews to the correct size.
+    SetPreferredSize(TabStyle::GetPreviewImageSize());
+    SetLayoutManager(std::make_unique<views::FillLayout>());
+  }
+
+  // Set the preview image to be visible. Included to match with Hide().
+  void Show() { SetVisible(true); }
+
+  // Set the preview image to not be visible. Stops any current fade animation
+  // and clears out all of the images to prevent flicker when the preview image
+  // transitions from visible to invisible and vice-versa.
+  void Hide() {
+    SetVisible(false);
+    // This will result in the fading image being discarded via the canceled
+    // event.
+    image_transition_animation_.End();
+    target_tab_image_->SetImage(gfx::ImageSkia());
+    target_tab_image_->SetBackground(nullptr);
+  }
+
+  // Sets the appropriate rounded corners for the preview image, for platforms
+  // where layers must be explicitly clipped (because they are not clipped by
+  // the widget). Set `rounded_corners` to kTopCorners if the preview image is
+  // the topmost view in the widget (including header); set kBottomCorners if
+  // the preview is the bottom-most view (including footer). If neither, use
+  // kNone.
+  void SetRoundedCorners(RoundedCorners rounded_corners, float radius) {
+    gfx::RoundedCornersF corners;
+    switch (rounded_corners) {
+      case RoundedCorners::kNone:
+        corners = {0, 0, 0, 0};
+        break;
+      case RoundedCorners::kTopCorners:
+        corners = {radius, radius, 0, 0};
+        break;
+      case RoundedCorners::kBottomCorners:
+        corners = {0, 0, radius, radius};
+        break;
+    }
+    image_fading_out_->layer()->SetRoundedCornerRadius(corners);
+  }
+
+  // Sets the new preview image. The old image will be faded out.
+  void SetTargetTabImage(gfx::ImageSkia preview_image) {
+    StartFadeOut();
+    SetImage(target_tab_image_, preview_image, /* is_placeholder = */ false);
+    showing_placeholder_image_ = false;
+  }
+
+  // Clears the preview image and replaces it with a placeholder image. The old
+  // image will be faded out.
+  void SetPlaceholderImage() {
+    if (showing_placeholder_image_)
+      return;
+
+    // Theme provider may be null if there is no associated widget. In that case
+    // there is nothing to render, and we can't get theme default colors to
+    // render with anyway, so bail out.
+    const ui::ThemeProvider* const theme_provider = GetThemeProvider();
+    if (!theme_provider)
+      return;
+
+    StartFadeOut();
+
+    // Check the no-preview color and size to see if it needs to be
+    // regenerated. DPI or theme change can cause a regeneration.
+    const SkColor foreground_color = theme_provider->GetColor(
+        ThemeProperties::COLOR_HOVER_CARD_NO_PREVIEW_FOREGROUND);
+
+    // Set the no-preview placeholder image. All sizes are in DIPs.
+    // gfx::CreateVectorIcon() caches its result so there's no need to store
+    // images here; if a particular size/color combination has already been
+    // requested it will be low-cost to request it again.
+    constexpr gfx::Size kNoPreviewImageSize{64, 64};
+    const gfx::ImageSkia no_preview_image = gfx::CreateVectorIcon(
+        kGlobeIcon, kNoPreviewImageSize.width(), foreground_color);
+    SetImage(target_tab_image_, no_preview_image, /* is_placeholder = */ true);
+    showing_placeholder_image_ = true;
+  }
+
+ private:
+  // Creates an image view with the appropriate default properties.
+  static std::unique_ptr<views::ImageView> CreateImageView() {
+    auto image_view = std::make_unique<views::ImageView>();
+    using Alignment = views::ImageView::Alignment;
+    image_view->SetHorizontalAlignment(Alignment::kCenter);
+    image_view->SetVerticalAlignment(Alignment::kCenter);
+    return image_view;
+  }
+
+  // Sets `image` on `image_view_`, configuring the image appropriately based
+  // on whether it's a placeholder or not.
+  static void SetImage(views::ImageView* image_view,
+                       gfx::ImageSkia image,
+                       bool is_placeholder) {
+    image_view->SetImage(image);
+    if (is_placeholder) {
+      image_view->SetImage(image);
+      image_view->SetImageSize(image.size());
+
+      // Also possibly regenerate the background if it has changed.
+      const SkColor background_color = image_view->GetThemeProvider()->GetColor(
+          ThemeProperties::COLOR_HOVER_CARD_NO_PREVIEW_BACKGROUND);
+      if (!image_view->background() ||
+          image_view->background()->get_color() != background_color) {
+        image_view->SetBackground(
+            views::CreateSolidBackground(background_color));
+      }
+    } else {
+      const gfx::Size preview_size = TabStyle::GetPreviewImageSize();
+      image_view->SetImage(image);
+      image_view->SetImageSize(GetPreviewImageSize(image.size(), preview_size));
+      image_view->SetBackground(nullptr);
+    }
+  }
+
+  // views::AnimationDelegateViews:
+  void AnimationProgressed(const gfx::Animation* animation) override {
+    image_fading_out_->layer()->SetOpacity(1.0 - animation->GetCurrentValue());
+  }
+
+  void AnimationEnded(const gfx::Animation* animation) override {
+    image_fading_out_->layer()->SetOpacity(0.0f);
+    image_fading_out_->SetImage(gfx::ImageSkia());
+  }
+
+  void AnimationCanceled(const gfx::Animation* animation) override {
+    AnimationEnded(animation);
+  }
+
+  // Begins fading out the existing image, which it reads from
+  // `target_tab_image_`. Does a smart three-way crossfade if an image is
+  // already fading out.
+  void StartFadeOut() {
+    if (!GetVisible())
+      return;
+
+    if (!GetPreviewImageCrossfadeStart().has_value())
+      return;
+
+    gfx::ImageSkia old_image = target_tab_image_->GetImage();
+    if (old_image.isNull())
+      return;
+
+    if (image_transition_animation_.is_animating()) {
+      // If we're already animating and we've barely faded out the previous old
+      // image, keep fading out the old one and just swap the new one
+      // underneath.
+      const double current_value =
+          image_transition_animation_.GetCurrentValue();
+      if (current_value <= 0.5)
+        return;
+
+      // Currently we have:
+      //  - old preview at `current_value` opacity
+      //  - previous old preview at 1.0 - `current_value` opacity
+      // We will discard the previous old preview and move the old preview into
+      // the occluding view. However, since the opacity of this view is
+      // inversely proportional to animation progress, to keep the same opacity
+      // (while we swap the new image in behind) we have to rewind the
+      // animation.
+      image_transition_animation_.SetCurrentValue(1.0 - current_value);
+      SetImage(image_fading_out_, old_image, showing_placeholder_image_);
+      AnimationProgressed(&image_transition_animation_);
+
+    } else {
+      SetImage(image_fading_out_, old_image, showing_placeholder_image_);
+      image_fading_out_->layer()->SetOpacity(1.0f);
+      image_transition_animation_.Start();
+    }
+  }
+
+  // Displays the image that we are trying to display for the target/current
+  // tab. Placed under `image_fading_out_` so that it is revealed as the
+  // previous image fades out.
+  views::ImageView* target_tab_image_ = nullptr;
+
+  // Displays the previous image as it's fading out. Rendered over
+  // `target_tab_image_` and has its alpha animated from 1 to 0.
+  views::ImageView* image_fading_out_ = nullptr;
+
+  // Provides a smooth fade out for `image_fading_out_`. We do not use a
+  // LayerAnimation because we need to rewind the transparency at various
+  // times (it's not necessarily a single smooth animation).
+  gfx::LinearAnimation image_transition_animation_;
+
+  // Records whether `target_tab_image_` is showing a placeholder image. Used
+  // to configure `image_fading_out_` when the target image becomes the
+  // previous image and fades out.
+  bool showing_placeholder_image_ = false;
+};
+
+// static
+constexpr base::TimeDelta TabHoverCardBubbleView::kHoverCardSlideDuration;
+
 TabHoverCardBubbleView::TabHoverCardBubbleView(Tab* tab)
     : BubbleDialogDelegateView(tab,
                                views::BubbleBorder::TOP_LEFT,
-                               views::BubbleBorder::STANDARD_SHADOW),
-      using_rounded_corners_(CustomShadowsSupported()) {
+                               views::BubbleBorder::STANDARD_SHADOW) {
+  if (CustomShadowsSupported()) {
+    corner_radius_ = ChromeLayoutProvider::Get()->GetCornerRadiusMetric(
+        views::Emphasis::kHigh);
+  }
   SetButtons(ui::DIALOG_BUTTON_NONE);
 
   // We'll do all of our own layout inside the bubble, so no need to inset this
@@ -198,14 +426,10 @@
   domain_fade_label_->GetViewAccessibility().OverrideIsIgnored(true);
 
   if (TabHoverCardController::AreHoverCardImagesEnabled()) {
-    using Alignment = views::ImageView::Alignment;
-    const gfx::Size preview_size = TabStyle::GetPreviewImageSize();
-    preview_image_ = AddChildView(std::make_unique<views::ImageView>());
-    preview_image_->SetVisible(true);
-    preview_image_->SetHorizontalAlignment(Alignment::kCenter);
-    preview_image_->SetVerticalAlignment(Alignment::kCenter);
-    preview_image_->SetImageSize(preview_size);
-    preview_image_->SetPreferredSize(preview_size);
+    thumbnail_view_ = AddChildView(std::make_unique<ThumbnailView>());
+    thumbnail_view_->SetRoundedCorners(
+        ThumbnailView::RoundedCorners::kBottomCorners,
+        corner_radius_.value_or(0));
   }
 
   // Set up layout.
@@ -241,7 +465,7 @@
   title_label_->SetProperty(
       views::kFlexBehaviorKey,
       views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToMinimum,
-                               views::MaximumFlexSizeRule::kPreferred));
+                               views::MaximumFlexSizeRule::kUnbounded));
 
   // Set up widget.
 
@@ -260,11 +484,8 @@
       views::BubbleFrameView::PreferredArrowAdjustment::kOffset);
   GetBubbleFrameView()->set_hit_test_transparent(true);
 
-  if (using_rounded_corners_) {
-    GetBubbleFrameView()->SetCornerRadius(
-        ChromeLayoutProvider::Get()->GetCornerRadiusMetric(
-            views::Emphasis::kHigh));
-  }
+  if (using_rounded_corners())
+    GetBubbleFrameView()->SetCornerRadius(corner_radius_.value());
 
   // Start in the fully "faded-in" position so that whatever text we initially
   // display is visible.
@@ -287,8 +508,12 @@
 
 void TabHoverCardBubbleView::UpdateCardContent(const Tab* tab) {
   // Preview image is never visible for the active tab.
-  if (preview_image_)
-    preview_image_->SetVisible(!tab->IsActive());
+  if (thumbnail_view_) {
+    if (tab->IsActive())
+      thumbnail_view_->Hide();
+    else
+      thumbnail_view_->Show();
+  }
 
   std::u16string title;
   absl::optional<TabAlertState> old_alert_state = alert_state_;
@@ -334,6 +559,15 @@
         alert_state_.has_value() ? CreateAlertView(*alert_state_) : nullptr);
   }
 
+  // We only clip the corners of the fade image when there isn't a footer.
+  if (thumbnail_view_) {
+    thumbnail_view_->SetRoundedCorners(
+        GetBubbleFrameView()->GetFootnoteView()
+            ? ThumbnailView::RoundedCorners::kNone
+            : ThumbnailView::RoundedCorners::kBottomCorners,
+        corner_radius_.value_or(0));
+  }
+
   domain_fade_label_->SetText(domain_label_->GetText());
   domain_label_->SetText(domain);
 
@@ -348,54 +582,26 @@
   domain_fade_label_->SetFade(percent);
 }
 
-void TabHoverCardBubbleView::ClearPreviewImage() {
-  DCHECK(preview_image_)
+void TabHoverCardBubbleView::SetTargetTabImage(gfx::ImageSkia preview_image) {
+  DCHECK(thumbnail_view_)
       << "This method should only be called when preview images are enabled.";
-
-  // This can return null if there is no associated widget, etc. In that case
-  // there is nothing to render, and we can't get theme default colors to render
-  // with anyway, so bail out. This should hopefully address crbug.com/1070980
-  // (Null dereference
-  const ui::ThemeProvider* const theme_provider = GetThemeProvider();
-  if (!theme_provider)
-    return;
-
-  // Check the no-preview color and size to see if it needs to be
-  // regenerated. DPI or theme change can cause a regeneration.
-  const SkColor foreground_color = theme_provider->GetColor(
-      ThemeProperties::COLOR_HOVER_CARD_NO_PREVIEW_FOREGROUND);
-
-  // Set the no-preview placeholder image. All sizes are in DIPs.
-  // gfx::CreateVectorIcon() caches its result so there's no need to store
-  // images here; if a particular size/color combination has already been
-  // requested it will be low-cost to request it again.
-  constexpr gfx::Size kNoPreviewImageSize{64, 64};
-  const gfx::ImageSkia no_preview_image = gfx::CreateVectorIcon(
-      kGlobeIcon, kNoPreviewImageSize.width(), foreground_color);
-  preview_image_->SetImage(no_preview_image);
-  preview_image_->SetImageSize(kNoPreviewImageSize);
-  preview_image_->SetPreferredSize(TabStyle::GetPreviewImageSize());
-
-  // Also possibly regenerate the background if it has changed.
-  const SkColor background_color = theme_provider->GetColor(
-      ThemeProperties::COLOR_HOVER_CARD_NO_PREVIEW_BACKGROUND);
-  if (!preview_image_->background() ||
-      preview_image_->background()->get_color() != background_color) {
-    preview_image_->SetBackground(
-        views::CreateSolidBackground(background_color));
-  }
+  thumbnail_view_->SetTargetTabImage(preview_image);
 }
 
-void TabHoverCardBubbleView::SetPreviewImage(gfx::ImageSkia preview_image) {
-  DCHECK(preview_image_)
+void TabHoverCardBubbleView::SetPlaceholderImage() {
+  DCHECK(thumbnail_view_)
       << "This method should only be called when preview images are enabled.";
+  thumbnail_view_->SetPlaceholderImage();
+}
 
-  const gfx::Size preview_size = TabStyle::GetPreviewImageSize();
-  preview_image_->SetImage(preview_image);
-  preview_image_->SetImageSize(
-      GetPreviewImageSize(preview_image.size(), preview_size));
-  preview_image_->SetPreferredSize(preview_size);
-  preview_image_->SetBackground(nullptr);
+// static
+absl::optional<double> TabHoverCardBubbleView::GetPreviewImageCrossfadeStart() {
+  static const double start_percent = base::GetFieldTrialParamByFeatureAsDouble(
+      features::kTabHoverCardImages,
+      features::kTabHoverCardImagesCrossfadePreviewAtParameterName, -1.0);
+  return start_percent >= 0.0
+             ? absl::make_optional(base::ClampToRange(start_percent, 0.0, 1.0))
+             : absl::nullopt;
 }
 
 gfx::Size TabHoverCardBubbleView::CalculatePreferredSize() const {
@@ -410,7 +616,7 @@
 
   // Bubble closes if the theme changes to the point where the border has to be
   // regenerated. See crbug.com/1140256
-  if (using_rounded_corners_ != CustomShadowsSupported()) {
+  if (using_rounded_corners() != CustomShadowsSupported()) {
     GetWidget()->Close();
     return;
   }
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h
index 031fbda6..3109479 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h
@@ -7,14 +7,17 @@
 
 #include "base/callback_list.h"
 #include "base/scoped_observation.h"
+#include "base/time/time.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/tabs/tab_utils.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/base/metadata/metadata_header_macros.h"
+#include "ui/gfx/animation/linear_animation.h"
+#include "ui/views/animation/animation_delegate_views.h"
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/public/cpp/metrics_util.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
 #endif
 
 namespace gfx {
@@ -22,7 +25,6 @@
 }
 
 namespace views {
-class ImageView;
 class Label;
 }  // namespace views
 
@@ -31,6 +33,9 @@
 // Dialog that displays an informational hover card containing page information.
 class TabHoverCardBubbleView : public views::BubbleDialogDelegateView {
  public:
+  static constexpr base::TimeDelta kHoverCardSlideDuration =
+      base::TimeDelta::FromMilliseconds(200);
+
   METADATA_HEADER(TabHoverCardBubbleView);
   explicit TabHoverCardBubbleView(Tab* tab);
   TabHoverCardBubbleView(const TabHoverCardBubbleView&) = delete;
@@ -43,13 +48,25 @@
   // Update the text fade to the given percent, which should be between 0 and 1.
   void SetTextFade(double percent);
 
-  void ClearPreviewImage();
-  void SetPreviewImage(gfx::ImageSkia preview_image);
+  // Set the preview image to use for the target tab.
+  void SetTargetTabImage(gfx::ImageSkia preview_image);
+
+  // Specifies that the hover card should display a placeholder image
+  // specifying that no preview for the tab is available (yet).
+  void SetPlaceholderImage();
+
+  // Returns the percentage complete during transition animations when a
+  // pre-emptive crossfade to a placeholder should start if a new image is not
+  // available, or `absl::nullopt` to disable crossfades entirely.
+  static absl::optional<double> GetPreviewImageCrossfadeStart();
 
  private:
   friend class TabHoverCardBubbleViewBrowserTest;
   friend class TabHoverCardBubbleViewInteractiveUiTest;
   class FadeLabel;
+  class ThumbnailView;
+
+  bool using_rounded_corners() const { return corner_radius_.has_value(); }
 
   // views::BubbleDialogDelegateView:
   ax::mojom::Role GetAccessibleWindowRole() override;
@@ -62,9 +79,9 @@
   absl::optional<TabAlertState> alert_state_;
   views::Label* domain_label_ = nullptr;
   FadeLabel* domain_fade_label_ = nullptr;
-  views::ImageView* preview_image_ = nullptr;
+  ThumbnailView* thumbnail_view_ = nullptr;
 
-  const bool using_rounded_corners_;
+  absl::optional<int> corner_radius_;
 };
 
 #endif  // CHROME_BROWSER_UI_VIEWS_TABS_TAB_HOVER_CARD_BUBBLE_VIEW_H_
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_controller.cc b/chrome/browser/ui/views/tabs/tab_hover_card_controller.cc
index e3c482b8..5021d77 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_controller.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h"
 #include "chrome/browser/ui/views/tabs/tab_hover_card_thumbnail_observer.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_observer.h"
@@ -342,7 +343,7 @@
 
   if (thumbnail_observer_) {
     thumbnail_observer_->Observe(nullptr);
-    waiting_for_preview_ = false;
+    thumbnail_wait_state_ = ThumbnailWaitState::kNotWaiting;
   }
   // This needs to be called whether we're doing a fade or a pop out.
   metrics_->CardWillBeHidden();
@@ -400,6 +401,8 @@
   hover_card_observation_.Observe(hover_card_);
   event_sniffer_ = std::make_unique<EventSniffer>(this);
   slide_animator_ = std::make_unique<views::BubbleSlideAnimator>(hover_card_);
+  slide_animator_->SetSlideDuration(
+      TabHoverCardBubbleView::kHoverCardSlideDuration);
   slide_progressed_subscription_ = slide_animator_->AddSlideProgressedCallback(
       base::BindRepeating(&TabHoverCardController::OnSlideAnimationProgressed,
                           base::Unretained(this)));
@@ -445,7 +448,8 @@
 
   auto thumbnail = tab->data().thumbnail;
   if (!thumbnail) {
-    hover_card_->ClearPreviewImage();
+    hover_card_->SetPlaceholderImage();
+    thumbnail_wait_state_ = ThumbnailWaitState::kNotWaiting;
     return;
   }
 
@@ -453,7 +457,14 @@
     return;
 
   // We're definitely going to wait for an image at some point.
-  waiting_for_preview_ = true;
+  const auto crossfade_at =
+      TabHoverCardBubbleView::GetPreviewImageCrossfadeStart();
+  if (crossfade_at.has_value() && crossfade_at.value() == 0.0) {
+    hover_card_->SetPlaceholderImage();
+    thumbnail_wait_state_ = ThumbnailWaitState::kWaitingWithPlaceholder;
+  } else {
+    thumbnail_wait_state_ = ThumbnailWaitState::kWaitingWithoutPlaceholder;
+  }
   // For the first show there has already been a delay, so it's fine to ask for
   // the image immediately; same is true if we already have a thumbnail.
   //  Otherwise the delay is based on the capture readiness.
@@ -466,7 +477,11 @@
   } else if (!delayed_show_timer_.IsRunning()) {
     // Stop updating the preview image unless/until we re-enable capture.
     thumbnail_observer_->Observe(nullptr);
-    hover_card_->ClearPreviewImage();
+    if (thumbnail_wait_state_ ==
+        ThumbnailWaitState::kWaitingWithoutPlaceholder) {
+      hover_card_->SetPlaceholderImage();
+      thumbnail_wait_state_ = ThumbnailWaitState::kWaitingWithPlaceholder;
+    }
     delayed_show_timer_.Start(
         FROM_HERE, capture_delay,
         base::BindOnce(&TabHoverCardController::StartThumbnailObservation,
@@ -480,7 +495,7 @@
 
   DCHECK(tab);
   DCHECK(hover_card_);
-  DCHECK(waiting_for_preview_);
+  DCHECK(waiting_for_preview());
 
   auto thumbnail = tab->data().thumbnail;
   if (!thumbnail || thumbnail == thumbnail_observer_->current_image())
@@ -518,8 +533,8 @@
 }
 
 void TabHoverCardController::OnCardFullyVisible() {
-  const bool has_preview =
-      ArePreviewsEnabled() && !target_tab_->IsActive() && !waiting_for_preview_;
+  const bool has_preview = ArePreviewsEnabled() && !target_tab_->IsActive() &&
+                           !waiting_for_preview();
   metrics_->CardFullyVisibleOnTab(target_tab_, has_preview);
 }
 
@@ -542,6 +557,14 @@
     double value) {
   if (hover_card_)
     hover_card_->SetTextFade(value);
+  if (thumbnail_wait_state_ == ThumbnailWaitState::kWaitingWithoutPlaceholder) {
+    const auto crossfade_start =
+        TabHoverCardBubbleView::GetPreviewImageCrossfadeStart();
+    if (crossfade_start.has_value() && value >= crossfade_start.value()) {
+      hover_card_->SetPlaceholderImage();
+      thumbnail_wait_state_ = ThumbnailWaitState::kWaitingWithPlaceholder;
+    }
+  }
 }
 
 void TabHoverCardController::OnSlideAnimationComplete(
@@ -554,8 +577,10 @@
   // keep showing the old image while hovering on the new tab, so clear it. This
   // shouldn't happen very often for slide animations, but could on slower
   // computers.
-  if (waiting_for_preview_)
-    hover_card_->ClearPreviewImage();
+  if (thumbnail_wait_state_ == ThumbnailWaitState::kWaitingWithoutPlaceholder) {
+    hover_card_->SetPlaceholderImage();
+    thumbnail_wait_state_ = ThumbnailWaitState::kWaitingWithPlaceholder;
+  }
 
   OnCardFullyVisible();
 }
@@ -565,8 +590,8 @@
     gfx::ImageSkia thumbnail_image) {
   DCHECK_EQ(thumbnail_observer_.get(), observer);
 
-  const bool was_waiting_for_preview = waiting_for_preview_;
-  waiting_for_preview_ = false;
+  const bool was_waiting_for_preview = waiting_for_preview();
+  thumbnail_wait_state_ = ThumbnailWaitState::kNotWaiting;
 
   // The hover card could be destroyed before the preview image is delivered.
   if (!hover_card_)
@@ -575,5 +600,5 @@
     metrics_->ImageLoadedForTab(target_tab_);
   // Can still set image on a fading-out hover card (we can change this behavior
   // later if we want).
-  hover_card_->SetPreviewImage(thumbnail_image);
+  hover_card_->SetTargetTabImage(thumbnail_image);
 }
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_controller.h b/chrome/browser/ui/views/tabs/tab_hover_card_controller.h
index fd9bd69..0b21d88 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_controller.h
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_controller.h
@@ -10,6 +10,7 @@
 #include "base/callback_list.h"
 #include "base/gtest_prod_util.h"
 #include "base/scoped_observation.h"
+#include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/ui/views/tabs/tab_controller.h"
 #include "chrome/browser/ui/views/tabs/tab_hover_card_metrics.h"
@@ -54,6 +55,12 @@
                            SetPreviewWithNoHoverCardDoesntCrash);
   class EventSniffer;
 
+  enum ThumbnailWaitState {
+    kNotWaiting,
+    kWaitingWithPlaceholder,
+    kWaitingWithoutPlaceholder
+  };
+
   static bool UseAnimations();
 
   // views::ViewObserver:
@@ -93,6 +100,10 @@
 
   TabHoverCardMetrics* metrics_for_testing() const { return metrics_.get(); }
 
+  bool waiting_for_preview() const {
+    return thumbnail_wait_state_ != ThumbnailWaitState::kNotWaiting;
+  }
+
   // Timestamp of the last time the hover card is hidden by the mouse leaving
   // the tab strip. This is used for reshowing the hover card without delay if
   // the mouse reenters within a given amount of time.
@@ -121,7 +132,7 @@
 
   std::unique_ptr<TabHoverCardThumbnailObserver> thumbnail_observer_;
   base::CallbackListSubscription thumbnail_subscription_;
-  bool waiting_for_preview_ = false;
+  ThumbnailWaitState thumbnail_wait_state_ = ThumbnailWaitState::kNotWaiting;
 
   base::CallbackListSubscription fade_complete_subscription_;
   base::CallbackListSubscription slide_progressed_subscription_;
diff --git a/chrome/browser/ui/views/web_apps/web_app_identity_update_confirmation_view.cc b/chrome/browser/ui/views/web_apps/web_app_identity_update_confirmation_view.cc
index 5014d1d..8083161 100644
--- a/chrome/browser/ui/views/web_apps/web_app_identity_update_confirmation_view.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_identity_update_confirmation_view.cc
@@ -15,6 +15,7 @@
 #include "content/public/browser/web_contents.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/base/models/image_model.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/controls/image_view.h"
@@ -135,11 +136,10 @@
   old_icon_image_view->SetImage(gfx::ImageSkia::CreateFrom1xBitmap(old_icon));
   layout->AddView(std::move(old_icon_image_view));
 
-  auto arrow = std::make_unique<views::ImageView>();
-  arrow->SetImage(
-      gfx::CreateVectorIcon(kKeyboardArrowRightIcon, kArrowIconSizeDp,
-                            GetNativeTheme()->GetSystemColor(
-                                ui::NativeTheme::kColorId_DefaultIconColor)));
+  auto arrow =
+      std::make_unique<views::ImageView>(ui::ImageModel::FromVectorIcon(
+          kKeyboardArrowRightIcon, ui::NativeTheme::kColorId_DefaultIconColor,
+          kArrowIconSizeDp));
   layout->AddView(std::move(arrow));
 
   auto new_icon_image_view = std::make_unique<views::ImageView>();
diff --git a/chrome/browser/ui/webui/extensions/extensions_internals_source.cc b/chrome/browser/ui/webui/extensions/extensions_internals_source.cc
index 057b2e9..c57ea396 100644
--- a/chrome/browser/ui/webui/extensions/extensions_internals_source.cc
+++ b/chrome/browser/ui/webui/extensions/extensions_internals_source.cc
@@ -55,6 +55,8 @@
       return "TYPE_SHARED_MODULE";
     case extensions::Manifest::TYPE_LOGIN_SCREEN_EXTENSION:
       return "TYPE_LOGIN_SCREEN_EXTENSION";
+    case extensions::Manifest::TYPE_CHROMEOS_SYSTEM_EXTENSION:
+      return "TYPE_CHROMEOS_SYSTEM_EXTENSION";
     case extensions::Manifest::NUM_LOAD_TYPES:
       break;
   }
diff --git a/chrome/browser/ui/webui/history_clusters/memories_ui.cc b/chrome/browser/ui/webui/history_clusters/memories_ui.cc
index 1578012..8df8050 100644
--- a/chrome/browser/ui/webui/history_clusters/memories_ui.cc
+++ b/chrome/browser/ui/webui/history_clusters/memories_ui.cc
@@ -27,17 +27,17 @@
 
   static constexpr webui::LocalizedString kStrings[] = {
       {"actionMenuDescription", IDS_HISTORY_ACTION_MENU_DESCRIPTION},
+      {"bookmarked", IDS_HISTORY_ENTRY_BOOKMARKED},
       {"cancel", IDS_CANCEL},
-      {"remove", IDS_HISTORY_DELETE_PRIOR_VISITS_CONFIRM_BUTTON},
+      {"deleteConfirm", IDS_HISTORY_DELETE_PRIOR_VISITS_CONFIRM_BUTTON},
+      {"deleteWarning", IDS_HISTORY_DELETE_PRIOR_VISITS_WARNING},
+      {"removeFromHistory", IDS_HISTORY_REMOVE_PAGE},
       {"removeSelected", IDS_HISTORY_REMOVE_SELECTED_ITEMS},
-      {"removeSelfFromHistory", IDS_HISTORY_REMOVE_PAGE},
-      {"removeWarning", IDS_HISTORY_DELETE_PRIOR_VISITS_WARNING},
       {"title", IDS_MEMORIES_PAGE_TITLE},
   };
   source->AddLocalizedStrings(kStrings);
 
   // TODO(crbug.com/1173908): Replace these with localized strings.
-  source->AddString("bookmarked", u"Bookmarked");
   source->AddString("clearLabel", u"Clear search");
   source->AddString("headerTitle", u"Based on web activity related to \"$1\"");
   source->AddString("relatedSearchesLabel", u"Related:");
@@ -46,7 +46,6 @@
   source->AddString("searchPrompt", u"Search clusters");
   source->AddString("toggleButtonLabelLess", u"Show less");
   source->AddString("toggleButtonLabelMore", u"Show more");
-  source->AddString("visitsSectionHeader", u"From Chrome History");
 
   webui::SetupWebUIDataSource(
       source,
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc
index 9b0ef76d..965b3b7 100644
--- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc
+++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc
@@ -352,8 +352,9 @@
 
 // static
 void NewTabPageHandler::RegisterProfilePrefs(PrefRegistrySimple* registry) {
-  registry->RegisterBooleanPref(prefs::kNtpModulesVisible, true);
   registry->RegisterListPref(prefs::kNtpDisabledModules, true);
+  registry->RegisterListPref(prefs::kNtpModulesOrder, true);
+  registry->RegisterBooleanPref(prefs::kNtpModulesVisible, true);
 }
 
 void NewTabPageHandler::SetMostVisitedSettings(bool custom_links_enabled,
diff --git a/chrome/browser/ui/webui/policy/policy_ui_browsertest.cc b/chrome/browser/ui/webui/policy/policy_ui_browsertest.cc
index 6006b3e..de6d439 100644
--- a/chrome/browser/ui/webui/policy/policy_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/policy/policy_ui_browsertest.cc
@@ -267,8 +267,8 @@
 PolicyUITest::~PolicyUITest() {}
 
 void PolicyUITest::SetUpInProcessBrowserTestFixture() {
-  ON_CALL(provider_, IsInitializationComplete(_)).WillByDefault(Return(true));
-  ON_CALL(provider_, IsFirstPolicyLoadComplete(_)).WillByDefault(Return(true));
+  provider_.SetDefaultReturns(/*is_initialization_complete_return=*/true,
+                              /*is_first_policy_load_complete_return=*/true);
   policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_);
   policy::PushProfilePolicyConnectorProviderForTesting(&provider_);
 
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_power_handler_browsertest.cc b/chrome/browser/ui/webui/settings/chromeos/device_power_handler_browsertest.cc
index fd94ad4..aba54d7 100644
--- a/chrome/browser/ui/webui/settings/chromeos/device_power_handler_browsertest.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/device_power_handler_browsertest.cc
@@ -83,9 +83,8 @@
   // InProcessBrowserTest:
   void SetUpInProcessBrowserTestFixture() override {
     // Initialize user policy.
-    ON_CALL(provider_, IsInitializationComplete(_)).WillByDefault(Return(true));
-    ON_CALL(provider_, IsFirstPolicyLoadComplete(_))
-        .WillByDefault(Return(true));
+    provider_.SetDefaultReturns(/*is_initialization_complete_return=*/true,
+                                /*is_first_policy_load_complete_return=*/true);
     policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_);
   }
 
diff --git a/chrome/browser/ui/webui/settings/metrics_reporting_handler_unittest.cc b/chrome/browser/ui/webui/settings/metrics_reporting_handler_unittest.cc
index c587ad61..9e61775f 100644
--- a/chrome/browser/ui/webui/settings/metrics_reporting_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/metrics_reporting_handler_unittest.cc
@@ -43,8 +43,8 @@
     handler_ = std::make_unique<TestingMetricsReportingHandler>();
     handler_->set_web_ui(&test_web_ui_);
 
-    EXPECT_CALL(provider_, IsInitializationComplete(testing::_)).WillRepeatedly(
-        testing::Return(true));
+    provider_.SetDefaultReturns(/*is_initialization_complete_return=*/true,
+                                /*is_first_policy_load_complete_return=*/true);
     policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_);
   }
 
@@ -83,7 +83,7 @@
   std::unique_ptr<ScopedTestingLocalState> local_state_;
   std::unique_ptr<TestingMetricsReportingHandler> handler_;
 
-  policy::MockConfigurationPolicyProvider provider_;
+  testing::NiceMock<policy::MockConfigurationPolicyProvider> provider_;
   policy::PolicyMap map_;
 };
 
diff --git a/chrome/browser/ui/webui/settings/people_handler.cc b/chrome/browser/ui/webui/settings/people_handler.cc
index 889af24..4c17ccf7 100644
--- a/chrome/browser/ui/webui/settings/people_handler.cc
+++ b/chrome/browser/ui/webui/settings/people_handler.cc
@@ -11,7 +11,6 @@
 #include "base/compiler_specific.h"
 #include "base/i18n/time_formatting.h"
 #include "base/json/json_reader.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
@@ -345,10 +344,6 @@
   // re-auth scenario, and we need to ensure that the user signs in with the
   // same email address.
   if (identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSync)) {
-    UMA_HISTOGRAM_ENUMERATION("Signin.Reauth",
-                              signin_metrics::HISTOGRAM_REAUTH_SHOWN,
-                              signin_metrics::HISTOGRAM_REAUTH_MAX);
-
     SigninErrorController* error_controller =
         SigninErrorControllerFactory::GetForProfile(browser->profile());
     DCHECK(error_controller->HasError());
diff --git a/chrome/browser/ui/webui/settings/settings_secure_dns_handler_browsertest.cc b/chrome/browser/ui/webui/settings/settings_secure_dns_handler_browsertest.cc
index c1d3caa..056257c 100644
--- a/chrome/browser/ui/webui/settings/settings_secure_dns_handler_browsertest.cc
+++ b/chrome/browser/ui/webui/settings/settings_secure_dns_handler_browsertest.cc
@@ -111,9 +111,8 @@
   // InProcessBrowserTest:
   void SetUpInProcessBrowserTestFixture() override {
     // Initialize user policy.
-    ON_CALL(provider_, IsInitializationComplete(_)).WillByDefault(Return(true));
-    ON_CALL(provider_, IsFirstPolicyLoadComplete(_))
-        .WillByDefault(Return(true));
+    provider_.SetDefaultReturns(/*is_initialization_complete_return=*/true,
+                                /*is_first_policy_load_complete_return=*/true);
     policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_);
   }
 
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc b/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc
index 4c9e87e..ea1b0072 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc
@@ -7,7 +7,6 @@
 #include <memory>
 #include <string>
 
-#include "ash/components/account_manager/account_manager_ash.h"
 #include "ash/components/account_manager/account_manager_factory.h"
 #include "ash/constants/ash_pref_names.h"
 #include "base/base64.h"
@@ -31,7 +30,9 @@
 #include "chrome/browser/ui/webui/signin/signin_helper_chromeos.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/dbus/util/version_loader.h"
+#include "components/account_manager_core/account.h"
 #include "components/account_manager_core/account_manager_facade.h"
+#include "components/account_manager_core/chromeos/account_manager_ash.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/public/identity_manager/account_info.h"
diff --git a/chrome/browser/ui/webui/signin/signin_helper_chromeos.cc b/chrome/browser/ui/webui/signin/signin_helper_chromeos.cc
index e3957b3..5a9c91d 100644
--- a/chrome/browser/ui/webui/signin/signin_helper_chromeos.cc
+++ b/chrome/browser/ui/webui/signin/signin_helper_chromeos.cc
@@ -4,9 +4,10 @@
 
 #include "chrome/browser/ui/webui/signin/signin_helper_chromeos.h"
 
-#include "ash/components/account_manager/account_manager_ash.h"
 #include "components/account_manager_core/account.h"
+#include "components/account_manager_core/account_addition_result.h"
 #include "components/account_manager_core/chromeos/account_manager.h"
+#include "components/account_manager_core/chromeos/account_manager_ash.h"
 #include "google_apis/gaia/gaia_auth_fetcher.h"
 
 namespace chromeos {
diff --git a/chrome/browser/ui/webui/signin/signin_helper_chromeos.h b/chrome/browser/ui/webui/signin/signin_helper_chromeos.h
index 2ea296d..c8b898f 100644
--- a/chrome/browser/ui/webui/signin/signin_helper_chromeos.h
+++ b/chrome/browser/ui/webui/signin/signin_helper_chromeos.h
@@ -5,9 +5,9 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_SIGNIN_SIGNIN_HELPER_CHROMEOS_H_
 #define CHROME_BROWSER_UI_WEBUI_SIGNIN_SIGNIN_HELPER_CHROMEOS_H_
 
-#include "ash/components/account_manager/account_manager_ash.h"
 #include "components/account_manager_core/account.h"
 #include "components/account_manager_core/chromeos/account_manager.h"
+#include "components/account_manager_core/chromeos/account_manager_ash.h"
 #include "google_apis/gaia/gaia_auth_consumer.h"
 #include "google_apis/gaia/gaia_auth_fetcher.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
diff --git a/chrome/browser/ui/webui/signin/signin_utils_desktop.cc b/chrome/browser/ui/webui/signin/signin_utils_desktop.cc
index 9654637..f469be3 100644
--- a/chrome/browser/ui/webui/signin/signin_utils_desktop.cc
+++ b/chrome/browser/ui/webui/signin/signin_utils_desktop.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/ui/webui/signin/signin_utils_desktop.h"
 
-#include "base/metrics/histogram_macros.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
@@ -55,12 +54,8 @@
         identity_manager->GetPrimaryAccountInfo(signin::ConsentLevel::kSync)
             .email;
     const bool same_email = gaia::AreEmailsSame(current_email, email);
-    if (!current_email.empty() && !same_email) {
-      UMA_HISTOGRAM_ENUMERATION("Signin.Reauth",
-                                signin_metrics::HISTOGRAM_ACCOUNT_MISSMATCH,
-                                signin_metrics::HISTOGRAM_REAUTH_MAX);
+    if (!current_email.empty() && !same_email)
       return SigninUIError::WrongReauthAccount(email, current_email);
-    }
 
     // If some profile, not just the current one, is already connected to this
     // account, don't show the infobar.
diff --git a/chrome/browser/video_tutorials/android/java/res/layout/video_tutorial_iph_card.xml b/chrome/browser/video_tutorials/android/java/res/layout/video_tutorial_iph_card.xml
index a5de0e68..976b9e25 100644
--- a/chrome/browser/video_tutorials/android/java/res/layout/video_tutorial_iph_card.xml
+++ b/chrome/browser/video_tutorials/android/java/res/layout/video_tutorial_iph_card.xml
@@ -3,100 +3,104 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 
-<RelativeLayout
+<org.chromium.components.browser_ui.widget.MaterialCardViewNoShadow
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/video_tutorial_card"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:background="@drawable/hairline_border_card_background"
-    android:paddingStart="12dp"
-    android:paddingBottom="12dp" >
+    style="@style/MaterialCardStyle">
 
     <RelativeLayout
-        android:id="@+id/thumbnail_wrapper"
-        android:layout_width="80dp"
-        android:layout_height="58dp"
-        android:layout_gravity="center_vertical"
-        android:layout_marginTop="12dp" >
-
-        <org.chromium.components.browser_ui.widget.async_image.AsyncImageView
-            android:id="@+id/thumbnail"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:importantForAccessibility="no"
-            app:unavailableSrc="@color/image_loading_color"
-            app:waitingSrc="@color/image_loading_color"
-            app:roundedfillColor="@color/modern_grey_300" />
-
-        <ImageView
-            android:layout_width="8dp"
-            android:layout_height="8dp"
-            android:layout_alignParentStart="true"
-            android:importantForAccessibility="no"
-            app:srcCompat="@drawable/corner_top_start"/>
-
-        <ImageView
-            android:layout_width="8dp"
-            android:layout_height="8dp"
-            android:layout_alignParentBottom="true"
-            android:layout_alignParentStart="true"
-            android:importantForAccessibility="no"
-            app:srcCompat="@drawable/corner_bottom_start"/>
-
-        <ImageView
-            android:layout_width="8dp"
-            android:layout_height="8dp"
-            android:layout_alignParentEnd="true"
-            android:importantForAccessibility="no"
-            app:srcCompat="@drawable/corner_top_end"/>
-
-        <ImageView
-            android:layout_width="8dp"
-            android:layout_height="8dp"
-            android:layout_alignParentBottom="true"
-            android:layout_alignParentEnd="true"
-            android:importantForAccessibility="no"
-            app:srcCompat="@drawable/corner_bottom_end"/>
-
-    </RelativeLayout>
-
-    <TextView
-        android:id="@+id/video_length"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignBottom="@id/thumbnail_wrapper"
-        android:layout_marginStart="6dp"
-        android:layout_marginBottom="6dp"
-        android:paddingStart="4dp"
-        android:paddingEnd="4dp"
-        android:background="@color/modern_grey_900"
-        android:importantForAccessibility="no"
-        android:textAppearance="@style/TextAppearance.TextSmall.Primary.Light" />
-
-    <TextView
-        android:id="@+id/title"
+        android:id="@+id/video_tutorial_card"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_toEndOf="@id/thumbnail_wrapper"
-        android:layout_toStartOf="@id/close_button"
-        android:layout_centerVertical="true"
-        android:layout_marginStart="12dp"
-        android:layout_marginEnd="12dp"
-        android:ellipsize="end"
-        android:maxLines="3"
-        android:textAppearance="@style/TextAppearance.TextLarge.Primary" />
+        android:paddingStart="12dp"
+        android:paddingBottom="12dp" >
 
-    <org.chromium.ui.widget.ChromeImageButton
-        android:id="@+id/close_button"
-        android:layout_height="48dp"
-        android:layout_width="48dp"
-        android:layout_alignParentEnd="true"
-        android:background="?attr/selectableItemBackground"
-        android:contentDescription="@string/close"
-        android:scaleType="center"
-        android:src="@drawable/btn_close"
-        app:tint="@color/default_icon_color_tint_list" />
+        <RelativeLayout
+            android:id="@+id/thumbnail_wrapper"
+            android:layout_width="80dp"
+            android:layout_height="58dp"
+            android:layout_gravity="center_vertical"
+            android:layout_marginTop="12dp" >
 
-</RelativeLayout>
+            <org.chromium.components.browser_ui.widget.async_image.AsyncImageView
+                android:id="@+id/thumbnail"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:importantForAccessibility="no"
+                app:unavailableSrc="@color/image_loading_color"
+                app:waitingSrc="@color/image_loading_color"
+                app:roundedfillColor="@color/modern_grey_300" />
+
+            <ImageView
+                android:layout_width="8dp"
+                android:layout_height="8dp"
+                android:layout_alignParentStart="true"
+                android:importantForAccessibility="no"
+                app:srcCompat="@drawable/corner_top_start"/>
+
+            <ImageView
+                android:layout_width="8dp"
+                android:layout_height="8dp"
+                android:layout_alignParentBottom="true"
+                android:layout_alignParentStart="true"
+                android:importantForAccessibility="no"
+                app:srcCompat="@drawable/corner_bottom_start"/>
+
+            <ImageView
+                android:layout_width="8dp"
+                android:layout_height="8dp"
+                android:layout_alignParentEnd="true"
+                android:importantForAccessibility="no"
+                app:srcCompat="@drawable/corner_top_end"/>
+
+            <ImageView
+                android:layout_width="8dp"
+                android:layout_height="8dp"
+                android:layout_alignParentBottom="true"
+                android:layout_alignParentEnd="true"
+                android:importantForAccessibility="no"
+                app:srcCompat="@drawable/corner_bottom_end"/>
+
+        </RelativeLayout>
+
+        <TextView
+            android:id="@+id/video_length"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignBottom="@id/thumbnail_wrapper"
+            android:layout_marginStart="6dp"
+            android:layout_marginBottom="6dp"
+            android:paddingStart="4dp"
+            android:paddingEnd="4dp"
+            android:background="@color/modern_grey_900"
+            android:importantForAccessibility="no"
+            android:textAppearance="@style/TextAppearance.TextSmall.Primary.Light" />
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_toEndOf="@id/thumbnail_wrapper"
+            android:layout_toStartOf="@id/close_button"
+            android:layout_centerVertical="true"
+            android:layout_marginStart="12dp"
+            android:layout_marginEnd="12dp"
+            android:ellipsize="end"
+            android:maxLines="3"
+            android:textAppearance="@style/TextAppearance.TextLarge.Primary" />
+
+        <org.chromium.ui.widget.ChromeImageButton
+            android:id="@+id/close_button"
+            android:layout_height="48dp"
+            android:layout_width="48dp"
+            android:layout_alignParentEnd="true"
+            android:background="?attr/selectableItemBackground"
+            android:contentDescription="@string/close"
+            android:scaleType="center"
+            android:src="@drawable/btn_close"
+            app:tint="@color/default_icon_color_tint_list" />
+
+    </RelativeLayout>
+</org.chromium.components.browser_ui.widget.MaterialCardViewNoShadow>
diff --git a/chrome/browser/video_tutorials/internal/android/java/res/layout/video_tutorial_large_card.xml b/chrome/browser/video_tutorials/internal/android/java/res/layout/video_tutorial_large_card.xml
index 29536c20..4595ff3 100644
--- a/chrome/browser/video_tutorials/internal/android/java/res/layout/video_tutorial_large_card.xml
+++ b/chrome/browser/video_tutorials/internal/android/java/res/layout/video_tutorial_large_card.xml
@@ -3,78 +3,82 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 
-<androidx.gridlayout.widget.GridLayout
+<org.chromium.components.browser_ui.widget.MaterialCardViewNoShadow
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:clickable="true"
     android:focusable="true"
-    android:background="@drawable/hairline_border_card_background"
-    app:columnCount="1"
-    app:rowCount="2">
+    style="@style/MaterialCardStyle">
 
-    <org.chromium.components.browser_ui.widget.async_image.AsyncImageView
-        android:id="@+id/thumbnail"
-        android:layout_width="match_parent"
-        android:layout_height="200dp"
-        android:layout_marginTop="1dp"
-        android:layout_marginStart="1dp"
-        android:layout_marginEnd="1dp"
-        android:scaleType="centerCrop"
-        android:adjustViewBounds="true"
-        android:importantForAccessibility="no"
-        app:unavailableSrc="@color/image_loading_color"
-        app:waitingSrc="@color/image_loading_color"
-        app:layout_column="0"
-        app:layout_row="0"
-        app:layout_gravity="center"
-        app:cornerRadiusTopStart="@dimen/download_manager_thumbnail_corner_radius"
-        app:cornerRadiusTopEnd="@dimen/download_manager_thumbnail_corner_radius"
-        app:roundedfillColor="@color/modern_grey_300"/>
-
-    <org.chromium.ui.widget.ChromeImageButton
-        android:id="@+id/action_button"
-        android:layout_width="60dp"
-        android:layout_height="60dp"
-        android:src="@drawable/ic_play_arrow_white_36dp"
-        android:tint="@color/modern_grey_800"
-        android:contentDescription="@string/accessibility_play_video"
-        app:layout_column="0"
-        app:layout_row="0"
-        app:layout_gravity="center"
-        android:elevation="2dp"
-        android:clickable="false"
-        android:background="@drawable/circular_media_button_background" />
-
-    <TextView
-        android:id="@+id/video_length"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="11dp"
-        android:layout_marginBottom="11dp"
-        android:background="@color/modern_grey_900"
-        android:paddingStart="4dp"
-        android:paddingEnd="4dp"
-        app:layout_column="0"
-        app:layout_row="0"
-        app:layout_gravity="bottom"
-        android:importantForAccessibility="no"
-        android:textAppearance="@style/TextAppearance.TextSmall.Primary.Light" />
-
-    <TextView
-        android:id="@+id/title"
+    <androidx.gridlayout.widget.GridLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginStart="12dp"
-        android:layout_marginEnd="12dp"
-        android:layout_marginTop="14dp"
-        android:layout_marginBottom="14dp"
-        android:maxLines="1"
-        android:ellipsize="end"
-        app:layout_column="0"
-        app:layout_row="1"
-        android:textAppearance="@style/TextAppearance.TextLarge.Primary" />
+        app:columnCount="1"
+        app:rowCount="2">
 
-</androidx.gridlayout.widget.GridLayout>
+        <org.chromium.components.browser_ui.widget.async_image.AsyncImageView
+            android:id="@+id/thumbnail"
+            android:layout_width="match_parent"
+            android:layout_height="200dp"
+            android:layout_marginTop="1dp"
+            android:layout_marginStart="1dp"
+            android:layout_marginEnd="1dp"
+            android:scaleType="centerCrop"
+            android:adjustViewBounds="true"
+            android:importantForAccessibility="no"
+            app:unavailableSrc="@color/image_loading_color"
+            app:waitingSrc="@color/image_loading_color"
+            app:layout_column="0"
+            app:layout_row="0"
+            app:layout_gravity="center"
+            app:cornerRadiusTopStart="16dp"
+            app:cornerRadiusTopEnd="16dp"
+            app:roundedfillColor="@color/modern_grey_300"/>
+
+        <org.chromium.ui.widget.ChromeImageButton
+            android:id="@+id/action_button"
+            android:layout_width="60dp"
+            android:layout_height="60dp"
+            android:src="@drawable/ic_play_arrow_white_36dp"
+            android:tint="@color/modern_grey_800"
+            android:contentDescription="@string/accessibility_play_video"
+            app:layout_column="0"
+            app:layout_row="0"
+            app:layout_gravity="center"
+            android:elevation="2dp"
+            android:clickable="false"
+            android:background="@drawable/circular_media_button_background" />
+
+        <TextView
+            android:id="@+id/video_length"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="11dp"
+            android:layout_marginBottom="11dp"
+            android:background="@color/modern_grey_900"
+            android:paddingStart="4dp"
+            android:paddingEnd="4dp"
+            app:layout_column="0"
+            app:layout_row="0"
+            app:layout_gravity="bottom"
+            android:importantForAccessibility="no"
+            android:textAppearance="@style/TextAppearance.TextSmall.Primary.Light" />
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="12dp"
+            android:layout_marginEnd="12dp"
+            android:layout_marginTop="14dp"
+            android:layout_marginBottom="14dp"
+            android:maxLines="1"
+            android:ellipsize="end"
+            app:layout_column="0"
+            app:layout_row="1"
+            android:textAppearance="@style/TextAppearance.TextLarge.Primary" />
+
+    </androidx.gridlayout.widget.GridLayout>
+</org.chromium.components.browser_ui.widget.MaterialCardViewNoShadow>
diff --git a/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/ReliabilityLoggingTestUtil.java b/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/ReliabilityLoggingTestUtil.java
index 33fb0c8f..67aaf03 100644
--- a/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/ReliabilityLoggingTestUtil.java
+++ b/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/ReliabilityLoggingTestUtil.java
@@ -11,12 +11,19 @@
 public interface ReliabilityLoggingTestUtil {
     /**
      * Return the most recent "flows" (at most 30), or lists of logged events
-     * representing a user interaction, rendered as a string.
+     * representing a user interaction, with each flow rendered as a string.
      */
     default String getRecentFlowsForTesting() {
         return "";
     }
 
+    /**
+     * Return the number of recent flows that would be rendered by getRecentFlowsForTesting().
+     */
+    default int getRecentFlowsCountForTesting() {
+        return 0;
+    }
+
     /** Clear the list of recent flows. */
     default void clearRecentFlowsForTesting() {}
 }
\ No newline at end of file
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index 0a53b96..38d736c0 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -358,7 +358,10 @@
       "extensions/api/input_ime/input_components_handler.h",
     ]
     public_deps += [ "//ash/keyboard/ui" ]
-    deps += [ "//ash/constants" ]
+    deps += [
+      "//ash/constants",
+      "//chrome/common/chromeos/extensions",
+    ]
   }
 
   if (enable_nacl) {
diff --git a/chrome/common/chromeos/extensions/BUILD.gn b/chrome/common/chromeos/extensions/BUILD.gn
new file mode 100644
index 0000000..5ad78d58
--- /dev/null
+++ b/chrome/common/chromeos/extensions/BUILD.gn
@@ -0,0 +1,26 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//extensions/buildflags/buildflags.gni")
+
+assert(enable_extensions)
+
+# Use a static library here because many test binaries depend on this but don't
+# require many files from it. This makes linking more efficient.
+static_library("extensions") {
+  sources = [
+    "chromeos_system_extensions_api_provider.cc",
+    "chromeos_system_extensions_api_provider.h",
+    "chromeos_system_extensions_manifest_constants.cc",
+    "chromeos_system_extensions_manifest_constants.h",
+    "chromeos_system_extensions_manifest_handler.cc",
+    "chromeos_system_extensions_manifest_handler.h",
+  ]
+
+  deps = [
+    "api:extensions_features",
+    "//base",
+    "//extensions/common",
+  ]
+}
diff --git a/chrome/common/chromeos/extensions/OWNERS b/chrome/common/chromeos/extensions/OWNERS
new file mode 100644
index 0000000..cb53585
--- /dev/null
+++ b/chrome/common/chromeos/extensions/OWNERS
@@ -0,0 +1,2 @@
+lamzin@google.com
+mgawad@google.com
diff --git a/chrome/common/chromeos/extensions/README.md b/chrome/common/chromeos/extensions/README.md
new file mode 100644
index 0000000..26ed49c
--- /dev/null
+++ b/chrome/common/chromeos/extensions/README.md
@@ -0,0 +1,4 @@
+# Chrome OS System Extension platform based on the Chrome Extension System.
+- [go/dd-telemetry-extension](go/dd-telemetry-extension)
+- [go/dd-telemetry-extension-api-surface](go/dd-telemetry-extension-api-surface)
+- [go/dd-cros-csx-poc](go/dd-cros-csx-poc)
diff --git a/chrome/common/chromeos/extensions/api/BUILD.gn b/chrome/common/chromeos/extensions/api/BUILD.gn
new file mode 100644
index 0000000..945ec94
--- /dev/null
+++ b/chrome/common/chromeos/extensions/api/BUILD.gn
@@ -0,0 +1,25 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//extensions/buildflags/buildflags.gni")
+import("//tools/json_schema_compiler/json_features.gni")
+
+assert(enable_extensions)
+
+################################################################################
+# Public Targets
+
+group("extensions_features") {
+  public_deps = [ ":manifest_features" ]
+}
+
+################################################################################
+# Private Targets
+
+json_features("manifest_features") {
+  feature_type = "ManifestFeature"
+  method_name = "AddChromeOSSystemExtensionsManifestFeatures"
+  sources = [ "_manifest_features.json" ]
+  visibility = [ ":extensions_features" ]
+}
diff --git a/chrome/common/chromeos/extensions/api/_manifest_features.json b/chrome/common/chromeos/extensions/api/_manifest_features.json
new file mode 100644
index 0000000..ddfcdfd1
--- /dev/null
+++ b/chrome/common/chromeos/extensions/api/_manifest_features.json
@@ -0,0 +1,23 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This features file defines manifest keys implemented under
+// src/chrome/common/chromeos/extensions.
+//
+// See chrome/common/extensions/api/_features.md to understand this file, as
+// well as feature.h, simple_feature.h, and feature_provider.h.
+{
+  // Note: only allowlisted extension ID hashes are allowed to declare this key.
+  // More info: http://go/dd-telemetry-extension-api-surface
+  "chromeos_system_extension": {
+    "channel": "dev",
+    "extension_types": [
+      "chromeos_system_extension"
+    ],
+    "min_manifest_version": 3,
+    "allowlist": [
+      "CF6FFE535FA1EE153CCAFBF8AA0613E549413E11" // http://crbug.com/1229585
+    ]
+  }
+}
diff --git a/chrome/common/chromeos/extensions/chromeos_system_extensions_api_provider.cc b/chrome/common/chromeos/extensions/chromeos_system_extensions_api_provider.cc
new file mode 100644
index 0000000..35a1dfc94
--- /dev/null
+++ b/chrome/common/chromeos/extensions/chromeos_system_extensions_api_provider.cc
@@ -0,0 +1,64 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/chromeos/extensions/chromeos_system_extensions_api_provider.h"
+
+#include <memory>
+
+#include "base/logging.h"
+#include "chrome/common/chromeos/extensions/api/manifest_features.h"
+#include "chrome/common/chromeos/extensions/chromeos_system_extensions_manifest_handler.h"
+#include "extensions/common/features/feature_provider.h"
+#include "extensions/common/features/json_feature_provider_source.h"
+#include "extensions/common/manifest_handler.h"
+#include "extensions/common/permissions/permissions_info.h"
+
+namespace chromeos {
+
+ChromeOSSystemExtensionsAPIProvider::ChromeOSSystemExtensionsAPIProvider()
+    : registry_(extensions::ManifestHandlerRegistry::Get()) {}
+
+ChromeOSSystemExtensionsAPIProvider::~ChromeOSSystemExtensionsAPIProvider() =
+    default;
+
+void ChromeOSSystemExtensionsAPIProvider::AddAPIFeatures(
+    extensions::FeatureProvider* provider) {}
+
+void ChromeOSSystemExtensionsAPIProvider::AddManifestFeatures(
+    extensions::FeatureProvider* provider) {
+  AddChromeOSSystemExtensionsManifestFeatures(provider);
+}
+
+void ChromeOSSystemExtensionsAPIProvider::AddPermissionFeatures(
+    extensions::FeatureProvider* provider) {}
+
+void ChromeOSSystemExtensionsAPIProvider::AddBehaviorFeatures(
+    extensions::FeatureProvider* provider) {
+  // Note: No chromeOS-specific behavior features.
+}
+
+void ChromeOSSystemExtensionsAPIProvider::AddAPIJSONSources(
+    extensions::JSONFeatureProviderSource* json_source) {}
+
+bool ChromeOSSystemExtensionsAPIProvider::IsAPISchemaGenerated(
+    const std::string& name) {
+  return false;
+}
+
+base::StringPiece ChromeOSSystemExtensionsAPIProvider::GetAPISchema(
+    const std::string& name) {
+  return "";
+}
+
+void ChromeOSSystemExtensionsAPIProvider::RegisterPermissions(
+    extensions::PermissionsInfo* permissions_info) {}
+
+void ChromeOSSystemExtensionsAPIProvider::RegisterManifestHandlers() {
+  DCHECK(!extensions::ManifestHandler::IsRegistrationFinalized());
+
+  registry_->RegisterHandler(
+      std::make_unique<ChromeOSSystemExtensionHandler>());
+}
+
+}  // namespace chromeos
diff --git a/chrome/common/chromeos/extensions/chromeos_system_extensions_api_provider.h b/chrome/common/chromeos/extensions/chromeos_system_extensions_api_provider.h
new file mode 100644
index 0000000..5770c9c
--- /dev/null
+++ b/chrome/common/chromeos/extensions/chromeos_system_extensions_api_provider.h
@@ -0,0 +1,52 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_CHROMEOS_EXTENSIONS_CHROMEOS_SYSTEM_EXTENSIONS_API_PROVIDER_H_
+#define CHROME_COMMON_CHROMEOS_EXTENSIONS_CHROMEOS_SYSTEM_EXTENSIONS_API_PROVIDER_H_
+
+#include <string>
+
+#include "base/strings/string_piece_forward.h"
+#include "extensions/common/extensions_api_provider.h"
+
+namespace extensions {
+class FeatureProvider;
+class JSONFeatureProviderSource;
+class ManifestHandlerRegistry;
+class PermissionsInfo;
+
+}  // namespace extensions
+
+namespace chromeos {
+
+class ChromeOSSystemExtensionsAPIProvider
+    : public extensions::ExtensionsAPIProvider {
+ public:
+  ChromeOSSystemExtensionsAPIProvider();
+  ChromeOSSystemExtensionsAPIProvider(
+      const ChromeOSSystemExtensionsAPIProvider&) = delete;
+  ChromeOSSystemExtensionsAPIProvider& operator=(
+      const ChromeOSSystemExtensionsAPIProvider&) = delete;
+  ~ChromeOSSystemExtensionsAPIProvider() override;
+
+  // ExtensionsAPIProvider:
+  void AddAPIFeatures(extensions::FeatureProvider* provider) override;
+  void AddManifestFeatures(extensions::FeatureProvider* provider) override;
+  void AddPermissionFeatures(extensions::FeatureProvider* provider) override;
+  void AddBehaviorFeatures(extensions::FeatureProvider* provider) override;
+  void AddAPIJSONSources(
+      extensions::JSONFeatureProviderSource* json_source) override;
+  bool IsAPISchemaGenerated(const std::string& name) override;
+  base::StringPiece GetAPISchema(const std::string& name) override;
+  void RegisterPermissions(
+      extensions::PermissionsInfo* permissions_info) override;
+  void RegisterManifestHandlers() override;
+
+ private:
+  extensions::ManifestHandlerRegistry* registry_;  // not owned
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_COMMON_CHROMEOS_EXTENSIONS_CHROMEOS_SYSTEM_EXTENSIONS_API_PROVIDER_H_
diff --git a/chrome/common/chromeos/extensions/chromeos_system_extensions_manifest_constants.cc b/chrome/common/chromeos/extensions/chromeos_system_extensions_manifest_constants.cc
new file mode 100644
index 0000000..c6cf206
--- /dev/null
+++ b/chrome/common/chromeos/extensions/chromeos_system_extensions_manifest_constants.cc
@@ -0,0 +1,12 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/chromeos/extensions/chromeos_system_extensions_manifest_constants.h"
+
+namespace chromeos {
+
+const char kInvalidChromeOSSystemExtensionDeclaration[] =
+    "Invalid value for 'chromeos_system_extension'. Must be a dictionary.";
+
+}  // namespace chromeos
diff --git a/chrome/common/chromeos/extensions/chromeos_system_extensions_manifest_constants.h b/chrome/common/chromeos/extensions/chromeos_system_extensions_manifest_constants.h
new file mode 100644
index 0000000..96f534dc
--- /dev/null
+++ b/chrome/common/chromeos/extensions/chromeos_system_extensions_manifest_constants.h
@@ -0,0 +1,16 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_CHROMEOS_EXTENSIONS_CHROMEOS_SYSTEM_EXTENSIONS_MANIFEST_CONSTANTS_H_
+#define CHROME_COMMON_CHROMEOS_EXTENSIONS_CHROMEOS_SYSTEM_EXTENSIONS_MANIFEST_CONSTANTS_H_
+
+namespace chromeos {
+
+// Error message returned when chromeos_system_extension's value is of incorrect
+// type.
+extern const char kInvalidChromeOSSystemExtensionDeclaration[];
+
+}  // namespace chromeos
+
+#endif  // CHROME_COMMON_CHROMEOS_EXTENSIONS_CHROMEOS_SYSTEM_EXTENSIONS_MANIFEST_CONSTANTS_H_
diff --git a/chrome/common/chromeos/extensions/chromeos_system_extensions_manifest_handler.cc b/chrome/common/chromeos/extensions/chromeos_system_extensions_manifest_handler.cc
new file mode 100644
index 0000000..82f1200b
--- /dev/null
+++ b/chrome/common/chromeos/extensions/chromeos_system_extensions_manifest_handler.cc
@@ -0,0 +1,42 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/chromeos/extensions/chromeos_system_extensions_manifest_handler.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/common/chromeos/extensions/chromeos_system_extensions_manifest_constants.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_constants.h"
+
+namespace chromeos {
+
+ChromeOSSystemExtensionHandler::ChromeOSSystemExtensionHandler() = default;
+
+ChromeOSSystemExtensionHandler::~ChromeOSSystemExtensionHandler() = default;
+
+bool ChromeOSSystemExtensionHandler::Parse(extensions::Extension* extension,
+                                           std::u16string* error) {
+  const base::DictionaryValue* system_extension_dict = nullptr;
+  if (!extension->manifest()->GetDictionary(
+          extensions::manifest_keys::kChromeOSSystemExtension,
+          &system_extension_dict)) {
+    *error = base::ASCIIToUTF16(kInvalidChromeOSSystemExtensionDeclaration);
+    return false;
+  }
+
+  return true;
+}
+
+bool ChromeOSSystemExtensionHandler::AlwaysParseForType(
+    extensions::Manifest::Type type) const {
+  return type == extensions::Manifest::TYPE_CHROMEOS_SYSTEM_EXTENSION;
+}
+
+base::span<const char* const> ChromeOSSystemExtensionHandler::Keys() const {
+  static constexpr const char* kKeys[] = {
+      extensions::manifest_keys::kChromeOSSystemExtension};
+  return kKeys;
+}
+
+}  // namespace chromeos
diff --git a/chrome/common/chromeos/extensions/chromeos_system_extensions_manifest_handler.h b/chrome/common/chromeos/extensions/chromeos_system_extensions_manifest_handler.h
new file mode 100644
index 0000000..d01f048
--- /dev/null
+++ b/chrome/common/chromeos/extensions/chromeos_system_extensions_manifest_handler.h
@@ -0,0 +1,34 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_CHROMEOS_EXTENSIONS_CHROMEOS_SYSTEM_EXTENSIONS_MANIFEST_HANDLER_H_
+#define CHROME_COMMON_CHROMEOS_EXTENSIONS_CHROMEOS_SYSTEM_EXTENSIONS_MANIFEST_HANDLER_H_
+
+#include <string>
+
+#include "base/containers/span.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_handler.h"
+
+namespace chromeos {
+
+// Parses the "chromeos_system_extension" manifest key.
+class ChromeOSSystemExtensionHandler : public extensions::ManifestHandler {
+ public:
+  ChromeOSSystemExtensionHandler();
+  ChromeOSSystemExtensionHandler(const ChromeOSSystemExtensionHandler&) =
+      delete;
+  ChromeOSSystemExtensionHandler& operator=(
+      const ChromeOSSystemExtensionHandler&) = delete;
+  ~ChromeOSSystemExtensionHandler() override;
+
+  bool Parse(extensions::Extension* extension, std::u16string* error) override;
+  bool AlwaysParseForType(extensions::Manifest::Type type) const override;
+  base::span<const char* const> Keys() const override;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_COMMON_CHROMEOS_EXTENSIONS_CHROMEOS_SYSTEM_EXTENSIONS_MANIFEST_HANDLER_H_
diff --git a/chrome/common/chromeos/extensions/manifest_tests/extension_manifests_chromeos_system_extension_unittest.cc b/chrome/common/chromeos/extensions/manifest_tests/extension_manifests_chromeos_system_extension_unittest.cc
new file mode 100644
index 0000000..59a44cd
--- /dev/null
+++ b/chrome/common/chromeos/extensions/manifest_tests/extension_manifests_chromeos_system_extension_unittest.cc
@@ -0,0 +1,34 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/scoped_refptr.h"
+#include "chrome/common/chromeos/extensions/chromeos_system_extensions_manifest_constants.h"
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+
+using ExtensionManifestChromeOSSystemExtensionTest = ChromeManifestTest;
+
+TEST_F(ExtensionManifestChromeOSSystemExtensionTest,
+       InvalidChromeOSSystemExtension) {
+  LoadAndExpectError("chromeos_system_extension_invalid.json",
+                     chromeos::kInvalidChromeOSSystemExtensionDeclaration);
+}
+
+TEST_F(ExtensionManifestChromeOSSystemExtensionTest,
+       ValidChromeOSSystemExtension) {
+  scoped_refptr<extensions::Extension> extension(
+      LoadAndExpectSuccess("chromeos_system_extension.json"));
+  EXPECT_TRUE(extension->is_chromeos_system_extension());
+}
+
+TEST_F(ExtensionManifestChromeOSSystemExtensionTest,
+       ValidNonChromeOSSystemExtension) {
+  scoped_refptr<extensions::Extension> extension(
+      LoadAndExpectSuccess("background_page.json"));
+  EXPECT_FALSE(extension->is_chromeos_system_extension());
+}
+
+}  // namespace chromeos
diff --git a/chrome/common/extensions/api/wm_desks_private.idl b/chrome/common/extensions/api/wm_desks_private.idl
index 513ebecf..f6eae00 100644
--- a/chrome/common/extensions/api/wm_desks_private.idl
+++ b/chrome/common/extensions/api/wm_desks_private.idl
@@ -8,10 +8,8 @@
 namespace wmDesksPrivate {
   dictionary DeskTemplate {
     // The unique id for a desk template. Used internally to identify a desk
-    // template. Currently it's a double type number derived on a timestamp. It
-    // will later be change to base::GUID type and its name will change back to
-    // templateUuid.
-    double templateId;
+    // template.
+    DOMString templateUuid;
     DOMString templateName;
   };
 
@@ -40,18 +38,18 @@
     static void getSavedDeskTemplates(
         GetSavedDeskTemplatesCallback callback);
 
-    // Deletes the previously-saved desk template with id |templateId|. Note if
+    // Deletes the previously-saved desk template with id |templateUuid|. Note if
     // no such existing desk template can be found, this will still be regarded
     // as a successful operation. If the file operation has failed, an error
     // will be returned.
-    static void deleteDeskTemplate(long templateId,
+    static void deleteDeskTemplate(DOMString templateUuid,
                                    DeskTemplateVoidCallback callback);
 
-    // Launches the desk template with |templateId| as a new desk.
+    // Launches the desk template with |templateUuid| as a new desk.
     // |templateId| should be the unique id for an existing desk template. If
     // no such id can be found or a new desk can’t be created, an error will be
     // returned.
-    static void launchDeskTemplate(long templateId,
+    static void launchDeskTemplate(DOMString templateUuid,
                                    DeskTemplateVoidCallback callback);
   };
 };
diff --git a/chrome/common/extensions/manifest_unittest.cc b/chrome/common/extensions/manifest_unittest.cc
index 12177de2..2edc46e 100644
--- a/chrome/common/extensions/manifest_unittest.cc
+++ b/chrome/common/extensions/manifest_unittest.cc
@@ -47,6 +47,8 @@
               manifest->is_shared_module());
     EXPECT_EQ(type == Manifest::TYPE_LOGIN_SCREEN_EXTENSION,
               manifest->is_login_screen_extension());
+    EXPECT_EQ(type == Manifest::TYPE_CHROMEOS_SYSTEM_EXTENSION,
+              manifest->is_chromeos_system_extension());
   }
 
   // Helper function that replaces the Manifest held by |manifest| with a copy
diff --git a/chrome/common/extensions/sync_helper.cc b/chrome/common/extensions/sync_helper.cc
index 202fac5..c9889fc 100644
--- a/chrome/common/extensions/sync_helper.cc
+++ b/chrome/common/extensions/sync_helper.cc
@@ -60,6 +60,7 @@
     case Manifest::TYPE_UNKNOWN:
     case Manifest::TYPE_SHARED_MODULE:
     case Manifest::TYPE_LOGIN_SCREEN_EXTENSION:
+    case Manifest::TYPE_CHROMEOS_SYSTEM_EXTENSION:
       return false;
 
     case Manifest::NUM_LOAD_TYPES:
diff --git a/chrome/common/initialize_extensions_client.cc b/chrome/common/initialize_extensions_client.cc
index 3e9d4cf..1a3ee7f 100644
--- a/chrome/common/initialize_extensions_client.cc
+++ b/chrome/common/initialize_extensions_client.cc
@@ -11,6 +11,10 @@
 #include "chrome/common/extensions/chrome_extensions_client.h"
 #include "extensions/common/extensions_client.h"
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "chrome/common/chromeos/extensions/chromeos_system_extensions_api_provider.h"
+#endif
+
 void EnsureExtensionsClientInitialized() {
   static bool initialized = false;
 
@@ -21,6 +25,10 @@
     initialized = true;
     extensions_client->AddAPIProvider(
         std::make_unique<chrome_apps::ChromeAppsAPIProvider>());
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+    extensions_client->AddAPIProvider(
+        std::make_unique<chromeos::ChromeOSSystemExtensionsAPIProvider>());
+#endif
     extensions::ExtensionsClient::Set(extensions_client.get());
   }
 
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index cee0b27..c885e700 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1819,8 +1819,12 @@
 const char kNtpCustomBackgroundDict[] = "ntp.custom_background_dict";
 const char kNtpCustomBackgroundLocalToDevice[] =
     "ntp.custom_background_local_to_device";
-const char kNtpModulesVisible[] = "NewTabPage.ModulesVisible";
+// List keeping track of disabled NTP modules.
 const char kNtpDisabledModules[] = "NewTabPage.DisabledModules";
+// List keeping track of NTP modules order.
+const char kNtpModulesOrder[] = "NewTabPage.ModulesOrder";
+// Whether NTP modules are visible.
+const char kNtpModulesVisible[] = "NewTabPage.ModulesVisible";
 // List of promos that the user has dismissed while on the NTP.
 const char kNtpPromoBlocklist[] = "ntp.promo_blocklist";
 // Data associated with search suggestions that appear on the NTP.
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 813799a..6d41f24 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -616,8 +616,9 @@
 #else
 extern const char kNtpCustomBackgroundDict[];
 extern const char kNtpCustomBackgroundLocalToDevice[];
-extern const char kNtpModulesVisible[];
 extern const char kNtpDisabledModules[];
+extern const char kNtpModulesOrder[];
+extern const char kNtpModulesVisible[];
 extern const char kNtpPromoBlocklist[];
 extern const char kNtpSearchSuggestionsBlocklist[];
 extern const char kNtpSearchSuggestionsImpressions[];
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 979bf8e7..b8b57b7 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -615,15 +615,15 @@
   }
 }
 
-group("telemetry_gpu_integration_test") {
-  testonly = true
-  data_deps = [
-    "//content/test:telemetry_gpu_integration_test_support",
-    "//tools/perf/chrome_telemetry_build:telemetry_chrome_test",
-  ]
-}
-
-if (is_android) {
+if (!is_android) {
+  group("telemetry_gpu_integration_test") {
+    testonly = true
+    data_deps = [
+      "//content/test:telemetry_gpu_integration_test_support",
+      "//tools/perf/chrome_telemetry_build:telemetry_chrome_test",
+    ]
+  }
+} else {
   template("telemetry_gpu_integration_test_android_template") {
     forward_variables_from(invoker, [ "telemetry_target_suffix" ])
     group(target_name) {
@@ -3985,15 +3985,15 @@
   data_deps = [ "//testing:test_scripts_shared" ]
 }
 
-group("telemetry_perf_unittests") {
-  testonly = true
-  data_deps = [
-    ":telemetry_perf_unittests_base",
-    "//tools/perf:perf",
-  ]
-}
-
-if (is_android) {
+if (!is_android) {
+  group("telemetry_perf_unittests") {
+    testonly = true
+    data_deps = [
+      ":telemetry_perf_unittests_base",
+      "//tools/perf:perf",
+    ]
+  }
+} else {
   template("telemetry_perf_unittests_android_template") {
     forward_variables_from(invoker, [ "telemetry_target_suffix" ])
     group(target_name) {
@@ -4021,15 +4021,15 @@
   ]
 }
 
-group("telemetry_perf_tests") {
-  testonly = true
-  data_deps = [
-    ":telemetry_perf_tests_base",
-    "//tools/perf/:perf",
-  ]
-}
-
-if (is_android) {
+if (!is_android) {
+  group("telemetry_perf_tests") {
+    testonly = true
+    data_deps = [
+      ":telemetry_perf_tests_base",
+      "//tools/perf/:perf",
+    ]
+  }
+} else {
   template("telemetry_perf_tests_android_template") {
     forward_variables_from(invoker, [ "telemetry_target_suffix" ])
     group(target_name) {
@@ -4122,14 +4122,14 @@
   }
 }
 
-template("performance_test_suite_template") {
-  forward_variables_from(invoker, [ "override_board" ])
-  performance_test_suite_template_base(target_name) {
-    data_deps = [ "//chrome/test:telemetry_perf_tests" ]
+if (!is_android) {
+  template("performance_test_suite_template") {
+    forward_variables_from(invoker, [ "override_board" ])
+    performance_test_suite_template_base(target_name) {
+      data_deps = [ "//chrome/test:telemetry_perf_tests" ]
+    }
   }
-}
-
-if (is_android) {
+} else {
   template("performance_test_suite_template_android") {
     forward_variables_from(invoker,
                            [
@@ -4143,10 +4143,11 @@
   }
 }
 
-performance_test_suite_template("performance_test_suite") {
-}
-
-if (is_android) {
+if (!is_android) {
+  performance_test_suite_template("performance_test_suite") {
+  }
+} else {
+  import("//tools/perf/chrome_telemetry_build/android_browser_types.gni")
   foreach(_target_suffix, telemetry_android_browser_target_suffixes) {
     performance_test_suite_template_android(
         "performance_test_suite${_target_suffix}") {
@@ -6648,8 +6649,10 @@
         "../browser/extensions/external_provider_impl_chromeos_unittest.cc",
         "../browser/extensions/system_display/display_info_provider_chromeos_unittest.cc",
         "../browser/extensions/system_display/system_display_serialization_unittest.cc",
+        "../common/chromeos/extensions/manifest_tests/extension_manifests_chromeos_system_extension_unittest.cc",
         "../renderer/extensions/accessibility_private_hooks_delegate_unittest.cc",
       ]
+      deps += [ "../common/chromeos/extensions" ]
     }
 
     allow_circular_includes_from = [
@@ -9013,15 +9016,15 @@
     data_deps = [ "//testing:test_scripts_shared" ]
   }
 
-  group("rendering_representative_perf_tests") {
-    testonly = true
-    data_deps = [
-      ":rendering_representative_perf_tests_base",
-      "//tools/perf/chrome_telemetry_build:telemetry_chrome_test",
-    ]
-  }
-
-  if (is_android) {
+  if (!is_android) {
+    group("rendering_representative_perf_tests") {
+      testonly = true
+      data_deps = [
+        ":rendering_representative_perf_tests_base",
+        "//tools/perf/chrome_telemetry_build:telemetry_chrome_test",
+      ]
+    }
+  } else {
     template("rendering_representative_perf_tests_android_template") {
       forward_variables_from(invoker, [ "telemetry_target_suffix" ])
       group(target_name) {
diff --git a/chrome/test/data/autofill/captured_sites/testcases.json b/chrome/test/data/autofill/captured_sites/testcases.json
index c2328d8..06b0975 100644
--- a/chrome/test/data/autofill/captured_sites/testcases.json
+++ b/chrome/test/data/autofill/captured_sites/testcases.json
@@ -210,7 +210,7 @@
     { "site_name": "wiley" },
     { "site_name": "williams_sonoma" },
     { "site_name": "worldmarket", "disabled":true, "bug_number":1173040 },
-    { "site_name": "zappos", "disabled":true, "bug_number":1223946 },
+    { "site_name": "zappos", "bug_number":1223946 },
     { "site_name": "zenni_optical" },
     { "site_name": "zulily" }
   ]
diff --git a/chrome/test/data/extensions/api_test/wm_desks_private/background.js b/chrome/test/data/extensions/api_test/wm_desks_private/background.js
index 9e65405b3..564c0dc2 100644
--- a/chrome/test/data/extensions/api_test/wm_desks_private/background.js
+++ b/chrome/test/data/extensions/api_test/wm_desks_private/background.js
@@ -12,7 +12,7 @@
     chrome.wmDesksPrivate.captureActiveDeskAndSaveTemplate(
         chrome.test.callbackPass(function(deskTemplate) {
           chrome.test.assertEq(typeof deskTemplate, 'object');
-          chrome.test.assertTrue(deskTemplate.hasOwnProperty('templateId'));
+          chrome.test.assertTrue(deskTemplate.hasOwnProperty('templateUuid'));
           chrome.test.assertTrue(deskTemplate.hasOwnProperty('templateName'));
         }));
   },
diff --git a/chrome/test/data/extensions/manifest_tests/chromeos_system_extension.json b/chrome/test/data/extensions/manifest_tests/chromeos_system_extension.json
new file mode 100644
index 0000000..b0ef86b
--- /dev/null
+++ b/chrome/test/data/extensions/manifest_tests/chromeos_system_extension.json
@@ -0,0 +1,10 @@
+{
+    // Sample telemetry extension public key. Currently, this is the only
+    // allowed extension to declare "chromeos_system_extension" key.
+    // See //chrome/common/chromeos/extensions/api/_manifest_features.json
+    "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt2CwI94nqAQzLTBHSIwtkMlkoRyhu27rmkDsBneMprscOzl4524Y0bEA+0RSjNZB+kZgP6M8QAZQJHCpAzULXa49MooDDIdzzmqQswswguAALm2FS7XP2N0p2UYQneQce4Wehq/C5Yr65mxasAgjXgDWlYBwV3mgiISDPXI/5WG94TM2Z3PDQePJ91msDAjN08jdBme3hAN976yH3Q44M7cP1r+OWRkZGwMA6TSQjeESEuBbkimaLgPIyzlJp2k6jwuorG5ujmbAGFiTQoSDFBFCjwPEtywUMLKcZjH4fD76pcIQIdkuuzRQCVyuImsGzm1cmGosJ/Z4iyb80c1ytwIDAQAB",
+    "name": "Test chromeos extension",
+    "version": "1.0",
+    "manifest_version": 3,
+    "chromeos_system_extension": {}
+}
diff --git a/chrome/test/data/extensions/manifest_tests/chromeos_system_extension_invalid.json b/chrome/test/data/extensions/manifest_tests/chromeos_system_extension_invalid.json
new file mode 100644
index 0000000..a635522
--- /dev/null
+++ b/chrome/test/data/extensions/manifest_tests/chromeos_system_extension_invalid.json
@@ -0,0 +1,6 @@
+{
+    "name": "Invalid test chromeos extension",
+    "version": "1.0",
+    "manifest_version": 3,
+    "chromeos_system_extension": "true"
+}
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index 247bbf0..cdfa69fd 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -5594,10 +5594,18 @@
     "reason_for_missing_test": "Maps into CrosSettings"
   },
 
+  "ReportDeviceNetworkConfiguration": {
+    "reason_for_missing_test": "Maps into CrosSettings"
+  },
+
   "ReportDeviceNetworkInterfaces": {
     "reason_for_missing_test": "Maps into CrosSettings"
   },
 
+  "ReportDeviceNetworkStatus": {
+    "reason_for_missing_test": "Maps into CrosSettings"
+  },
+
   "ReportDeviceUsers": {
     "reason_for_missing_test": "Maps into CrosSettings"
   },
diff --git a/chrome/test/data/webui/chromeos/diagnostics/system_page_test.js b/chrome/test/data/webui/chromeos/diagnostics/system_page_test.js
index a75d9e9a..42b47f745 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/system_page_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/system_page_test.js
@@ -5,7 +5,7 @@
 import 'chrome://diagnostics/system_page.js';
 
 import {DiagnosticsBrowserProxyImpl} from 'chrome://diagnostics/diagnostics_browser_proxy.js';
-import {BatteryChargeStatus, BatteryHealth, BatteryInfo, CpuUsage, MemoryUsage, RoutineType, SystemInfo} from 'chrome://diagnostics/diagnostics_types.js';
+import {BatteryChargeStatus, BatteryHealth, BatteryInfo, CpuUsage, MemoryUsage, RoutineType, StandardRoutineResult, SystemInfo} from 'chrome://diagnostics/diagnostics_types.js';
 import {fakeBatteryChargeStatus, fakeBatteryHealth, fakeBatteryInfo, fakeCellularNetwork, fakeCpuUsage, fakeEthernetNetwork, fakeMemoryUsage, fakeNetworkGuidInfoList, fakePowerRoutineResults, fakeRoutineResults, fakeSystemInfo, fakeSystemInfoWithoutBattery, fakeWifiNetwork} from 'chrome://diagnostics/fake_data.js';
 import {FakeNetworkHealthProvider} from 'chrome://diagnostics/fake_network_health_provider.js';
 import {FakeSystemDataProvider} from 'chrome://diagnostics/fake_system_data_provider.js';
@@ -314,4 +314,37 @@
         .then(() => flushTasks())
         .then(() => assertFalse(isVisible(getCautionBanner())));
   });
+
+  test('RunningMemoryTestsShowsBanner', () => {
+    /** @type {?RoutineSectionElement} */
+    let routineSection;
+    /** @type {!Array<!RoutineType>} */
+    const routines = [
+      RoutineType.kMemory,
+    ];
+    routineController.setFakeStandardRoutineResult(
+        RoutineType.kMemory, StandardRoutineResult.kTestPassed);
+    return initializeSystemPage(
+               fakeSystemInfo, fakeBatteryChargeStatus, fakeBatteryHealth,
+               fakeBatteryInfo, fakeCpuUsage, fakeMemoryUsage)
+        .then(() => {
+          routineSection = dx_utils.getRoutineSection(page.$$('memory-card'));
+          routineSection.routines = routines;
+          assertFalse(isVisible(getCautionBanner()));
+          return flushTasks();
+        })
+        .then(() => {
+          dx_utils.getRunTestsButtonFromSection(routineSection).click();
+          return flushTasks();
+        })
+        .then(() => {
+          dx_utils.assertElementContainsText(
+              page.$$('#banner > #bannerMsg'),
+              loadTimeData.getString('memoryBannerMessage'));
+          assertTrue(isVisible(getCautionBanner()));
+          return routineController.resolveRoutineForTesting();
+        })
+        .then(() => flushTasks())
+        .then(() => assertFalse(isVisible(getCautionBanner())));
+  });
 }
\ No newline at end of file
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/BUILD.gn b/chrome/test/data/webui/chromeos/shimless_rma/BUILD.gn
index a1a86e0..98c0cfe 100644
--- a/chrome/test/data/webui/chromeos/shimless_rma/BUILD.gn
+++ b/chrome/test/data/webui/chromeos/shimless_rma/BUILD.gn
@@ -22,6 +22,7 @@
     ":onboarding_wait_for_manual_wp_disable_page_test",
     ":reimaging_firmware_update_page_test",
     ":reimaging_provisioning_page_test",
+    ":repair_component_chip_test",
     ":shimless_rma_app_test",
     ":shimless_rma_unified_test",
     ":wrapup_repair_complete_page_test",
@@ -149,6 +150,15 @@
   externs_list = [ "$externs_path/mocha-2.5.js" ]
 }
 
+js_library("repair_component_chip_test") {
+  deps = [
+    "../..:chai_assert",
+    "//ash/webui/shimless_rma/resources:repair_component_chip",
+    "//ui/webui/resources/cr_elements/cr_button:cr_button.m",
+  ]
+  externs_list = [ "$externs_path/mocha-2.5.js" ]
+}
+
 js_library("shimless_rma_unified_test") {
   deps = []
   externs_list = [ "$externs_path/mocha-2.5.js" ]
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/onboarding_select_components_page_test.js b/chrome/test/data/webui/chromeos/shimless_rma/onboarding_select_components_page_test.js
index 031b3e4..f87bac7 100644
--- a/chrome/test/data/webui/chromeos/shimless_rma/onboarding_select_components_page_test.js
+++ b/chrome/test/data/webui/chromeos/shimless_rma/onboarding_select_components_page_test.js
@@ -83,13 +83,13 @@
     const trackpadComponent =
         component.shadowRoot.querySelector('#componentTrackpad');
     assertFalse(reworkFlowLink.hidden);
-    assertEquals(keyboardComponent.textContent.trim(), 'Keyboard');
+    assertEquals(keyboardComponent.componentName, 'Keyboard');
     assertFalse(keyboardComponent.disabled);
     assertFalse(keyboardComponent.checked);
-    assertEquals(thumbReaderComponent.textContent.trim(), 'Thumb Reader');
+    assertEquals(thumbReaderComponent.componentName, 'Thumb Reader');
     assertTrue(thumbReaderComponent.disabled);
     assertFalse(thumbReaderComponent.checked);
-    assertEquals(trackpadComponent.textContent.trim(), 'Trackpad');
+    assertEquals(trackpadComponent.componentName, 'Trackpad');
     assertFalse(trackpadComponent.disabled);
     assertTrue(trackpadComponent.checked);
   });
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/repair_component_chip_test.js b/chrome/test/data/webui/chromeos/shimless_rma/repair_component_chip_test.js
new file mode 100644
index 0000000..2d15e7f
--- /dev/null
+++ b/chrome/test/data/webui/chromeos/shimless_rma/repair_component_chip_test.js
@@ -0,0 +1,79 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {RepairComponentChipElement} from 'chrome://shimless-rma/repair_component_chip.js';
+
+import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js';
+import {flushTasks} from '../../test_util.m.js';
+
+export function repairComponentChipElementTest() {
+  /** @type {?RepairComponentChipElement} */
+  let component = null;
+
+  setup(() => {
+    document.body.innerHTML = '';
+  });
+
+  teardown(() => {
+    component.remove();
+    component = null;
+  });
+
+  /**
+   * @param {string} componentName
+   * @return {!Promise}
+   */
+  function initializeRepairComponentChip(componentName) {
+    assertFalse(!!component);
+
+    component = /** @type {!RepairComponentChipElement} */ (
+        document.createElement('repair-component-chip'));
+    component.componentName = componentName;
+    assertTrue(!!component);
+    document.body.appendChild(component);
+
+    return flushTasks();
+  }
+
+  /**
+   * @return {!Promise}
+   */
+  function clickChip() {
+    assertTrue(!!component);
+
+    const button = component.shadowRoot.querySelector('#containerButton');
+    button.click();
+    return flushTasks();
+  }
+
+  test('ComponentRenders', async () => {
+    await initializeRepairComponentChip('cpu');
+    assertTrue(!!component);
+    assertFalse(component.checked);
+
+    const componentNameSpanElement =
+        component.shadowRoot.querySelector('#componentName');
+    assertTrue(!!componentNameSpanElement);
+    assertEquals(componentNameSpanElement.textContent, 'cpu');
+  });
+
+  test('ComponentToggleChecked', async () => {
+    await initializeRepairComponentChip('cpu');
+
+    await clickChip();
+    assertTrue(component.checked);
+
+    await clickChip();
+    assertFalse(component.checked);
+  });
+
+  test('ComponentNoToggleOnDisabled', async () => {
+    await initializeRepairComponentChip('cpu');
+    component.disabled = true;
+    await flushTasks();
+    await clickChip();
+
+    assertFalse(component.checked);
+  });
+}
diff --git a/chrome/test/media_router/BUILD.gn b/chrome/test/media_router/BUILD.gn
index d2c5191..0df8230 100644
--- a/chrome/test/media_router/BUILD.gn
+++ b/chrome/test/media_router/BUILD.gn
@@ -154,15 +154,15 @@
     data_deps = [ "//tools/perf/contrib/media_router_benchmarks:telemetry_extension_resources" ]
   }
 
-  group("media_router_perf_tests") {
-    testonly = true
-    data_deps = [
-      ":media_router_perf_tests_base",
-      "//tools/perf:perf",
-    ]
-  }
-
-  if (is_android) {
+  if (!is_android) {
+    group("media_router_perf_tests") {
+      testonly = true
+      data_deps = [
+        ":media_router_perf_tests_base",
+        "//tools/perf:perf",
+      ]
+    }
+  } else {
     template("media_router_perf_tests_android_template") {
       forward_variables_from(invoker, [ "telemetry_target_suffix" ])
       group(target_name) {
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd
index 5aa5b6ab..a5444a06 100644
--- a/chromeos/chromeos_strings.grd
+++ b/chromeos/chromeos_strings.grd
@@ -923,6 +923,9 @@
       <message name="IDS_DIAGNOSTICS_CPU_BANNER_MESSAGE" desc="The text shown while a user is running their CPU test.">
         Running a CPU test may affect your system performance
       </message>
+      <message name="IDS_DIAGNOSTICS_MEMORY_BANNER_MESSAGE" desc="The text shown while a user is running their Memory test.">
+        For more accurate results, close all apps until the test is complete.
+      </message>
       <message name="IDS_DIAGNOSTICS_TROUBLE_CONNECTING" desc="The label for the text link that leads to a help support article to learn more about connecting to Ethernet networks.">
         Having trouble connecting?
       </message>
diff --git a/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_MEMORY_BANNER_MESSAGE.png.sha1 b/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_MEMORY_BANNER_MESSAGE.png.sha1
new file mode 100644
index 0000000..1d6ea83
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_MEMORY_BANNER_MESSAGE.png.sha1
@@ -0,0 +1 @@
+bbb2e74a97b3fe45e7f076a5660ae85a0c3d0c02
\ No newline at end of file
diff --git a/chromeos/components/eche_app_ui/proto/exo_messages.proto b/chromeos/components/eche_app_ui/proto/exo_messages.proto
index bc49d8d..0d0d443 100644
--- a/chromeos/components/eche_app_ui/proto/exo_messages.proto
+++ b/chromeos/components/eche_app_ui/proto/exo_messages.proto
@@ -9,6 +9,7 @@
     SignalingRequest request = 1;
     SignalingResponse response = 2;
     SignalingAction action = 3;
+    ProximityPing proximity_ping = 4;
   }
 }
 
@@ -28,3 +29,7 @@
   ACTION_UNKNOWN = 0;
   ACTION_TEAR_DOWN = 1;
 }
+
+message ProximityPing {
+}
+
diff --git a/chromeos/components/personalization_app/BUILD.gn b/chromeos/components/personalization_app/BUILD.gn
index 0d768a5..3c0a0d8 100644
--- a/chromeos/components/personalization_app/BUILD.gn
+++ b/chromeos/components/personalization_app/BUILD.gn
@@ -24,7 +24,9 @@
     "//chromeos/resources:personalization_app_resources",
     "//chromeos/strings",
     "//content/public/browser",
+    "//ui/chromeos/colors:cros_colors_views_generator",
     "//ui/resources:webui_generated_resources_grd_grit",
+    "//ui/resources:webui_resources_grd_grit",
     "//ui/webui",
   ]
 }
diff --git a/chromeos/components/personalization_app/DEPS b/chromeos/components/personalization_app/DEPS
index 518b29e..b391421 100644
--- a/chromeos/components/personalization_app/DEPS
+++ b/chromeos/components/personalization_app/DEPS
@@ -5,7 +5,9 @@
   "+chromeos/grit/chromeos_personalization_app_resources.h",
   "+content/public/browser",
   "+content/public/common",
+  "+ui/chromeos/colors/cros_colors.h",
   "+ui/resources/grit/webui_generated_resources.h",
   "+ui/resources/grit/webui_generated_resources_map.h",
+  "+ui/resources/grit/webui_resources.h",
   "+ui/webui",
 ]
diff --git a/chromeos/components/personalization_app/resources/trusted/index.html b/chromeos/components/personalization_app/resources/trusted/index.html
index 32683b0..b3b460f 100644
--- a/chromeos/components/personalization_app/resources/trusted/index.html
+++ b/chromeos/components/personalization_app/resources/trusted/index.html
@@ -8,6 +8,9 @@
     <link rel="icon" type="image/png" sizes="192x192" href="icon_192.png">
     <meta charset="utf-8">
     <link rel="stylesheet" href="/common/base.css">
+    <link rel="stylesheet"
+        href="chrome://resources/chromeos/colors/cros_colors.generated.css">
+    <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
     <script type="module" src="/trusted/personalization_app.js" defer></script>
   </head>
   <body>
diff --git a/chromeos/components/personalization_app/resources/trusted/styles.js b/chromeos/components/personalization_app/resources/trusted/styles.js
index a65769948..ad81eaf 100644
--- a/chromeos/components/personalization_app/resources/trusted/styles.js
+++ b/chromeos/components/personalization_app/resources/trusted/styles.js
@@ -3,6 +3,9 @@
 // found in the LICENSE file.
 
 import 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import 'chrome://resources/cr_elements/chromeos/cros_color_overrides.m.js';
+import 'chrome://resources/cr_elements/shared_vars_css.m.js';
+import 'chrome://resources/polymer/v3_0/paper-styles/color.js';
 
 const styles = document.createElement('dom-module');
 
diff --git a/chromeos/components/personalization_app/resources/trusted/wallpaper_breadcrumb_element.html b/chromeos/components/personalization_app/resources/trusted/wallpaper_breadcrumb_element.html
index a54c5b1..f606230 100644
--- a/chromeos/components/personalization_app/resources/trusted/wallpaper_breadcrumb_element.html
+++ b/chromeos/components/personalization_app/resources/trusted/wallpaper_breadcrumb_element.html
@@ -15,7 +15,7 @@
 
   #textContainer {
     @apply --personalization-app-typeface-headline-1;
-    color: var(--cr-secondary-text-color);
+    color: var(--cros-text-color-secondary);
     align-items: center;
     box-sizing: border-box;
     display: flex;
diff --git a/chromeos/components/personalization_app/resources/trusted/wallpaper_breadcrumb_element.js b/chromeos/components/personalization_app/resources/trusted/wallpaper_breadcrumb_element.js
index 783daed..052942e30 100644
--- a/chromeos/components/personalization_app/resources/trusted/wallpaper_breadcrumb_element.js
+++ b/chromeos/components/personalization_app/resources/trusted/wallpaper_breadcrumb_element.js
@@ -12,7 +12,6 @@
 import 'chrome://resources/cr_elements/cr_icons_css.m.js';
 import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js';
 import 'chrome://resources/cr_elements/icons.m.js';
-import 'chrome://resources/cr_elements/shared_vars_css.m.js';
 import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
 import '../common/styles.js';
 import {html} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/chromeos/components/personalization_app/resources/trusted/wallpaper_selected_element.html b/chromeos/components/personalization_app/resources/trusted/wallpaper_selected_element.html
index 5173d056..3780fb38 100644
--- a/chromeos/components/personalization_app/resources/trusted/wallpaper_selected_element.html
+++ b/chromeos/components/personalization_app/resources/trusted/wallpaper_selected_element.html
@@ -42,16 +42,16 @@
 
   #textContainer > p:first-child {
     @apply --personalization-app-typeface-body-2;
-    color: var(--cr-secondary-text-color);
+    color: var(--cros-text-color-secondary);
   }
 
   #textContainer > p:nth-child(2) {
     @apply --personalization-app-typeface-display-6;
-    color: var(--cr-primary-text-color);
+    color: var(--cros-text-color-primary);
   }
 
   #textContainer > p:nth-child(n+3) {
-    color: var(--cr-secondary-text-color);
+    color: var(--cros-text-color-secondary);
     font-family: var(--personalization-app-font-google-sans);
     font-size: 14px;
     font-weight: 400;
@@ -72,7 +72,7 @@
 
   #currentWallpaperMoreOptions #center.selected,
   #currentWallpaperMoreOptions #fill.selected {
-    color: var(--cr-toggle-color);
+    color: var(--cros-toggle-color);
     pointer-events: none;
   }
 </style>
diff --git a/chromeos/components/personalization_app/resources/untrusted/collections.html b/chromeos/components/personalization_app/resources/untrusted/collections.html
index 8cbdcfa..13ba2e6 100644
--- a/chromeos/components/personalization_app/resources/untrusted/collections.html
+++ b/chromeos/components/personalization_app/resources/untrusted/collections.html
@@ -3,6 +3,7 @@
 <head>
   <meta charset="utf-8">
   <link rel="stylesheet" href="/common/base.css">
+  <link rel="stylesheet" href="/chromeos/colors/cros_colors.generated.css">
   <script type="module" src="collections_grid.js" defer></script>
 </head>
 <body>
diff --git a/chromeos/components/personalization_app/resources/untrusted/images.html b/chromeos/components/personalization_app/resources/untrusted/images.html
index 7af2a89..023b965 100644
--- a/chromeos/components/personalization_app/resources/untrusted/images.html
+++ b/chromeos/components/personalization_app/resources/untrusted/images.html
@@ -3,6 +3,7 @@
 <head>
   <meta charset="utf-8">
   <link rel="stylesheet" href="/common/base.css">
+  <link rel="stylesheet" href="/chromeos/colors/cros_colors.generated.css">
   <script type="module" src="images_grid.js" defer></script>
 </head>
 <body>
diff --git a/chromeos/components/personalization_app/untrusted_personalization_app_ui_config.cc b/chromeos/components/personalization_app/untrusted_personalization_app_ui_config.cc
index c8abb9f..3a028ba 100644
--- a/chromeos/components/personalization_app/untrusted_personalization_app_ui_config.cc
+++ b/chromeos/components/personalization_app/untrusted_personalization_app_ui_config.cc
@@ -16,8 +16,10 @@
 #include "content/public/browser/web_ui_data_source.h"
 #include "content/public/common/url_constants.h"
 #include "services/network/public/mojom/content_security_policy.mojom-shared.h"
+#include "ui/chromeos/colors/cros_colors.h"
 #include "ui/resources/grit/webui_generated_resources.h"
 #include "ui/resources/grit/webui_generated_resources_map.h"
+#include "ui/resources/grit/webui_resources.h"
 #include "url/gurl.h"
 
 namespace chromeos {
@@ -39,6 +41,17 @@
   source->UseStringsJs();
 }
 
+void AddCrosColors(content::WebUIDataSource* source) {
+  source->AddResourcePath("chromeos/colors/cros_colors.generated.css",
+                          IDR_WEBUI_CROS_COLORS_CSS);
+
+  source->AddString(
+      "crosColorsDebugOverrides",
+      base::FeatureList::IsEnabled(ash::features::kSemanticColorsDebugOverride)
+          ? cros_colors::kDebugOverrideCssString
+          : std::string());
+}
+
 class UntrustedPersonalizationAppUI : public ui::UntrustedWebUIController {
  public:
   explicit UntrustedPersonalizationAppUI(content::WebUI* web_ui)
@@ -67,6 +80,8 @@
     source->AddResourcePaths(base::make_span(kWebuiGeneratedResources,
                                              kWebuiGeneratedResourcesSize));
 
+    AddCrosColors(source.get());
+
     source->AddFrameAncestor(GURL(kChromeUIPersonalizationAppURL));
 
     // Allow images only from this url.
diff --git a/chromeos/dbus/fake_smb_provider_client.cc b/chromeos/dbus/fake_smb_provider_client.cc
index e0cbb03..2d44aaa 100644
--- a/chromeos/dbus/fake_smb_provider_client.cc
+++ b/chromeos/dbus/fake_smb_provider_client.cc
@@ -47,132 +47,6 @@
 
 void FakeSmbProviderClient::Init(dbus::Bus* bus) {}
 
-void FakeSmbProviderClient::Mount(const base::FilePath& share_path,
-                                  const MountOptions& options,
-                                  base::ScopedFD password_fd,
-                                  MountCallback callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK, 1));
-}
-
-void FakeSmbProviderClient::Unmount(int32_t mount_id,
-                                    bool remove_password,
-                                    StatusCallback callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK));
-}
-
-void FakeSmbProviderClient::ReadDirectory(int32_t mount_id,
-                                          const base::FilePath& directory_path,
-                                          ReadDirectoryCallback callback) {
-  smbprovider::DirectoryEntryListProto entry_list;
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::BindOnce(std::move(callback), smbprovider::ERROR_OK, entry_list));
-}
-
-void FakeSmbProviderClient::GetMetadataEntry(int32_t mount_id,
-                                             const base::FilePath& entry_path,
-                                             GetMetdataEntryCallback callback) {
-  smbprovider::DirectoryEntryProto entry;
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::BindOnce(std::move(callback), smbprovider::ERROR_OK, entry));
-}
-
-void FakeSmbProviderClient::OpenFile(int32_t mount_id,
-                                     const base::FilePath& file_path,
-                                     bool writeable,
-                                     OpenFileCallback callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK, 1));
-}
-
-void FakeSmbProviderClient::CloseFile(int32_t mount_id,
-                                      int32_t file_id,
-                                      StatusCallback callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK));
-}
-
-void FakeSmbProviderClient::ReadFile(int32_t mount_id,
-                                     int32_t file_id,
-                                     int64_t offset,
-                                     int32_t length,
-                                     ReadFileCallback callback) {
-  base::ScopedFD fd;
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK,
-                                std::move(fd)));
-}
-
-void FakeSmbProviderClient::DeleteEntry(int32_t mount_id,
-                                        const base::FilePath& entry_path,
-                                        bool recursive,
-                                        StatusCallback callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK));
-}
-
-void FakeSmbProviderClient::CreateFile(int32_t mount_id,
-                                       const base::FilePath& file_path,
-                                       StatusCallback callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK));
-}
-
-void FakeSmbProviderClient::Truncate(int32_t mount_id,
-                                     const base::FilePath& file_path,
-                                     int64_t length,
-                                     StatusCallback callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK));
-}
-
-void FakeSmbProviderClient::WriteFile(int32_t mount_id,
-                                      int32_t file_id,
-                                      int64_t offset,
-                                      int32_t length,
-                                      base::ScopedFD temp_fd,
-                                      StatusCallback callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK));
-}
-
-void FakeSmbProviderClient::CreateDirectory(
-    int32_t mount_id,
-    const base::FilePath& directory_path,
-    bool recursive,
-    StatusCallback callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK));
-}
-
-void FakeSmbProviderClient::MoveEntry(int32_t mount_id,
-                                      const base::FilePath& source_path,
-                                      const base::FilePath& target_path,
-                                      StatusCallback callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK));
-}
-
-void FakeSmbProviderClient::CopyEntry(int32_t mount_id,
-                                      const base::FilePath& source_path,
-                                      const base::FilePath& target_path,
-                                      StatusCallback callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK));
-}
-
-void FakeSmbProviderClient::GetDeleteList(int32_t mount_id,
-                                          const base::FilePath& entry_path,
-                                          GetDeleteListCallback callback) {
-  smbprovider::DeleteListProto delete_list;
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::BindOnce(std::move(callback), smbprovider::ERROR_OK, delete_list));
-}
-
 void FakeSmbProviderClient::GetShares(const base::FilePath& server_url,
                                       ReadDirectoryCallback callback) {
   smbprovider::DirectoryEntryListProto entry_list;
@@ -225,60 +99,6 @@
   std::move(callback).Run(result);
 }
 
-void FakeSmbProviderClient::StartCopy(int32_t mount_id,
-                                      const base::FilePath& source_path,
-                                      const base::FilePath& target_path,
-                                      StartCopyCallback callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK,
-                                -1 /* copy_token */));
-}
-
-void FakeSmbProviderClient::ContinueCopy(int32_t mount_id,
-                                         int32_t copy_token,
-                                         StatusCallback callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK));
-}
-
-void FakeSmbProviderClient::StartReadDirectory(
-    int32_t mount_id,
-    const base::FilePath& directory_path,
-    StartReadDirectoryCallback callback) {
-  smbprovider::DirectoryEntryListProto entry_list;
-  // Simulate a ReadDirectory that completes during the StartReadDirectory call.
-  // read_dir_token is unset and error is set to ERROR_OK.
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK,
-                                -1 /* read_dir_token */, entry_list));
-}
-
-void FakeSmbProviderClient::ContinueReadDirectory(
-    int32_t mount_id,
-    int32_t read_dir_token,
-    ReadDirectoryCallback callback) {
-  smbprovider::DirectoryEntryListProto entry_list;
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::BindOnce(std::move(callback), smbprovider::ERROR_OK, entry_list));
-}
-
-void FakeSmbProviderClient::UpdateMountCredentials(int32_t mount_id,
-                                                   std::string workgroup,
-                                                   std::string username,
-                                                   base::ScopedFD password_fd,
-                                                   StatusCallback callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK));
-}
-
-void FakeSmbProviderClient::UpdateSharePath(int32_t mount_id,
-                                            const std::string& share_path,
-                                            StatusCallback callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK));
-}
-
 void FakeSmbProviderClient::ClearShares() {
   shares_.clear();
 }
diff --git a/chromeos/dbus/fake_smb_provider_client.h b/chromeos/dbus/fake_smb_provider_client.h
index 6d149899..15f8ad90 100644
--- a/chromeos/dbus/fake_smb_provider_client.h
+++ b/chromeos/dbus/fake_smb_provider_client.h
@@ -30,73 +30,6 @@
   void Init(dbus::Bus* bus) override;
 
   // SmbProviderClient override.
-  void Mount(const base::FilePath& share_path,
-             const MountOptions& options,
-             base::ScopedFD password_fd,
-             MountCallback callback) override;
-
-  void Unmount(int32_t mount_id,
-               bool remove_password,
-               StatusCallback callback) override;
-  void ReadDirectory(int32_t mount_id,
-                     const base::FilePath& directory_path,
-                     ReadDirectoryCallback callback) override;
-  void GetMetadataEntry(int32_t mount_id,
-                        const base::FilePath& entry_path,
-                        GetMetdataEntryCallback callback) override;
-  void OpenFile(int32_t mount_id,
-                const base::FilePath& file_path,
-                bool writeable,
-                OpenFileCallback callback) override;
-  void CloseFile(int32_t mount_id,
-                 int32_t file_id,
-                 StatusCallback callback) override;
-  void ReadFile(int32_t mount_id,
-                int32_t file_id,
-                int64_t offset,
-                int32_t length,
-                ReadFileCallback callback) override;
-
-  void DeleteEntry(int32_t mount_id,
-                   const base::FilePath& entry_path,
-                   bool recursive,
-                   StatusCallback callback) override;
-
-  void CreateFile(int32_t mount_id,
-                  const base::FilePath& file_path,
-                  StatusCallback callback) override;
-
-  void Truncate(int32_t mount_id,
-                const base::FilePath& file_path,
-                int64_t length,
-                StatusCallback callback) override;
-
-  void WriteFile(int32_t mount_id,
-                 int32_t file_id,
-                 int64_t offset,
-                 int32_t length,
-                 base::ScopedFD temp_fd,
-                 StatusCallback callback) override;
-
-  void CreateDirectory(int32_t mount_id,
-                       const base::FilePath& directory_path,
-                       bool recursive,
-                       StatusCallback callback) override;
-
-  void MoveEntry(int32_t mount_id,
-                 const base::FilePath& source_path,
-                 const base::FilePath& target_path,
-                 StatusCallback callback) override;
-
-  void CopyEntry(int32_t mount_id,
-                 const base::FilePath& source_path,
-                 const base::FilePath& target_path,
-                 StatusCallback callback) override;
-
-  void GetDeleteList(int32_t mount_id,
-                     const base::FilePath& entry_path,
-                     GetDeleteListCallback callback) override;
-
   void GetShares(const base::FilePath& server_url,
                  ReadDirectoryCallback callback) override;
 
@@ -107,33 +40,6 @@
                           uint16_t transaction_id,
                           ParseNetBiosPacketCallback callback) override;
 
-  void StartCopy(int32_t mount_id,
-                 const base::FilePath& source_path,
-                 const base::FilePath& target_path,
-                 StartCopyCallback callback) override;
-
-  void ContinueCopy(int32_t mount_id,
-                    int32_t copy_token,
-                    StatusCallback callback) override;
-
-  void StartReadDirectory(int32_t mount_id,
-                          const base::FilePath& directory_path,
-                          StartReadDirectoryCallback callback) override;
-
-  void ContinueReadDirectory(int32_t mount_id,
-                             int32_t read_dir_token,
-                             ReadDirectoryCallback callback) override;
-
-  void UpdateMountCredentials(int32_t mount_id,
-                              std::string workgroup,
-                              std::string username,
-                              base::ScopedFD password_fd,
-                              StatusCallback callback) override;
-
-  void UpdateSharePath(int32_t mount_id,
-                       const std::string& share_path,
-                       StatusCallback callback) override;
-
   // Adds |share| to the list of shares for |server_url| in |shares_|.
   void AddToShares(const std::string& server_url, const std::string& share);
 
diff --git a/chromeos/dbus/smb_provider_client.cc b/chromeos/dbus/smb_provider_client.cc
index e5cfedc..06566392 100644
--- a/chromeos/dbus/smb_provider_client.cc
+++ b/chromeos/dbus/smb_provider_client.cc
@@ -49,219 +49,12 @@
   return smbprovider::ERROR_OK;
 }
 
-bool ParseDeleteList(const base::ScopedFD& fd,
-                     int32_t bytes_written,
-                     smbprovider::DeleteListProto* delete_list) {
-  DCHECK(delete_list);
-  std::vector<uint8_t> buffer(bytes_written);
-  return base::ReadFromFD(fd.get(), reinterpret_cast<char*>(buffer.data()),
-                          buffer.size()) &&
-         delete_list->ParseFromArray(buffer.data(), buffer.size());
-}
-
-std::unique_ptr<smbprovider::MountConfigProto> CreateMountConfigProto(
-    bool enable_ntlm) {
-  auto mount_config = std::make_unique<smbprovider::MountConfigProto>();
-  mount_config->set_enable_ntlm(enable_ntlm);
-
-  return mount_config;
-}
-
 class SmbProviderClientImpl : public SmbProviderClient {
  public:
   SmbProviderClientImpl() = default;
 
   ~SmbProviderClientImpl() override {}
 
-  void Mount(const base::FilePath& share_path,
-             const MountOptions& options,
-             base::ScopedFD password_fd,
-             MountCallback callback) override {
-    smbprovider::MountOptionsProto options_proto;
-    options_proto.set_path(share_path.value());
-    options_proto.set_original_path(options.original_path);
-    options_proto.set_workgroup(options.workgroup);
-    options_proto.set_username(options.username);
-    options_proto.set_skip_connect(options.skip_connect);
-    options_proto.set_account_hash(options.account_hash);
-    options_proto.set_save_password(options.save_password);
-    options_proto.set_restore_password(options.restore_password);
-
-    std::unique_ptr<smbprovider::MountConfigProto> config =
-        CreateMountConfigProto(options.ntlm_enabled);
-    options_proto.set_allocated_mount_config(config.release());
-
-    dbus::MethodCall method_call(smbprovider::kSmbProviderInterface,
-                                 smbprovider::kMountMethod);
-    dbus::MessageWriter writer(&method_call);
-    writer.AppendProtoAsArrayOfBytes(options_proto);
-    writer.AppendFileDescriptor(password_fd.get());
-    CallMethod(&method_call, &SmbProviderClientImpl::HandleMountCallback,
-               &callback);
-  }
-
-  void Unmount(int32_t mount_id,
-               bool remove_password,
-               StatusCallback callback) override {
-    smbprovider::UnmountOptionsProto options;
-    options.set_mount_id(mount_id);
-    options.set_remove_password(remove_password);
-    CallDefaultMethod(smbprovider::kUnmountMethod, options, &callback);
-  }
-
-  void ReadDirectory(int32_t mount_id,
-                     const base::FilePath& directory_path,
-                     ReadDirectoryCallback callback) override {
-    smbprovider::ReadDirectoryOptionsProto options;
-    options.set_mount_id(mount_id);
-    options.set_directory_path(directory_path.value());
-    CallMethod(smbprovider::kReadDirectoryMethod, options,
-               &SmbProviderClientImpl::HandleProtoCallback<
-                   smbprovider::DirectoryEntryListProto>,
-               &callback);
-  }
-
-  void GetMetadataEntry(int32_t mount_id,
-                        const base::FilePath& entry_path,
-                        GetMetdataEntryCallback callback) override {
-    smbprovider::GetMetadataEntryOptionsProto options;
-    options.set_mount_id(mount_id);
-    options.set_entry_path(entry_path.value());
-    CallMethod(smbprovider::kGetMetadataEntryMethod, options,
-               &SmbProviderClientImpl::HandleProtoCallback<
-                   smbprovider::DirectoryEntryProto>,
-               &callback);
-  }
-
-  void OpenFile(int32_t mount_id,
-                const base::FilePath& file_path,
-                bool writeable,
-                OpenFileCallback callback) override {
-    smbprovider::OpenFileOptionsProto options;
-    options.set_mount_id(mount_id);
-    options.set_file_path(file_path.value());
-    options.set_writeable(writeable);
-    CallMethod(smbprovider::kOpenFileMethod, options,
-               &SmbProviderClientImpl::HandleOpenFileCallback, &callback);
-  }
-
-  void CloseFile(int32_t mount_id,
-                 int32_t file_id,
-                 StatusCallback callback) override {
-    smbprovider::CloseFileOptionsProto options;
-    options.set_mount_id(mount_id);
-    options.set_file_id(file_id);
-    CallDefaultMethod(smbprovider::kCloseFileMethod, options, &callback);
-  }
-
-  void ReadFile(int32_t mount_id,
-                int32_t file_id,
-                int64_t offset,
-                int32_t length,
-                ReadFileCallback callback) override {
-    smbprovider::ReadFileOptionsProto options;
-    options.set_mount_id(mount_id);
-    options.set_file_id(file_id);
-    options.set_offset(offset);
-    options.set_length(length);
-    CallMethod(smbprovider::kReadFileMethod, options,
-               &SmbProviderClientImpl::HandleReadFileCallback, &callback);
-  }
-
-  void DeleteEntry(int32_t mount_id,
-                   const base::FilePath& entry_path,
-                   bool recursive,
-                   StatusCallback callback) override {
-    smbprovider::DeleteEntryOptionsProto options;
-    options.set_mount_id(mount_id);
-    options.set_entry_path(entry_path.value());
-    options.set_recursive(recursive);
-    CallDefaultMethod(smbprovider::kDeleteEntryMethod, options, &callback);
-  }
-
-  void CreateFile(int32_t mount_id,
-                  const base::FilePath& file_path,
-                  StatusCallback callback) override {
-    smbprovider::CreateFileOptionsProto options;
-    options.set_mount_id(mount_id);
-    options.set_file_path(file_path.value());
-    CallDefaultMethod(smbprovider::kCreateFileMethod, options, &callback);
-  }
-
-  void Truncate(int32_t mount_id,
-                const base::FilePath& file_path,
-                int64_t length,
-                StatusCallback callback) override {
-    smbprovider::TruncateOptionsProto options;
-    options.set_mount_id(mount_id);
-    options.set_file_path(file_path.value());
-    options.set_length(length);
-    CallDefaultMethod(smbprovider::kTruncateMethod, options, &callback);
-  }
-
-  void WriteFile(int32_t mount_id,
-                 int32_t file_id,
-                 int64_t offset,
-                 int32_t length,
-                 base::ScopedFD temp_fd,
-                 StatusCallback callback) override {
-    smbprovider::WriteFileOptionsProto options;
-    options.set_mount_id(mount_id);
-    options.set_file_id(file_id);
-    options.set_offset(offset);
-    options.set_length(length);
-
-    dbus::MethodCall method_call(smbprovider::kSmbProviderInterface,
-                                 smbprovider::kWriteFileMethod);
-    dbus::MessageWriter writer(&method_call);
-    writer.AppendProtoAsArrayOfBytes(options);
-    writer.AppendFileDescriptor(temp_fd.get());
-    CallDefaultMethod(&method_call, &callback);
-  }
-
-  void CreateDirectory(int32_t mount_id,
-                       const base::FilePath& directory_path,
-                       bool recursive,
-                       StatusCallback callback) override {
-    smbprovider::CreateDirectoryOptionsProto options;
-    options.set_mount_id(mount_id);
-    options.set_directory_path(directory_path.value());
-    options.set_recursive(recursive);
-    CallDefaultMethod(smbprovider::kCreateDirectoryMethod, options, &callback);
-  }
-
-  void MoveEntry(int32_t mount_id,
-                 const base::FilePath& source_path,
-                 const base::FilePath& target_path,
-                 StatusCallback callback) override {
-    smbprovider::MoveEntryOptionsProto options;
-    options.set_mount_id(mount_id);
-    options.set_source_path(source_path.value());
-    options.set_target_path(target_path.value());
-    CallDefaultMethod(smbprovider::kMoveEntryMethod, options, &callback);
-  }
-
-  void CopyEntry(int32_t mount_id,
-                 const base::FilePath& source_path,
-                 const base::FilePath& target_path,
-                 StatusCallback callback) override {
-    smbprovider::CopyEntryOptionsProto options;
-    options.set_mount_id(mount_id);
-    options.set_source_path(source_path.value());
-    options.set_target_path(target_path.value());
-    CallCopyEntryMethod(options, std::move(callback));
-  }
-
-  void GetDeleteList(int32_t mount_id,
-                     const base::FilePath& entry_path,
-                     GetDeleteListCallback callback) override {
-    smbprovider::GetDeleteListOptionsProto options;
-    options.set_mount_id(mount_id);
-    options.set_entry_path(entry_path.value());
-    CallMethod(smbprovider::kGetDeleteListMethod, options,
-               &SmbProviderClientImpl::HandleGetDeleteListCallback, &callback);
-  }
-
   void GetShares(const base::FilePath& server_url,
                  ReadDirectoryCallback callback) override {
     smbprovider::GetSharesOptionsProto options;
@@ -295,88 +88,6 @@
                &callback);
   }
 
-  void StartCopy(int32_t mount_id,
-                 const base::FilePath& source_path,
-                 const base::FilePath& target_path,
-                 StartCopyCallback callback) override {
-    smbprovider::CopyEntryOptionsProto options;
-    options.set_mount_id(mount_id);
-    options.set_source_path(source_path.value());
-    options.set_target_path(target_path.value());
-
-    CallMethod(smbprovider::kStartCopyMethod, options,
-               &SmbProviderClientImpl::HandleStartCopyCallback, &callback);
-  }
-
-  void ContinueCopy(int32_t mount_id,
-                    int32_t copy_token,
-                    StatusCallback callback) override {
-    dbus::MethodCall method_call(smbprovider::kSmbProviderInterface,
-                                 smbprovider::kContinueCopyMethod);
-    dbus::MessageWriter writer(&method_call);
-    writer.AppendInt32(mount_id);
-    writer.AppendInt32(copy_token);
-    CallDefaultMethod(&method_call, &callback);
-  }
-
-  void StartReadDirectory(int32_t mount_id,
-                          const base::FilePath& directory_path,
-                          StartReadDirectoryCallback callback) override {
-    smbprovider::ReadDirectoryOptionsProto options;
-    options.set_mount_id(mount_id);
-    options.set_directory_path(directory_path.value());
-    CallMethod(smbprovider::kStartReadDirectoryMethod, options,
-               &SmbProviderClientImpl::HandleStartReadDirectoryCallback,
-               &callback);
-  }
-
-  void ContinueReadDirectory(int32_t mount_id,
-                             int32_t read_dir_token,
-                             ReadDirectoryCallback callback) override {
-    dbus::MethodCall method_call(smbprovider::kSmbProviderInterface,
-                                 smbprovider::kContinueReadDirectoryMethod);
-    dbus::MessageWriter writer(&method_call);
-    writer.AppendInt32(mount_id);
-    writer.AppendInt32(read_dir_token);
-    CallMethod(&method_call,
-               &SmbProviderClientImpl::HandleContinueReadDirectoryCallback,
-               &callback);
-  }
-
-  void UpdateMountCredentials(int32_t mount_id,
-                              std::string workgroup,
-                              std::string username,
-                              base::ScopedFD password_fd,
-                              StatusCallback callback) override {
-    smbprovider::UpdateMountCredentialsOptionsProto options;
-    options.set_mount_id(mount_id);
-    options.set_workgroup(workgroup);
-    options.set_username(username);
-
-    dbus::MethodCall method_call(smbprovider::kSmbProviderInterface,
-                                 smbprovider::kUpdateMountCredentialsMethod);
-    dbus::MessageWriter writer(&method_call);
-    writer.AppendProtoAsArrayOfBytes(options);
-    writer.AppendFileDescriptor(password_fd.get());
-
-    CallDefaultMethod(&method_call, &callback);
-  }
-
-  void UpdateSharePath(int32_t mount_id,
-                       const std::string& share_path,
-                       StatusCallback callback) override {
-    smbprovider::UpdateSharePathOptionsProto options;
-    options.set_mount_id(mount_id);
-    options.set_path(share_path);
-
-    dbus::MethodCall method_call(smbprovider::kSmbProviderInterface,
-                                 smbprovider::kUpdateSharePathMethod);
-    dbus::MessageWriter writer(&method_call);
-    writer.AppendProtoAsArrayOfBytes(options);
-
-    CallDefaultMethod(&method_call, &callback);
-  }
-
  protected:
   // DBusClient override.
   void Init(dbus::Bus* bus) override {
@@ -436,122 +147,6 @@
                        std::move(*callback)));
   }
 
-  // Calls the CopyEntry D-Bus method with no timeout, passing the |protobuf| as
-  // an argument. Uses the default callback handler to process |callback|.
-  void CallCopyEntryMethod(const google::protobuf::MessageLite& protobuf,
-                           StatusCallback callback) {
-    dbus::MethodCall method_call(smbprovider::kSmbProviderInterface,
-                                 smbprovider::kCopyEntryMethod);
-    dbus::MessageWriter writer(&method_call);
-    writer.AppendProtoAsArrayOfBytes(protobuf);
-    proxy_->CallMethod(
-        &method_call, dbus::ObjectProxy::TIMEOUT_INFINITE,
-        base::BindOnce(&SmbProviderClientImpl::HandleDefaultCallback,
-                       GetWeakPtr(), method_call.GetMember(),
-                       std::move(callback)));
-  }
-
-  // Handles D-Bus callback for mount.
-  void HandleMountCallback(MountCallback callback, dbus::Response* response) {
-    if (!response) {
-      LOG(ERROR) << "Mount: failed to call smbprovider";
-      std::move(callback).Run(smbprovider::ERROR_DBUS_PARSE_FAILED, -1);
-      return;
-    }
-    dbus::MessageReader reader(response);
-    smbprovider::ErrorType error = GetErrorFromReader(&reader);
-    if (error != smbprovider::ERROR_OK) {
-      std::move(callback).Run(error, -1);
-      return;
-    }
-    int32_t mount_id = -1;
-    if (!reader.PopInt32(&mount_id) || mount_id < 0) {
-      LOG(ERROR) << "Mount: failed to parse mount id";
-      std::move(callback).Run(smbprovider::ERROR_DBUS_PARSE_FAILED, -1);
-      return;
-    }
-    std::move(callback).Run(smbprovider::ERROR_OK, mount_id);
-  }
-
-  // Handles D-Bus callback for OpenFile.
-  void HandleOpenFileCallback(OpenFileCallback callback,
-                              dbus::Response* response) {
-    if (!response) {
-      LOG(ERROR) << "OpenFile: failed to call smbprovider";
-      std::move(callback).Run(smbprovider::ERROR_DBUS_PARSE_FAILED, -1);
-      return;
-    }
-    dbus::MessageReader reader(response);
-    smbprovider::ErrorType error = GetErrorFromReader(&reader);
-    if (error != smbprovider::ERROR_OK) {
-      std::move(callback).Run(error, -1);
-      return;
-    }
-    int32_t file_id = -1;
-    if (!reader.PopInt32(&file_id) || file_id < 0) {
-      LOG(ERROR) << "OpenFile: failed to parse mount id";
-      std::move(callback).Run(smbprovider::ERROR_DBUS_PARSE_FAILED, -1);
-      return;
-    }
-    std::move(callback).Run(smbprovider::ERROR_OK, file_id);
-  }
-
-  // Handles D-Bus callback for ReadFile.
-  void HandleReadFileCallback(ReadFileCallback callback,
-                              dbus::Response* response) {
-    base::ScopedFD fd;
-    if (!response) {
-      LOG(ERROR) << "ReadFile: failed to call smbprovider";
-      std::move(callback).Run(smbprovider::ERROR_DBUS_PARSE_FAILED, fd);
-      return;
-    }
-    dbus::MessageReader reader(response);
-    smbprovider::ErrorType error = GetErrorFromReader(&reader);
-    if (error != smbprovider::ERROR_OK) {
-      std::move(callback).Run(error, fd);
-      return;
-    }
-    if (!reader.PopFileDescriptor(&fd)) {
-      LOG(ERROR) << "ReadFile: failed to parse file descriptor";
-      std::move(callback).Run(smbprovider::ERROR_DBUS_PARSE_FAILED, fd);
-      return;
-    }
-    std::move(callback).Run(smbprovider::ERROR_OK, fd);
-  }
-
-  // Handles D-Bus callback for GetDeleteList.
-  void HandleGetDeleteListCallback(GetDeleteListCallback callback,
-                                   dbus::Response* response) {
-    base::ScopedFD fd;
-    smbprovider::DeleteListProto delete_list;
-    if (!response) {
-      LOG(ERROR) << "GetDeleteList: failed to call smbprovider";
-      std::move(callback).Run(smbprovider::ERROR_DBUS_PARSE_FAILED,
-                              delete_list);
-      return;
-    }
-
-    dbus::MessageReader reader(response);
-    smbprovider::ErrorType error = GetErrorFromReader(&reader);
-    if (error != smbprovider::ERROR_OK) {
-      std::move(callback).Run(error, delete_list);
-      return;
-    }
-
-    int32_t bytes_written;
-    bool success = reader.PopFileDescriptor(&fd) &&
-                   reader.PopInt32(&bytes_written) &&
-                   ParseDeleteList(fd, bytes_written, &delete_list);
-    if (!success) {
-      LOG(ERROR) << "GetDeleteList: parse failure.";
-      std::move(callback).Run(smbprovider::ERROR_DBUS_PARSE_FAILED,
-                              delete_list);
-      return;
-    }
-
-    std::move(callback).Run(smbprovider::ERROR_OK, delete_list);
-  }
-
   // Handles D-Bus callback for SetupKerberos.
   void HandleSetupKerberosCallback(SetupKerberosCallback callback,
                                    dbus::Response* response) {
@@ -594,87 +189,6 @@
     std::move(callback).Run(hostnames);
   }
 
-  void HandleStartCopyCallback(StartCopyCallback callback,
-                               dbus::Response* response) {
-    if (!response) {
-      LOG(ERROR) << "StartCopy: failed to call smbprovider";
-      std::move(callback).Run(smbprovider::ERROR_DBUS_PARSE_FAILED,
-                              -1 /* copy_token */);
-      return;
-    }
-
-    dbus::MessageReader reader(response);
-
-    smbprovider::ErrorType error = GetErrorFromReader(&reader);
-
-    int32_t copy_token;
-    if (!reader.PopInt32(&copy_token)) {
-      LOG(ERROR) << "StartCopy: parse failure.";
-      std::move(callback).Run(smbprovider::ERROR_DBUS_PARSE_FAILED,
-                              -1 /* copy_token*/);
-      return;
-    }
-
-    if (error != smbprovider::ERROR_COPY_PENDING) {
-      std::move(callback).Run(error, -1 /* copy_token */);
-      return;
-    }
-
-    std::move(callback).Run(smbprovider::ERROR_COPY_PENDING, copy_token);
-  }
-
-  void HandleStartReadDirectoryCallback(StartReadDirectoryCallback callback,
-                                        dbus::Response* response) {
-    if (!response) {
-      LOG(ERROR) << "StartReadDirectory: failed to call smbprovider";
-      std::move(callback).Run(smbprovider::ERROR_DBUS_PARSE_FAILED,
-                              -1 /* read_dir_token */,
-                              smbprovider::DirectoryEntryListProto());
-      return;
-    }
-
-    dbus::MessageReader reader(response);
-
-    smbprovider::ErrorType error = GetErrorFromReader(&reader);
-
-    smbprovider::DirectoryEntryListProto entries;
-    int32_t read_dir_token;
-    if (!reader.PopArrayOfBytesAsProto(&entries) ||
-        !reader.PopInt32(&read_dir_token)) {
-      LOG(ERROR) << "StartReadDirectory: Failed to parse protobuf.";
-      std::move(callback).Run(smbprovider::ERROR_DBUS_PARSE_FAILED,
-                              -1 /* read_dir_token */,
-                              smbprovider::DirectoryEntryListProto());
-      return;
-    }
-
-    std::move(callback).Run(error, read_dir_token, entries);
-  }
-
-  void HandleContinueReadDirectoryCallback(ReadDirectoryCallback callback,
-                                           dbus::Response* response) {
-    if (!response) {
-      LOG(ERROR) << "ContinueReadDirectory: failed to call smbprovider";
-      std::move(callback).Run(smbprovider::ERROR_DBUS_PARSE_FAILED,
-                              smbprovider::DirectoryEntryListProto());
-      return;
-    }
-
-    dbus::MessageReader reader(response);
-
-    smbprovider::ErrorType error = GetErrorFromReader(&reader);
-
-    smbprovider::DirectoryEntryListProto entries;
-    if (!reader.PopArrayOfBytesAsProto(&entries)) {
-      LOG(ERROR) << "ContinueReadDirectory: Failed to parse protobuf.";
-      std::move(callback).Run(smbprovider::ERROR_DBUS_PARSE_FAILED,
-                              smbprovider::DirectoryEntryListProto());
-      return;
-    }
-
-    std::move(callback).Run(error, entries);
-  }
-
   // Default callback handler for D-Bus calls.
   void HandleDefaultCallback(const std::string& method_name,
                              StatusCallback callback,
@@ -710,10 +224,6 @@
 
 }  // namespace
 
-SmbProviderClient::MountOptions::MountOptions() = default;
-
-SmbProviderClient::MountOptions::~MountOptions() = default;
-
 SmbProviderClient::SmbProviderClient() = default;
 
 SmbProviderClient::~SmbProviderClient() = default;
diff --git a/chromeos/dbus/smb_provider_client.h b/chromeos/dbus/smb_provider_client.h
index e58b24a9..2748ccdc 100644
--- a/chromeos/dbus/smb_provider_client.h
+++ b/chromeos/dbus/smb_provider_client.h
@@ -27,55 +27,13 @@
     : public DBusClient,
       public base::SupportsWeakPtr<SmbProviderClient> {
  public:
-  using GetMetdataEntryCallback =
-      base::OnceCallback<void(smbprovider::ErrorType error,
-                              const smbprovider::DirectoryEntryProto& entry)>;
-  using MountCallback =
-      base::OnceCallback<void(smbprovider::ErrorType error, int32_t mount_id)>;
-  using OpenFileCallback =
-      base::OnceCallback<void(smbprovider::ErrorType error, int32_t file_id)>;
   using ReadDirectoryCallback = base::OnceCallback<void(
       smbprovider::ErrorType error,
       const smbprovider::DirectoryEntryListProto& entries)>;
   using StatusCallback = base::OnceCallback<void(smbprovider::ErrorType error)>;
-  using ReadFileCallback = base::OnceCallback<void(smbprovider::ErrorType error,
-                                                   const base::ScopedFD& fd)>;
-  using GetDeleteListCallback =
-      base::OnceCallback<void(smbprovider::ErrorType error,
-                              const smbprovider::DeleteListProto& delete_list)>;
   using SetupKerberosCallback = base::OnceCallback<void(bool success)>;
   using ParseNetBiosPacketCallback =
       base::OnceCallback<void(const std::vector<std::string>&)>;
-  using StartCopyCallback =
-      base::OnceCallback<void(smbprovider::ErrorType error,
-                              int32_t copy_token)>;
-  using StartReadDirectoryCallback = base::OnceCallback<void(
-      smbprovider::ErrorType error,
-      int32_t read_dir_token,
-      const smbprovider::DirectoryEntryListProto& entries)>;
-
-  // Optional arguments to pass to Mount().
-  struct MountOptions {
-    MountOptions();
-    ~MountOptions();
-
-    std::string original_path;
-    std::string username;
-    std::string workgroup;
-    std::string account_hash;
-
-    // Enable NTLM Authentication.
-    bool ntlm_enabled = false;
-
-    // Do not attempt to connect to and authenticate the mounted share.
-    bool skip_connect = false;
-
-    // Save the password for this share if it is successfully mounted.
-    bool save_password = false;
-
-    // Use a saved password for authenticating the share.
-    bool restore_password = false;
-  };
 
   ~SmbProviderClient() override;
 
@@ -83,121 +41,6 @@
   // For normal usage, access the singleton via DBusThreadManager::Get().
   static std::unique_ptr<SmbProviderClient> Create();
 
-  // Calls Mount. It runs OpenDirectory() on |share_path| to check that it is a
-  // valid share. |options.workgroup|, |options.username|, and |password_fd|
-  // will be used as credentials to access the mount. |callback| is called after
-  // getting (or failing to get) D-BUS response.
-  virtual void Mount(const base::FilePath& share_path,
-                     const MountOptions& options,
-                     base::ScopedFD password_fd,
-                     MountCallback callback) = 0;
-
-  // Calls Unmount. This removes the corresponding mount of |mount_id| from
-  // the list of valid mounts. Subsequent operations on |mount_id| will fail.
-  virtual void Unmount(int32_t mount_id,
-                       bool remove_password,
-                       StatusCallback callback) = 0;
-
-  // Calls ReadDirectory. Using the corresponding mount of |mount_id|, this
-  // reads the directory on a given |directory_path| and passes the
-  // DirectoryEntryList to the supplied ReadDirectoryCallback.
-  virtual void ReadDirectory(int32_t mount_id,
-                             const base::FilePath& directory_path,
-                             ReadDirectoryCallback callback) = 0;
-
-  // Calls GetMetadataEntry. Using the corresponding mount of |mount_id|, this
-  // reads an entry in a given |entry_path| and passes the DirectoryEntry to the
-  // supplied GetMetadataEntryCallback.
-  virtual void GetMetadataEntry(int32_t mount_id,
-                                const base::FilePath& entry_path,
-                                GetMetdataEntryCallback callback) = 0;
-
-  // Calls OpenFile. Using the corresponding mount |mount_id|, this opens the
-  // file at a given |file_path|, and passes a file handle to the supplied
-  // OpenFileCallback.
-  virtual void OpenFile(int32_t mount_id,
-                        const base::FilePath& file_path,
-                        bool writeable,
-                        OpenFileCallback callback) = 0;
-
-  // Calls CloseFile. This closes the file with mount |mount_id| and handle
-  // |file_id|. Subsequent operations using file with this handle will fail.
-  virtual void CloseFile(int32_t mount_id,
-                         int32_t file_id,
-                         StatusCallback callback) = 0;
-
-  // Calls ReadFile. Using the corresponding mount |mount_id|, this reads the
-  // file with handle |file_id| from |offset| and reads up to |length| in bytes.
-  // The data read is saved to a temporary file and is returned as a file
-  // descriptor in the supplied ReadFileCallback.
-  virtual void ReadFile(int32_t mount_id,
-                        int32_t file_id,
-                        int64_t offset,
-                        int32_t length,
-                        ReadFileCallback callback) = 0;
-
-  // Calls DeleteEntry. This deletes the file or directory at |entry_path|.
-  // Subsequent operations on the entry at this path will fail.
-  virtual void DeleteEntry(int32_t mount_id,
-                           const base::FilePath& entry_path,
-                           bool recursive,
-                           StatusCallback callback) = 0;
-
-  // Calls CreateFile. Using the corresponding mount |mount_id|, this creates
-  // the file in the specified |file_path|.
-  virtual void CreateFile(int32_t mount_id,
-                          const base::FilePath& file_path,
-                          StatusCallback callback) = 0;
-
-  // Calls Truncate. Using the corresponding mount |mount_id|, this truncates
-  // the file in |file_path| to the desired |length|.
-  virtual void Truncate(int32_t mount_id,
-                        const base::FilePath& file_path,
-                        int64_t length,
-                        StatusCallback callback) = 0;
-
-  // Calls WriteFile. Using the corresponding mount |mount_id|, this writes to a
-  // file with handle |file_id| from |offset| and writes |length| bytes. The
-  // data to be written is contained in the file with handle |temp_fd|.
-  virtual void WriteFile(int32_t mount_id,
-                         int32_t file_id,
-                         int64_t offset,
-                         int32_t length,
-                         base::ScopedFD temp_fd,
-                         StatusCallback callback) = 0;
-
-  // Calls CreateDirectory. Using the corresponding |mount_id|, this creates the
-  // directory at |directory_path|. If |recursive| is set to true, this creates
-  // all non-existing directories on the path. The operation will fail if the
-  // directory already exists.
-  virtual void CreateDirectory(int32_t mount_id,
-                               const base::FilePath& directory_path,
-                               bool recursive,
-                               StatusCallback callback) = 0;
-
-  // Calls MoveEntry. Using the corresponding |mount_id|, this moves the entry
-  // at |source_path| to |target_path|. This operation will fail if the
-  // target already exists.
-  virtual void MoveEntry(int32_t mount_id,
-                         const base::FilePath& source_path,
-                         const base::FilePath& target_path,
-                         StatusCallback callback) = 0;
-
-  // Calls CopyEntry. Using the corresponding |mount_id|, this copies the entry
-  // at |source_path| to |target_path|. This operation will fail if the
-  // target already exists.
-  virtual void CopyEntry(int32_t mount_id,
-                         const base::FilePath& source_path,
-                         const base::FilePath& target_path,
-                         StatusCallback callback) = 0;
-
-  // Calls GetDeleteList. Using the corresponding |mount_id|, this generates an
-  // ordered list of individual entries that must be deleted in order to delete
-  // |entry_path|. This operations does not modify the filesystem.
-  virtual void GetDeleteList(int32_t mount_id,
-                             const base::FilePath& entry_path,
-                             GetDeleteListCallback callback) = 0;
-
   // Calls GetShares. This gets the shares from |server_url| and calls
   // |callback| when shares are found. The DirectoryEntryListProto will contain
   // no entries if there are no shares found.
@@ -218,54 +61,6 @@
                                   uint16_t transaction_id,
                                   ParseNetBiosPacketCallback callback) = 0;
 
-  // Calls StartCopy. This starts the copy from |source_path| to |target_path|.
-  // In order to avoid blocking the SmbProvider daemon, this operation performs
-  // one unit of work and returns smbprovider::ERROR_COPY_PENDING along with a
-  // continuation token to |callback| if there is more work to do.
-  virtual void StartCopy(int32_t mount_id,
-                         const base::FilePath& source_path,
-                         const base::FilePath& target_path,
-                         StartCopyCallback callback) = 0;
-
-  // Calls ContinueCopy. This continues the copy corresponding to |copy_token|.
-  // In order to avoid blocking the SmbProvider daemon, this operation performs
-  // one unit of work and returns smbprovider::ERROR_COPY_PENDING if there is
-  // more work to do.
-  virtual void ContinueCopy(int32_t mount_id,
-                            int32_t copy_token,
-                            StatusCallback callback) = 0;
-
-  // Calls StartReadDirectory. This starts a read directory of |directory_path|.
-  // Returns smbprovider::ERROR_OPERATION_PENDING if there is more work to do.
-  virtual void StartReadDirectory(int32_t mount_id,
-                                  const base::FilePath& directory_path,
-                                  StartReadDirectoryCallback callback) = 0;
-
-  // Calls ContinueReadDirectory. This continues the copy corresponding to
-  // |read_dir_token|. Returns smbprovider::ERROR_OPERATION_PENDING if there is
-  // more work to do.
-  virtual void ContinueReadDirectory(int32_t mount_id,
-                                     int32_t read_dir_token,
-                                     ReadDirectoryCallback callback) = 0;
-
-  // Calls UpdateMountCredentials. This will update a mount's credentials with
-  // |workgroup|, |username|, and |password_fd|. Returns smbprovider::ERROR_OK
-  // if the mount's credentials successfully updated. Returns
-  // smbprovider::ERROR_NOT_FOUND if the mount's credentials were not updated.
-  virtual void UpdateMountCredentials(int32_t mount_id,
-                                      std::string workgroup,
-                                      std::string username,
-                                      base::ScopedFD password_fd,
-                                      StatusCallback callback) = 0;
-
-  // Calls UpdateSharePath. This will update a mount's share path with
-  // |share_path|. Returns smbprovider::ERROR_OK if the mount's share path was
-  // successfully updated. Returns smbprovider::ERROR_NOT_FOUND if the mount's
-  // share path were not updated.
-  virtual void UpdateSharePath(int32_t mount_id,
-                               const std::string& share_path,
-                               StatusCallback callback) = 0;
-
  protected:
   // Create() should be used instead.
   SmbProviderClient();
diff --git a/chromeos/hugepage_text/OWNERS b/chromeos/hugepage_text/OWNERS
index 67b0f2a4..4ad6b380 100644
--- a/chromeos/hugepage_text/OWNERS
+++ b/chromeos/hugepage_text/OWNERS
@@ -1,4 +1,3 @@
-llozano@chromium.org
 gbiv@chromium.org
+llozano@chromium.org
 manojgupta@chromium.org
-tcwang@chromium.org
diff --git a/chromeos/profiles/bigcore.afdo.newest.txt b/chromeos/profiles/bigcore.afdo.newest.txt
index 6b959206e..511c629 100644
--- a/chromeos/profiles/bigcore.afdo.newest.txt
+++ b/chromeos/profiles/bigcore.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-bigcore-93-4554.0-1626087514-benchmark-93.0.4574.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-bigcore-93-4554.0-1626087514-benchmark-93.0.4576.0-r1-redacted.afdo.xz
diff --git a/chromeos/settings/cros_settings_names.cc b/chromeos/settings/cros_settings_names.cc
index 9c0e77e..e4b7fb5 100644
--- a/chromeos/settings/cros_settings_names.cc
+++ b/chromeos/settings/cros_settings_names.cc
@@ -138,11 +138,23 @@
 // along with device policy requests.
 const char kReportDeviceLocation[] = "cros.device_status.report_location";
 
+// Determines whether the device reports static network configuration info such
+// as MAC Address, MEID, and MEI in device status reports to the device
+// management server.
+const char kReportDeviceNetworkConfiguration[] =
+    "cros.device_status.report_network_configuration";
+
 // Determines whether the device reports network interface types and addresses
 // in device status reports to the device management server.
 const char kReportDeviceNetworkInterfaces[] =
     "cros.device_status.report_network_interfaces";
 
+// Determines whether the device reports dynamic network information such
+// connection state, signal strength, and IP Address in device status reports
+// and to management server.
+const char kReportDeviceNetworkStatus[] =
+    "cros.device_status.report_network_status";
+
 // A boolean pref that determines whether the device power status should be
 // included in status reports to the device management server.
 const char kReportDevicePowerStatus[] =
diff --git a/chromeos/settings/cros_settings_names.h b/chromeos/settings/cros_settings_names.h
index 8770289a9..63353ae 100644
--- a/chromeos/settings/cros_settings_names.h
+++ b/chromeos/settings/cros_settings_names.h
@@ -98,8 +98,12 @@
 extern const char kReportDeviceBacklightInfo[];
 COMPONENT_EXPORT(CHROMEOS_SETTINGS) extern const char kReportDeviceLocation[];
 COMPONENT_EXPORT(CHROMEOS_SETTINGS)
+extern const char kReportDeviceNetworkConfiguration[];
+COMPONENT_EXPORT(CHROMEOS_SETTINGS)
 extern const char kReportDeviceNetworkInterfaces[];
 COMPONENT_EXPORT(CHROMEOS_SETTINGS)
+extern const char kReportDeviceNetworkStatus[];
+COMPONENT_EXPORT(CHROMEOS_SETTINGS)
 extern const char kReportDevicePowerStatus[];
 COMPONENT_EXPORT(CHROMEOS_SETTINGS)
 extern const char kReportDeviceStorageStatus[];
@@ -401,7 +405,9 @@
 using ::chromeos::kReportDeviceLocation;
 using ::chromeos::kReportDeviceLoginLogout;
 using ::chromeos::kReportDeviceMemoryInfo;
+using ::chromeos::kReportDeviceNetworkConfiguration;
 using ::chromeos::kReportDeviceNetworkInterfaces;
+using ::chromeos::kReportDeviceNetworkStatus;
 using ::chromeos::kReportDevicePowerStatus;
 using ::chromeos::kReportDevicePrintJobs;
 using ::chromeos::kReportDeviceSessionStatus;
diff --git a/components/account_manager_core/BUILD.gn b/components/account_manager_core/BUILD.gn
index 19875fd..b20d05c 100644
--- a/components/account_manager_core/BUILD.gn
+++ b/components/account_manager_core/BUILD.gn
@@ -20,8 +20,14 @@
     "account_manager_facade_impl.h",
     "account_manager_util.cc",
     "account_manager_util.h",
+    "chromeos/access_token_fetcher.cc",
+    "chromeos/access_token_fetcher.h",
     "chromeos/account_manager.cc",
     "chromeos/account_manager.h",
+    "chromeos/account_manager_ash.cc",
+    "chromeos/account_manager_ash.h",
+    "chromeos/account_manager_ui.cc",
+    "chromeos/account_manager_ui.h",
     "pref_names.cc",
     "pref_names.h",
   ]
@@ -56,6 +62,7 @@
 
   sources = [
     "account_manager_facade_impl_unittest.cc",
+    "chromeos/account_manager_ash_unittest.cc",
     "chromeos/account_manager_unittest.cc",
   ]
 
diff --git a/components/account_manager_core/DEPS b/components/account_manager_core/DEPS
index 727c09f..6fc7e71 100644
--- a/components/account_manager_core/DEPS
+++ b/components/account_manager_core/DEPS
@@ -11,4 +11,8 @@
    'account_manager_unittest.cc': [
       '+services/network/test/test_url_loader_factory.h',
    ],
+  'account_manager_ash_unittest.cc': [
+      '+chromeos/crosapi/mojom/account_manager.mojom-test-utils.h',
+      '+services/network/test/test_url_loader_factory.h',
+   ],
 }
diff --git a/ash/components/account_manager/access_token_fetcher.cc b/components/account_manager_core/chromeos/access_token_fetcher.cc
similarity index 97%
rename from ash/components/account_manager/access_token_fetcher.cc
rename to components/account_manager_core/chromeos/access_token_fetcher.cc
index 4662263..589abd7 100644
--- a/ash/components/account_manager/access_token_fetcher.cc
+++ b/components/account_manager_core/chromeos/access_token_fetcher.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/account_manager/access_token_fetcher.h"
+#include "components/account_manager_core/chromeos/access_token_fetcher.h"
 
 #include <string>
 #include <utility>
diff --git a/ash/components/account_manager/access_token_fetcher.h b/components/account_manager_core/chromeos/access_token_fetcher.h
similarity index 91%
rename from ash/components/account_manager/access_token_fetcher.h
rename to components/account_manager_core/chromeos/access_token_fetcher.h
index 05971d5..5a65db0 100644
--- a/ash/components/account_manager/access_token_fetcher.h
+++ b/components/account_manager_core/chromeos/access_token_fetcher.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_ACCOUNT_MANAGER_ACCESS_TOKEN_FETCHER_H_
-#define ASH_COMPONENTS_ACCOUNT_MANAGER_ACCESS_TOKEN_FETCHER_H_
+#ifndef COMPONENTS_ACCOUNT_MANAGER_CORE_CHROMEOS_ACCESS_TOKEN_FETCHER_H_
+#define COMPONENTS_ACCOUNT_MANAGER_CORE_CHROMEOS_ACCESS_TOKEN_FETCHER_H_
 
 #include <memory>
 #include <string>
@@ -66,4 +66,4 @@
 
 }  // namespace crosapi
 
-#endif  // ASH_COMPONENTS_ACCOUNT_MANAGER_ACCESS_TOKEN_FETCHER_H_
+#endif  // COMPONENTS_ACCOUNT_MANAGER_CORE_CHROMEOS_ACCESS_TOKEN_FETCHER_H_
diff --git a/ash/components/account_manager/account_manager_ash.cc b/components/account_manager_core/chromeos/account_manager_ash.cc
similarity index 95%
rename from ash/components/account_manager/account_manager_ash.cc
rename to components/account_manager_core/chromeos/account_manager_ash.cc
index 1d43def..b5fb2090 100644
--- a/ash/components/account_manager/account_manager_ash.cc
+++ b/components/account_manager_core/chromeos/account_manager_ash.cc
@@ -2,14 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/account_manager/account_manager_ash.h"
+#include "components/account_manager_core/chromeos/account_manager_ash.h"
 
 #include <algorithm>
 #include <memory>
 #include <utility>
 
-#include "ash/components/account_manager/access_token_fetcher.h"
-#include "ash/components/account_manager/account_manager_ui.h"
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/logging.h"
@@ -18,7 +16,9 @@
 #include "components/account_manager_core/account.h"
 #include "components/account_manager_core/account_addition_result.h"
 #include "components/account_manager_core/account_manager_util.h"
+#include "components/account_manager_core/chromeos/access_token_fetcher.h"
 #include "components/account_manager_core/chromeos/account_manager.h"
+#include "components/account_manager_core/chromeos/account_manager_ui.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -68,7 +68,7 @@
 }
 
 void AccountManagerAsh::SetAccountManagerUI(
-    std::unique_ptr<ash::AccountManagerUI> account_manager_ui) {
+    std::unique_ptr<account_manager::AccountManagerUI> account_manager_ui) {
   account_manager_ui_ = std::move(account_manager_ui);
 }
 
diff --git a/ash/components/account_manager/account_manager_ash.h b/components/account_manager_core/chromeos/account_manager_ash.h
similarity index 86%
rename from ash/components/account_manager/account_manager_ash.h
rename to components/account_manager_core/chromeos/account_manager_ash.h
index 62809c9..3745fe3 100644
--- a/ash/components/account_manager/account_manager_ash.h
+++ b/components/account_manager_core/chromeos/account_manager_ash.h
@@ -2,19 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_ACCOUNT_MANAGER_ACCOUNT_MANAGER_ASH_H_
-#define ASH_COMPONENTS_ACCOUNT_MANAGER_ACCOUNT_MANAGER_ASH_H_
+#ifndef COMPONENTS_ACCOUNT_MANAGER_CORE_CHROMEOS_ACCOUNT_MANAGER_ASH_H_
+#define COMPONENTS_ACCOUNT_MANAGER_CORE_CHROMEOS_ACCOUNT_MANAGER_ASH_H_
 
 #include <memory>
 #include <vector>
 
-#include "ash/components/account_manager/access_token_fetcher.h"
-#include "ash/components/account_manager/account_manager_ui.h"
 #include "base/callback_forward.h"
 #include "chromeos/crosapi/mojom/account_manager.mojom.h"
 #include "components/account_manager_core/account.h"
 #include "components/account_manager_core/account_addition_result.h"
+#include "components/account_manager_core/chromeos/access_token_fetcher.h"
 #include "components/account_manager_core/chromeos/account_manager.h"
+#include "components/account_manager_core/chromeos/account_manager_ui.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
 #include "mojo/public/cpp/bindings/remote_set.h"
@@ -29,7 +29,7 @@
 // Implements the |crosapi::mojom::AccountManager| interface in ash-chrome.
 // It enables lacros-chrome to interact with accounts stored in the Chrome OS
 // Account Manager.
-class COMPONENT_EXPORT(ASH_COMPONENTS_ACCOUNT_MANAGER) AccountManagerAsh
+class COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE) AccountManagerAsh
     : public mojom::AccountManager,
       public account_manager::AccountManager::Observer {
  public:
@@ -41,7 +41,7 @@
   void BindReceiver(mojo::PendingReceiver<mojom::AccountManager> receiver);
 
   void SetAccountManagerUI(
-      std::unique_ptr<ash::AccountManagerUI> account_manager_ui);
+      std::unique_ptr<account_manager::AccountManagerUI> account_manager_ui);
 
   // crosapi::mojom::AccountManager:
   void IsInitialized(IsInitializedCallback callback) override;
@@ -85,7 +85,7 @@
   ShowAddAccountDialogCallback account_addition_callback_;
   bool account_addition_in_progress_ = false;
   account_manager::AccountManager* const account_manager_;
-  std::unique_ptr<ash::AccountManagerUI> account_manager_ui_;
+  std::unique_ptr<account_manager::AccountManagerUI> account_manager_ui_;
   std::vector<std::unique_ptr<AccessTokenFetcher>>
       pending_access_token_requests_;
 
@@ -100,4 +100,4 @@
 
 }  // namespace crosapi
 
-#endif  // ASH_COMPONENTS_ACCOUNT_MANAGER_ACCOUNT_MANAGER_ASH_H_
+#endif  // COMPONENTS_ACCOUNT_MANAGER_CORE_CHROMEOS_ACCOUNT_MANAGER_ASH_H_
diff --git a/ash/components/account_manager/account_manager_ash_unittest.cc b/components/account_manager_core/chromeos/account_manager_ash_unittest.cc
similarity index 98%
rename from ash/components/account_manager/account_manager_ash_unittest.cc
rename to components/account_manager_core/chromeos/account_manager_ash_unittest.cc
index f2b9ab1..f50940b 100644
--- a/ash/components/account_manager/account_manager_ash_unittest.cc
+++ b/components/account_manager_core/chromeos/account_manager_ash_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/account_manager/account_manager_ash.h"
+#include "components/account_manager_core/chromeos/account_manager_ash.h"
 
 #include <cstddef>
 #include <memory>
@@ -10,8 +10,6 @@
 #include <utility>
 #include <vector>
 
-#include "ash/components/account_manager/access_token_fetcher.h"
-#include "ash/components/account_manager/account_manager_ui.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/run_loop.h"
@@ -21,7 +19,9 @@
 #include "chromeos/crosapi/mojom/account_manager.mojom.h"
 #include "components/account_manager_core/account.h"
 #include "components/account_manager_core/account_manager_util.h"
+#include "components/account_manager_core/chromeos/access_token_fetcher.h"
 #include "components/account_manager_core/chromeos/account_manager.h"
+#include "components/account_manager_core/chromeos/account_manager_ui.h"
 #include "components/prefs/testing_pref_service.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "google_apis/gaia/google_service_auth_error.h"
@@ -110,7 +110,7 @@
   mojo::Receiver<mojom::AccountManagerObserver> receiver_;
 };
 
-class FakeAccountManagerUI : public ash::AccountManagerUI {
+class FakeAccountManagerUI : public account_manager::AccountManagerUI {
  public:
   FakeAccountManagerUI() = default;
   FakeAccountManagerUI(const FakeAccountManagerUI&) = delete;
diff --git a/ash/components/account_manager/account_manager_ui.cc b/components/account_manager_core/chromeos/account_manager_ui.cc
similarity index 66%
rename from ash/components/account_manager/account_manager_ui.cc
rename to components/account_manager_core/chromeos/account_manager_ui.cc
index adc64e2..fc0c619 100644
--- a/ash/components/account_manager/account_manager_ui.cc
+++ b/components/account_manager_core/chromeos/account_manager_ui.cc
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/components/account_manager/account_manager_ui.h"
+#include "components/account_manager_core/chromeos/account_manager_ui.h"
 
-namespace ash {
+namespace account_manager {
 
 AccountManagerUI::AccountManagerUI() = default;
 AccountManagerUI::~AccountManagerUI() = default;
 
-}  // namespace ash
+}  // namespace account_manager
diff --git a/ash/components/account_manager/account_manager_ui.h b/components/account_manager_core/chromeos/account_manager_ui.h
similarity index 77%
rename from ash/components/account_manager/account_manager_ui.h
rename to components/account_manager_core/chromeos/account_manager_ui.h
index afd93df..5354a60 100644
--- a/ash/components/account_manager/account_manager_ui.h
+++ b/components/account_manager_core/chromeos/account_manager_ui.h
@@ -2,18 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_COMPONENTS_ACCOUNT_MANAGER_ACCOUNT_MANAGER_UI_H_
-#define ASH_COMPONENTS_ACCOUNT_MANAGER_ACCOUNT_MANAGER_UI_H_
+#ifndef COMPONENTS_ACCOUNT_MANAGER_CORE_CHROMEOS_ACCOUNT_MANAGER_UI_H_
+#define COMPONENTS_ACCOUNT_MANAGER_CORE_CHROMEOS_ACCOUNT_MANAGER_UI_H_
 
 #include "base/callback.h"
 #include "base/callback_forward.h"
 #include "base/component_export.h"
 
-namespace ash {
+namespace account_manager {
 
 // This interface is used by `AccountManagerFacadeImpl` to show system UI
 // (system dialogs, OS Settings etc.)
-class COMPONENT_EXPORT(ASH_COMPONENTS_ACCOUNT_MANAGER) AccountManagerUI {
+class COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE) AccountManagerUI {
  public:
   AccountManagerUI();
   AccountManagerUI(const AccountManagerUI&) = delete;
@@ -37,6 +37,6 @@
   virtual void ShowManageAccountsSettings() = 0;
 };
 
-}  // namespace ash
+}  // namespace account_manager
 
-#endif  // ASH_COMPONENTS_ACCOUNT_MANAGER_ACCOUNT_MANAGER_UI_H_
+#endif  // COMPONENTS_ACCOUNT_MANAGER_CORE_CHROMEOS_ACCOUNT_MANAGER_UI_H_
diff --git a/components/autofill/core/browser/autofill_download_manager.cc b/components/autofill/core/browser/autofill_download_manager.cc
index 0780018..20f84b29 100644
--- a/components/autofill/core/browser/autofill_download_manager.cc
+++ b/components/autofill/core/browser/autofill_download_manager.cc
@@ -54,6 +54,7 @@
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 #include "url/gurl.h"
 
 namespace autofill {
diff --git a/components/autofill/core/browser/autofill_download_manager_unittest.cc b/components/autofill/core/browser/autofill_download_manager_unittest.cc
index 7432e64..9d06d06 100644
--- a/components/autofill/core/browser/autofill_download_manager_unittest.cc
+++ b/components/autofill/core/browser/autofill_download_manager_unittest.cc
@@ -49,6 +49,7 @@
 #include "net/test/embedded_test_server/http_response.h"
 #include "services/network/public/cpp/data_element.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 #include "services/network/test/test_shared_url_loader_factory.h"
 #include "services/network/test/test_url_loader_factory.h"
 #include "services/network/test/test_utils.h"
diff --git a/components/autofill/core/browser/payments/payments_client.cc b/components/autofill/core/browser/payments/payments_client.cc
index 0bc800e..5e07122 100644
--- a/components/autofill/core/browser/payments/payments_client.cc
+++ b/components/autofill/core/browser/payments/payments_client.cc
@@ -43,6 +43,7 @@
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 
 namespace autofill {
 namespace payments {
diff --git a/components/certificate_transparency/data/log_list.json b/components/certificate_transparency/data/log_list.json
index b154b67..57306a24 100644
--- a/components/certificate_transparency/data/log_list.json
+++ b/components/certificate_transparency/data/log_list.json
@@ -282,8 +282,8 @@
           "url": "https://yeti2022.ct.digicert.com/log/",
           "mmd": 86400,
           "state": {
-            "usable": {
-              "timestamp": "2018-08-24T00:53:07Z"
+            "retired": {
+              "timestamp": "2021-07-21T00:00:00Z"
             }
           },
           "temporal_interval": {
diff --git a/components/crash/core/app/crashpad.cc b/components/crash/core/app/crashpad.cc
index 27f5504d..42938c3 100644
--- a/components/crash/core/app/crashpad.cc
+++ b/components/crash/core/app/crashpad.cc
@@ -279,6 +279,11 @@
 void DumpWithoutCrashAndDeferProcessing() {
   CRASHPAD_SIMULATE_CRASH_AND_DEFER_PROCESSING();
 }
+
+void DumpWithoutCrashAndDeferProcessingAtPath(const base::FilePath& path) {
+  CRASHPAD_SIMULATE_CRASH_AND_DEFER_PROCESSING_AT_PATH(path);
+}
+
 #endif
 
 #endif
diff --git a/components/crash/core/app/crashpad.h b/components/crash/core/app/crashpad.h
index 6c6f3af..9b1176b 100644
--- a/components/crash/core/app/crashpad.h
+++ b/components/crash/core/app/crashpad.h
@@ -148,6 +148,7 @@
 
 #if defined(OS_IOS)
 void DumpWithoutCrashAndDeferProcessing();
+void DumpWithoutCrashAndDeferProcessingAtPath(const base::FilePath& path);
 #endif
 
 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
@@ -181,15 +182,24 @@
 #endif
 
 #if defined(OS_IOS)
-// Convert intermediate dumps into minidumps and trigger an upload. Optional
-// |annotations| will be merged with any process annotations. These are useful
-// for adding annotations detected on the next run after a crash but before
-// upload.
+// Convert intermediate dumps into minidumps and trigger an upload if
+// StartProcessingPendingReports() has been called. Optional |annotations| will
+// merge with any process annotations. These are useful for adding annotations
+// detected on the next run after a crash but before upload.
 void ProcessIntermediateDumps(
     const std::map<std::string, std::string>& annotations = {});
 
+// Convert a single intermediate dump at |file| into a minidump and
+// trigger an upload if StartProcessingPendingReports() has been called.
+// Optional |annotations| will merge with any process annotations. These are
+// useful for adding annotations detected on the next run after a crash but
+// before upload.
+void ProcessIntermediateDump(
+    const base::FilePath& file,
+    const std::map<std::string, std::string>& annotations = {});
+
 // Requests that the handler begin in-process uploading of any pending reports.
-void StartProcesingPendingReports();
+void StartProcessingPendingReports();
 #endif
 
 #if defined(OS_ANDROID)
diff --git a/components/crash/core/app/crashpad_ios.mm b/components/crash/core/app/crashpad_ios.mm
index b12f410..7074895 100644
--- a/components/crash/core/app/crashpad_ios.mm
+++ b/components/crash/core/app/crashpad_ios.mm
@@ -63,8 +63,14 @@
   GetCrashpadClient().ProcessIntermediateDumps(annotations);
 }
 
-void StartProcesingPendingReports() {
-  GetCrashpadClient().StartProcesingPendingReports();
+void ProcessIntermediateDump(
+    const base::FilePath& file,
+    const std::map<std::string, std::string>& annotations) {
+  GetCrashpadClient().ProcessIntermediateDump(file, annotations);
+}
+
+void StartProcessingPendingReports() {
+  GetCrashpadClient().StartProcessingPendingReports();
 }
 
 namespace internal {
diff --git a/components/desks_storage/BUILD.gn b/components/desks_storage/BUILD.gn
index 3a6203c..b091cd1 100644
--- a/components/desks_storage/BUILD.gn
+++ b/components/desks_storage/BUILD.gn
@@ -11,13 +11,14 @@
     "core/desk_model_observer.h",
     "core/desk_sync_bridge.cc",
     "core/desk_sync_bridge.h",
-    "core/desk_template.cc",
-    "core/desk_template.h",
     "core/local_desk_data_manager.cc",
     "core/local_desk_data_manager.h",
   ]
   deps = [
+    "//ash/public/cpp",
     "//base",
+    "//base/util/values:values_util",
+    "//components/full_restore",
     "//components/sync",
     "//components/sync/model",
     "//components/sync/protocol",
@@ -36,6 +37,7 @@
   ]
   deps = [
     ":desks_storage",
+    "//ash/public/cpp",
     "//base",
     "//base/test:test_support",
     "//components/sync:test_support",
diff --git a/components/desks_storage/DEPS b/components/desks_storage/DEPS
index 5fb592e..8815754 100644
--- a/components/desks_storage/DEPS
+++ b/components/desks_storage/DEPS
@@ -1,3 +1,5 @@
 include_rules = [
+  "+ash/public",
   "+components/sync",
+  "+components/full_restore",
 ]
diff --git a/components/desks_storage/core/desk_model.h b/components/desks_storage/core/desk_model.h
index 5e416b7d..f6e60be 100644
--- a/components/desks_storage/core/desk_model.h
+++ b/components/desks_storage/core/desk_model.h
@@ -12,11 +12,13 @@
 #include "base/observer_list.h"
 #include "base/time/time.h"
 
+namespace ash {
+class DeskTemplate;
+}
+
 namespace desks_storage {
 
 class DeskModelObserver;
-class DeskTemplate;
-
 // The DeskModel is an interface for accessing desk templates.
 // Actual desk template storage backend (e.g. local file system backend and Sync
 // backend) classes should implement this interface. Desk template accessor
@@ -35,6 +37,7 @@
     kOk,
     kFailure,
     kNotFound,
+    kInvalidUuid,
   };
 
   // Status codes for adding or updating a desk template.
@@ -63,7 +66,7 @@
 
   using GetEntryByUuidCallback =
       base::OnceCallback<void(GetEntryByUuidStatus status,
-                              std::unique_ptr<DeskTemplate>)>;
+                              std::unique_ptr<ash::DeskTemplate>)>;
   // Get a specific desk template by |uuid|. Actual storage backend does not
   // need to keep desk templates in memory. The storage backend could load the
   // specified desk template into memory and then call the |callback| with a
@@ -85,7 +88,7 @@
   // critical information, such as |uuid|, |callback| will be called with
   // |kInvalidArgument|. If the given desk template could not be persisted due
   // to any backend error, |callback| will be called with |kFailure|.
-  virtual void AddOrUpdateEntry(std::unique_ptr<DeskTemplate> new_entry,
+  virtual void AddOrUpdateEntry(std::unique_ptr<ash::DeskTemplate> new_entry,
                                 AddOrUpdateEntryCallback callback) = 0;
 
   using DeleteEntryCallback =
diff --git a/components/desks_storage/core/desk_model_observer.h b/components/desks_storage/core/desk_model_observer.h
index d2f0fb8e..243c166 100644
--- a/components/desks_storage/core/desk_model_observer.h
+++ b/components/desks_storage/core/desk_model_observer.h
@@ -8,9 +8,11 @@
 #include <string>
 #include <vector>
 
-namespace desks_storage {
-
+namespace ash {
 class DeskTemplate;
+}
+
+namespace desks_storage {
 
 // Observer for the Desk model. In the observer methods care should
 // be taken to not modify the model.
@@ -24,13 +26,13 @@
   // This is the mechanism for the sync server to push changes in the state of
   // the model to clients.
   virtual void EntriesAddedOrUpdatedRemotely(
-      const std::vector<const DeskTemplate*>& new_entries) = 0;
+      const std::vector<const ash::DeskTemplate*>& new_entries) = 0;
   virtual void EntriesRemovedRemotely(
       const std::vector<std::string>& uuids) = 0;
 
   // Invoked when desk templates are added/updated, removed locally.
   virtual void EntriesAddedOrUpdatedLocally(
-      const std::vector<const DeskTemplate*>& new_entries) = 0;
+      const std::vector<const ash::DeskTemplate*>& new_entries) = 0;
   virtual void EntriesRemovedLocally(const std::vector<std::string>& uuids) = 0;
 
  protected:
diff --git a/components/desks_storage/core/desk_sync_bridge.cc b/components/desks_storage/core/desk_sync_bridge.cc
index 8f89c46d..68ae772 100644
--- a/components/desks_storage/core/desk_sync_bridge.cc
+++ b/components/desks_storage/core/desk_sync_bridge.cc
@@ -6,14 +6,17 @@
 
 #include <algorithm>
 
+#include "ash/public/cpp/desk_template.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/check_op.h"
+#include "base/guid.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "components/desks_storage/core/desk_model_observer.h"
-#include "components/desks_storage/core/desk_template.h"
 #include "components/sync/model/entity_change.h"
 #include "components/sync/model/metadata_batch.h"
 #include "components/sync/model/metadata_change_list.h"
@@ -25,6 +28,8 @@
 
 namespace desks_storage {
 
+using ash::DeskTemplate;
+
 namespace {
 
 using syncer::ModelTypeStore;
@@ -35,6 +40,12 @@
       base::TimeDelta::FromMicroseconds(proto_t));
 }
 
+// Converts a time object to the format used in sync protobufs
+// (Microseconds since the Windows epoch).
+int64_t TimeToProtoTime(const base::Time& t) {
+  return t.ToDeltaSinceWindowsEpoch().InMicroseconds();
+}
+
 // Allocate a EntityData and copies |specifics| into it.
 std::unique_ptr<syncer::EntityData> CopyToEntityData(
     const sync_pb::WorkspaceDeskSpecifics& specifics) {
@@ -47,7 +58,7 @@
 
 // Parses the content of |record_list| into |*desk_templates|.
 absl::optional<syncer::ModelError> ParseDeskTemplatesOnBackendSequence(
-    std::map<std::string, std::unique_ptr<DeskTemplate>>* desk_templates,
+    std::map<base::GUID, std::unique_ptr<DeskTemplate>>* desk_templates,
     std::unique_ptr<ModelTypeStore::RecordList> record_list) {
   DCHECK(desk_templates);
   DCHECK(desk_templates->empty());
@@ -56,8 +67,22 @@
   for (const syncer::ModelTypeStore::Record& r : *record_list) {
     auto specifics = std::make_unique<sync_pb::WorkspaceDeskSpecifics>();
     if (specifics->ParseFromString(r.value)) {
-      (*desk_templates)[specifics->uuid()] =
-          DeskTemplate::FromProto(*specifics);
+      const base::GUID uuid =
+          base::GUID::ParseCaseInsensitive(specifics->uuid());
+      if (!uuid.is_valid()) {
+        return syncer::ModelError(
+            FROM_HERE,
+            base::StringPrintf("Failed to parse WorkspaceDeskSpecifics uuid %s",
+                               specifics->uuid().c_str()));
+      }
+
+      std::unique_ptr<ash::DeskTemplate> entry =
+          DeskSyncBridge::FromProto(*specifics);
+
+      if (!entry)
+        continue;
+
+      (*desk_templates)[uuid] = std::move(entry);
     } else {
       return syncer::ModelError(
           FROM_HERE, "Failed to deserialize WorkspaceDeskSpecifics.");
@@ -81,6 +106,34 @@
 
 DeskSyncBridge::~DeskSyncBridge() = default;
 
+// Static
+sync_pb::WorkspaceDeskSpecifics DeskSyncBridge::AsSyncProto(
+    const DeskTemplate* desk_template) {
+  sync_pb::WorkspaceDeskSpecifics pb_entry;
+
+  pb_entry.set_uuid(desk_template->uuid().AsLowercaseString());
+  pb_entry.set_name(base::UTF16ToUTF8(desk_template->template_name()));
+  pb_entry.set_created_time_usec(
+      TimeToProtoTime(desk_template->created_time()));
+
+  // TODO(yzd) copy other data fields
+  return pb_entry;
+}
+
+// Static
+std::unique_ptr<DeskTemplate> DeskSyncBridge::FromProto(
+    const sync_pb::WorkspaceDeskSpecifics& pb_entry) {
+  const std::string uuid(pb_entry.uuid());
+  if (uuid.empty() || !base::GUID::ParseCaseInsensitive(uuid).is_valid())
+    return nullptr;
+
+  const base::Time created_time = ProtoTimeToTime(pb_entry.created_time_usec());
+
+  // Protobuf parsing enforces utf8 encoding for all strings.
+  // TODO(yzd) copy other data fields
+  return std::make_unique<DeskTemplate>(uuid, pb_entry.name(), created_time);
+}
+
 std::unique_ptr<syncer::MetadataChangeList>
 DeskSyncBridge::CreateMetadataChangeList() {
   return ModelTypeStore::WriteBatch::CreateMetadataChangeList();
@@ -115,13 +168,19 @@
       store_->CreateWriteBatch();
 
   for (const std::unique_ptr<syncer::EntityChange>& change : entity_changes) {
-    const std::string& uuid = change->storage_key();
+    const base::GUID uuid =
+        base::GUID::ParseCaseInsensitive(change->storage_key());
+    if (!uuid.is_valid()) {
+      // Skip invalid storage keys.
+      continue;
+    }
+
     switch (change->type()) {
       case syncer::EntityChange::ACTION_DELETE: {
         if (entries_.find(uuid) != entries_.end()) {
           entries_.erase(uuid);
-          batch->DeleteData(uuid);
-          removed.push_back(uuid);
+          batch->DeleteData(uuid.AsLowercaseString());
+          removed.push_back(uuid.AsLowercaseString());
         }
         break;
       }
@@ -131,7 +190,7 @@
             change->data().specifics.workspace_desk();
 
         std::unique_ptr<DeskTemplate> remote_entry =
-            DeskTemplate::FromProto(specifics);
+            DeskSyncBridge::FromProto(specifics);
         if (!remote_entry) {
           // Skip invalid entries.
           continue;
@@ -139,14 +198,14 @@
 
         DCHECK_EQ(uuid, remote_entry->uuid());
         std::string serialized_remote_entry =
-            remote_entry->AsSyncProto().SerializeAsString();
+            DeskSyncBridge::AsSyncProto(remote_entry.get()).SerializeAsString();
 
         // Add/update the remote_entry to the model.
         entries_[uuid] = std::move(remote_entry);
         added_or_updated.push_back(GetEntryByUUID(uuid));
 
         // Write to the store.
-        batch->WriteData(uuid, serialized_remote_entry);
+        batch->WriteData(uuid.AsLowercaseString(), serialized_remote_entry);
         break;
       }
     }
@@ -166,12 +225,13 @@
   auto batch = std::make_unique<syncer::MutableDataBatch>();
 
   for (const std::string& uuid : storage_keys) {
-    const DeskTemplate* entry = GetEntryByUUID(uuid);
+    const DeskTemplate* entry =
+        GetEntryByUUID(base::GUID::ParseCaseInsensitive(uuid));
     if (!entry) {
       continue;
     }
 
-    batch->Put(uuid, CopyToEntityData(entry->AsSyncProto()));
+    batch->Put(uuid, CopyToEntityData(DeskSyncBridge::AsSyncProto(entry)));
   }
   std::move(callback).Run(std::move(batch));
 }
@@ -179,7 +239,8 @@
 void DeskSyncBridge::GetAllDataForDebugging(DataCallback callback) {
   auto batch = std::make_unique<syncer::MutableDataBatch>();
   for (const auto& it : entries_) {
-    batch->Put(it.first, CopyToEntityData(it.second->AsSyncProto()));
+    batch->Put(it.first.AsLowercaseString(),
+               CopyToEntityData(DeskSyncBridge::AsSyncProto(it.second.get())));
   }
   std::move(callback).Run(std::move(batch));
 }
@@ -203,7 +264,7 @@
   std::move(callback).Run(GetAllUuidsStatus::kOk, GetAllUuids());
 }
 
-void DeskSyncBridge::GetEntryByUUID(const std::string& uuid,
+void DeskSyncBridge::GetEntryByUUID(const std::string& uuid_str,
                                     GetEntryByUuidCallback callback) {
   if (!IsReady()) {
     std::move(callback).Run(GetEntryByUuidStatus::kFailure,
@@ -211,14 +272,21 @@
     return;
   }
 
+  const base::GUID uuid = base::GUID::ParseCaseInsensitive(uuid_str);
+  if (uuid.is_valid()) {
+    std::move(callback).Run(GetEntryByUuidStatus::kInvalidUuid,
+                            std::unique_ptr<DeskTemplate>());
+    return;
+  }
+
   auto it = entries_.find(uuid);
   if (it == entries_.end()) {
     std::move(callback).Run(GetEntryByUuidStatus::kNotFound,
                             std::unique_ptr<DeskTemplate>());
   } else {
-    std::move(callback).Run(
-        GetEntryByUuidStatus::kOk,
-        DeskTemplate::FromProto(it->second.get()->AsSyncProto()));
+    std::move(callback).Run(GetEntryByUuidStatus::kOk,
+                            DeskSyncBridge::FromProto(
+                                DeskSyncBridge::AsSyncProto(it->second.get())));
   }
 }
 
@@ -231,40 +299,38 @@
     return;
   }
 
-  std::string uuid = new_entry->uuid();
-  if (uuid.empty()) {
+  base::GUID uuid = new_entry->uuid();
+  if (!uuid.is_valid()) {
     std::move(callback).Run(AddOrUpdateEntryStatus::kInvalidArgument);
     return;
   }
 
-  std::string trimmed_name = "";
+  std::string trimmed_name = base::UTF16ToUTF8(
+      base::CollapseWhitespace(new_entry->template_name(), true));
 
-  if (base::IsStringUTF8(new_entry->name())) {
-    trimmed_name = base::CollapseWhitespaceASCII(new_entry->name(), false);
-  }
-
-  auto entry = std::make_unique<DeskTemplate>(uuid, trimmed_name,
-                                              new_entry->created_time());
+  auto entry = std::make_unique<DeskTemplate>(
+      uuid.AsLowercaseString(), trimmed_name, new_entry->created_time());
 
   std::unique_ptr<ModelTypeStore::WriteBatch> batch =
       store_->CreateWriteBatch();
   // Add/update this entry to the store and model.
-  auto entity_data = CopyToEntityData(entry->AsSyncProto());
+  auto entity_data = CopyToEntityData(DeskSyncBridge::AsSyncProto(entry.get()));
 
-  change_processor()->Put(uuid, std::move(entity_data),
+  change_processor()->Put(uuid.AsLowercaseString(), std::move(entity_data),
                           batch->GetMetadataChangeList());
 
   entries_[uuid] = std::move(entry);
   const DeskTemplate* result = GetEntryByUUID(uuid);
 
-  batch->WriteData(uuid, result->AsSyncProto().SerializeAsString());
+  batch->WriteData(uuid.AsLowercaseString(),
+                   DeskSyncBridge::AsSyncProto(result).SerializeAsString());
 
   Commit(std::move(batch));
 
   std::move(callback).Run(AddOrUpdateEntryStatus::kOk);
 }
 
-void DeskSyncBridge::DeleteEntry(const std::string& uuid,
+void DeskSyncBridge::DeleteEntry(const std::string& uuid_str,
                                  DeleteEntryCallback callback) {
   if (!IsReady()) {
     // This sync bridge has not finished initializing.
@@ -273,6 +339,8 @@
     return;
   }
 
+  const base::GUID uuid = base::GUID::ParseCaseInsensitive(uuid_str);
+
   if (GetEntryByUUID(uuid) == nullptr) {
     // Consider the deletion successful if the entry does not exist.
     std::move(callback).Run(DeleteEntryStatus::kOk);
@@ -282,11 +350,12 @@
   std::unique_ptr<ModelTypeStore::WriteBatch> batch =
       store_->CreateWriteBatch();
 
-  change_processor()->Delete(uuid, batch->GetMetadataChangeList());
+  change_processor()->Delete(uuid.AsLowercaseString(),
+                             batch->GetMetadataChangeList());
 
   entries_.erase(uuid);
 
-  batch->DeleteData(uuid);
+  batch->DeleteData(uuid.AsLowercaseString());
 
   Commit(std::move(batch));
 
@@ -330,13 +399,13 @@
   std::vector<std::string> keys;
   for (const auto& it : entries_) {
     DCHECK_EQ(it.first, it.second->uuid());
-    keys.push_back(it.first);
+    keys.push_back(it.first.AsLowercaseString());
   }
   return keys;
 }
 
 const DeskTemplate* DeskSyncBridge::GetEntryByUUID(
-    const std::string& uuid) const {
+    const base::GUID& uuid) const {
   auto it = entries_.find(uuid);
   if (it == entries_.end())
     return nullptr;
@@ -428,7 +497,7 @@
 void DeskSyncBridge::UploadLocalOnlyData(
     syncer::MetadataChangeList* metadata_change_list,
     const syncer::EntityChangeList& entity_data) {
-  std::set<std::string> local_keys_to_upload;
+  std::set<base::GUID> local_keys_to_upload;
   for (const auto& it : entries_) {
     local_keys_to_upload.insert(it.first);
   }
@@ -436,14 +505,15 @@
   // Strip |local_keys_to_upload| of any key (UUID) that is already known to the
   // server.
   for (const std::unique_ptr<syncer::EntityChange>& change : entity_data) {
-    local_keys_to_upload.erase(change->storage_key());
+    local_keys_to_upload.erase(
+        base::GUID::ParseCaseInsensitive(change->storage_key()));
   }
 
   // Upload the local-only templates.
-  for (const std::string& storage_key : local_keys_to_upload) {
-    change_processor()->Put(
-        storage_key, CopyToEntityData(entries_[storage_key]->AsSyncProto()),
-        metadata_change_list);
+  for (const base::GUID& uuid : local_keys_to_upload) {
+    change_processor()->Put(uuid.AsLowercaseString(),
+                            CopyToEntityData(AsSyncProto(entries_[uuid].get())),
+                            metadata_change_list);
   }
 }
 
diff --git a/components/desks_storage/core/desk_sync_bridge.h b/components/desks_storage/core/desk_sync_bridge.h
index f9d4490..f834c43 100644
--- a/components/desks_storage/core/desk_sync_bridge.h
+++ b/components/desks_storage/core/desk_sync_bridge.h
@@ -9,6 +9,7 @@
 #include <string>
 #include <vector>
 
+#include "base/guid.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observation.h"
 #include "base/time/time.h"
@@ -21,9 +22,15 @@
 class ModelTypeChangeProcessor;
 }  // namespace syncer
 
-namespace desks_storage {
+namespace sync_pb {
+class WorkspaceDeskSpecifics;
+}  // namespace sync_pb
 
+namespace ash {
 class DeskTemplate;
+}  // namespace ash
+
+namespace desks_storage {
 
 // A Sync-backed persistence layer for Workspace Desk.
 class DeskSyncBridge : public syncer::ModelTypeSyncBridge, public DeskModel {
@@ -35,6 +42,12 @@
   DeskSyncBridge& operator=(const DeskSyncBridge&) = delete;
   ~DeskSyncBridge() override;
 
+  // Converts an ash::DeskTemplate to its corresponding WorkspaceDesk proto.
+  static sync_pb::WorkspaceDeskSpecifics AsSyncProto(
+      const ash::DeskTemplate* desk_template);
+  static std::unique_ptr<ash::DeskTemplate> FromProto(
+      const sync_pb::WorkspaceDeskSpecifics& pb_entry);
+
   // syncer::ModelTypeSyncBridge overrides.
   std::unique_ptr<syncer::MetadataChangeList> CreateMetadataChangeList()
       override;
@@ -53,7 +66,7 @@
   void GetAllUuids(GetAllUuidsCallback callback) override;
   void GetEntryByUUID(const std::string& uuid,
                       GetEntryByUuidCallback callback) override;
-  void AddOrUpdateEntry(std::unique_ptr<DeskTemplate> new_entry,
+  void AddOrUpdateEntry(std::unique_ptr<ash::DeskTemplate> new_entry,
                         AddOrUpdateEntryCallback callback) override;
   void DeleteEntry(const std::string& uuid,
                    DeleteEntryCallback callback) override;
@@ -70,16 +83,15 @@
   // for Workspace Desk model type.
   bool IsSyncing() const;
   std::vector<std::string> GetAllUuids() const;
-  const DeskTemplate* GetEntryByUUID(const std::string& uuid) const;
+  const ash::DeskTemplate* GetEntryByUUID(const base::GUID& uuid) const;
 
  private:
-  // TODO(yzd) Refactor template keys to be base::GUID.
-  using DeskEntries = std::map<std::string, std::unique_ptr<DeskTemplate>>;
+  using DeskEntries = std::map<base::GUID, std::unique_ptr<ash::DeskTemplate>>;
 
   // Notify all observers of any |new_entries| when they are added/updated via
   // sync.
   void NotifyRemoteDeskTemplateAddedOrUpdated(
-      const std::vector<const DeskTemplate*>& new_entries);
+      const std::vector<const ash::DeskTemplate*>& new_entries);
 
   // Notify all observers when the entries with |uuids| have been removed via
   // sync or disabling sync locally.
diff --git a/components/desks_storage/core/desk_sync_bridge_unittest.cc b/components/desks_storage/core/desk_sync_bridge_unittest.cc
index a7d177d..c4b9c77 100644
--- a/components/desks_storage/core/desk_sync_bridge_unittest.cc
+++ b/components/desks_storage/core/desk_sync_bridge_unittest.cc
@@ -8,13 +8,15 @@
 #include <set>
 #include <utility>
 
+#include "ash/public/cpp/desk_template.h"
 #include "base/bind.h"
+#include "base/guid.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/test/simple_test_clock.h"
 #include "base/test/task_environment.h"
 #include "components/desks_storage/core/desk_model_observer.h"
-#include "components/desks_storage/core/desk_template.h"
 #include "components/sync/engine/entity_data.h"
 #include "components/sync/model/entity_change.h"
 #include "components/sync/model/in_memory_metadata_change_list.h"
@@ -30,6 +32,7 @@
 
 namespace {
 
+using ash::DeskTemplate;
 using sync_pb::ModelTypeState;
 using sync_pb::WorkspaceDeskSpecifics;
 using syncer::EntityChange;
@@ -48,8 +51,12 @@
 using testing::SizeIs;
 using testing::StrEq;
 
-const char kUuidFormat[] = "uuid %d";
-const char kNameFormat[] = "template %d";
+constexpr char kUuidFormat[] = "9e186d5a-502e-49ce-9ee1-00000000000%d";
+constexpr char kNameFormat[] = "template %d";
+const base::GUID kTestUuid1 =
+    base::GUID::ParseCaseInsensitive(base::StringPrintf(kUuidFormat, 1));
+const base::GUID kTestUuid2 =
+    base::GUID::ParseCaseInsensitive(base::StringPrintf(kUuidFormat, 2));
 
 WorkspaceDeskSpecifics CreateWorkspaceDeskSpecifics(
     int templateIndex,
@@ -90,16 +97,16 @@
  protected:
   static void VerifyAddOrUpdateEntrySuccess(
       DeskModel::AddOrUpdateEntryStatus status) {
-    EXPECT_EQ(status, DeskModel::AddOrUpdateEntryStatus::kOk);
+    EXPECT_EQ(status, DeskSyncBridge::AddOrUpdateEntryStatus::kOk);
   }
 
   static void VerifyAddOrUpdateEntryFailure(
       DeskModel::AddOrUpdateEntryStatus status) {
-    EXPECT_EQ(status, DeskModel::AddOrUpdateEntryStatus::kFailure);
+    EXPECT_EQ(status, DeskSyncBridge::AddOrUpdateEntryStatus::kFailure);
   }
 
   static void VerifyDeleteEntrySuccess(DeskModel::DeleteEntryStatus status) {
-    EXPECT_EQ(status, DeskModel::DeleteEntryStatus::kOk);
+    EXPECT_EQ(status, DeskSyncBridge::DeleteEntryStatus::kOk);
   }
 
   DeskSyncBridgeTest()
@@ -169,7 +176,7 @@
   }
 
   EntityData MakeEntityData(const DeskTemplate& desk_template) {
-    return MakeEntityData(desk_template.AsSyncProto());
+    return MakeEntityData(DeskSyncBridge::AsSyncProto(&desk_template));
   }
 
   // Helper method to reduce duplicated code between tests. Wraps the given
@@ -193,12 +200,12 @@
 
   void AddTwoTemplates() {
     bridge_->AddOrUpdateEntry(
-        std::make_unique<DeskTemplate>("uuid 1", "template 1",
-                                       AdvanceAndGetTime()),
+        std::make_unique<DeskTemplate>(kTestUuid1.AsLowercaseString(),
+                                       "template 1", AdvanceAndGetTime()),
         base::BindOnce(DeskSyncBridgeTest::VerifyAddOrUpdateEntrySuccess));
     bridge_->AddOrUpdateEntry(
-        std::make_unique<DeskTemplate>("uuid 2", "template 2",
-                                       AdvanceAndGetTime()),
+        std::make_unique<DeskTemplate>(kTestUuid2.AsLowercaseString(),
+                                       "template 2", AdvanceAndGetTime()),
         base::BindOnce(DeskSyncBridgeTest::VerifyAddOrUpdateEntrySuccess));
   }
 
@@ -256,15 +263,15 @@
   EXPECT_EQ(2ul, bridge()->GetAllUuids().size());
 
   // Verify both local specifics are loaded correctly.
-  EXPECT_EQ(bridge()
-                ->GetEntryByUUID(template1.uuid())
-                ->AsSyncProto()
+  EXPECT_EQ(DeskSyncBridge::AsSyncProto(
+                bridge()->GetEntryByUUID(
+                    base::GUID::ParseCaseInsensitive(template1.uuid())))
                 .SerializeAsString(),
             template1.SerializeAsString());
 
-  EXPECT_EQ(bridge()
-                ->GetEntryByUUID(template2.uuid())
-                ->AsSyncProto()
+  EXPECT_EQ(DeskSyncBridge::AsSyncProto(
+                bridge()->GetEntryByUUID(
+                    base::GUID::ParseCaseInsensitive(template2.uuid())))
                 .SerializeAsString(),
             template2.SerializeAsString());
 }
@@ -292,8 +299,8 @@
   // Add entry should fail when the sync bridge is not ready.
   EXPECT_CALL(*processor(), Put(_, _, _)).Times(1);
   bridge()->AddOrUpdateEntry(
-      std::make_unique<DeskTemplate>("uuid 1", "template 1",
-                                     AdvanceAndGetTime()),
+      std::make_unique<DeskTemplate>(kTestUuid1.AsLowercaseString(),
+                                     "template 1", AdvanceAndGetTime()),
       base::BindOnce(DeskSyncBridgeTest::VerifyAddOrUpdateEntrySuccess));
 }
 
@@ -307,8 +314,8 @@
   // Add entry should fail when the sync bridge is not ready.
   EXPECT_CALL(*processor(), Put(_, _, _)).Times(0);
   bridge()->AddOrUpdateEntry(
-      std::make_unique<DeskTemplate>("uuid 1", "template 1",
-                                     AdvanceAndGetTime()),
+      std::make_unique<DeskTemplate>(kTestUuid1.AsLowercaseString(),
+                                     "template 1", AdvanceAndGetTime()),
       base::BindOnce(DeskSyncBridgeTest::VerifyAddOrUpdateEntryFailure));
 }
 
@@ -329,17 +336,21 @@
   // Update template 1
   EXPECT_CALL(*processor(), Put(_, _, _)).Times(1);
   bridge()->AddOrUpdateEntry(
-      std::make_unique<DeskTemplate>("uuid 1", "updated template 1",
-                                     AdvanceAndGetTime()),
+      std::make_unique<DeskTemplate>(kTestUuid1.AsLowercaseString(),
+                                     "updated template 1", AdvanceAndGetTime()),
       base::BindOnce(DeskSyncBridgeTest::VerifyAddOrUpdateEntrySuccess));
 
   // We should still have both templates.
   EXPECT_EQ(2ul, bridge()->GetAllUuids().size());
   // Template 1 should be updated.
-  EXPECT_EQ(bridge()->GetEntryByUUID("uuid 1")->name(), "updated template 1");
+  EXPECT_EQ(
+      base::UTF16ToUTF8(bridge()->GetEntryByUUID(kTestUuid1)->template_name()),
+      "updated template 1");
 
   // Template 2 should be unchanged.
-  EXPECT_EQ(bridge()->GetEntryByUUID("uuid 2")->name(), "template 2");
+  EXPECT_EQ(
+      base::UTF16ToUTF8(bridge()->GetEntryByUUID(kTestUuid2)->template_name()),
+      "template 2");
 }
 
 TEST_F(DeskSyncBridgeTest, DeleteEntryLocally) {
@@ -358,12 +369,15 @@
 
   // Delete template 1.
   bridge()->DeleteEntry(
-      "uuid 1", base::BindOnce(DeskSyncBridgeTest::VerifyDeleteEntrySuccess));
+      kTestUuid1.AsLowercaseString(),
+      base::BindOnce(DeskSyncBridgeTest::VerifyDeleteEntrySuccess));
 
   // We should have only 1 template.
   EXPECT_EQ(1ul, bridge()->GetAllUuids().size());
   // Template 2 should be unchanged.
-  EXPECT_EQ(bridge()->GetEntryByUUID("uuid 2")->name(), "template 2");
+  EXPECT_EQ(
+      base::UTF16ToUTF8(bridge()->GetEntryByUUID(kTestUuid2)->template_name()),
+      "template 2");
 }
 
 TEST_F(DeskSyncBridgeTest, DeleteAllEntriesLocally) {
@@ -441,14 +455,14 @@
   // We should still have both templates.
   EXPECT_EQ(2ul, bridge()->GetAllUuids().size());
   // Template 1 should be updated to new content.
-  EXPECT_EQ(bridge()
-                ->GetEntryByUUID(template1.uuid())
-                ->AsSyncProto()
+  EXPECT_EQ(DeskSyncBridge::AsSyncProto(
+                bridge()->GetEntryByUUID(
+                    base::GUID::ParseCaseInsensitive(template1.uuid())))
                 .SerializeAsString(),
             updated_template1.SerializeAsString());
-  EXPECT_EQ(bridge()
-                ->GetEntryByUUID(template2.uuid())
-                ->AsSyncProto()
+  EXPECT_EQ(DeskSyncBridge::AsSyncProto(
+                bridge()->GetEntryByUUID(
+                    base::GUID::ParseCaseInsensitive(template2.uuid())))
                 .SerializeAsString(),
             template2.SerializeAsString());
 }
@@ -477,9 +491,9 @@
 
   // Verify that we only have template 2.
   EXPECT_EQ(1ul, bridge()->GetAllUuids().size());
-  EXPECT_EQ(bridge()
-                ->GetEntryByUUID(template2.uuid())
-                ->AsSyncProto()
+  EXPECT_EQ(DeskSyncBridge::AsSyncProto(
+                bridge()->GetEntryByUUID(
+                    base::GUID::ParseCaseInsensitive(template2.uuid())))
                 .SerializeAsString(),
             template2.SerializeAsString());
 }
@@ -517,21 +531,22 @@
   InitializeBridge();
 
   // Seed two templates.
-  // Seeded templates will be "uuid 1" and "uuid 2".
+  // Seeded templates will be "template 1" and "template 2".
   AddTwoTemplates();
 
   // We should have seeded two templates.
   EXPECT_EQ(2ul, bridge()->GetAllUuids().size());
 
-  // Create server-side templates "uuid 2" and "uuid 3".
+  // Create server-side templates "template 2" and "template 3".
   const WorkspaceDeskSpecifics template1 = CreateWorkspaceDeskSpecifics(2);
   const WorkspaceDeskSpecifics template2 = CreateWorkspaceDeskSpecifics(3);
 
   auto metadata_change_list = std::make_unique<InMemoryMetadataChangeList>();
   EXPECT_CALL(*mock_observer(), EntriesAddedOrUpdatedRemotely(SizeIs(2)));
 
-  // MergeSyncData should upload the local-only template "uuid 1".
-  EXPECT_CALL(*processor(), Put(StrEq("uuid 1"), _, _)).Times(1);
+  // MergeSyncData should upload the local-only template "template 1".
+  EXPECT_CALL(*processor(), Put(StrEq(kTestUuid1.AsLowercaseString()), _, _))
+      .Times(1);
 
   bridge()->MergeSyncData(std::move(metadata_change_list),
                           EntityAddList({template1, template2}));
diff --git a/components/desks_storage/core/desk_template.h b/components/desks_storage/core/desk_template.h
index 69096db..4bc8b56 100644
--- a/components/desks_storage/core/desk_template.h
+++ b/components/desks_storage/core/desk_template.h
@@ -19,8 +19,7 @@
 // template. This class is a temporary placeholder. This could be replaced
 // by future ash::DeskTemplate when it is ready.
 //
-// NOTE: This definition will be deleted in an upcoming CL to be replaced by
-// ash::DeskTemplate.
+// TODO(crbug/1225727): remove this class.
 class DeskTemplate {
  public:
   // Creates a DeskTemplate from the protobuf format.
diff --git a/components/desks_storage/core/local_desk_data_manager.cc b/components/desks_storage/core/local_desk_data_manager.cc
index 799e030..ce95c7b9 100644
--- a/components/desks_storage/core/local_desk_data_manager.cc
+++ b/components/desks_storage/core/local_desk_data_manager.cc
@@ -4,20 +4,87 @@
 
 #include "components/desks_storage/core/local_desk_data_manager.h"
 
+#include "ash/public/cpp/desk_template.h"
 #include "base/files/dir_reader_posix.h"
 #include "base/files/file_util.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/logging.h"
 #include "base/task/post_task.h"
 #include "base/task/thread_pool.h"
 #include "base/threading/scoped_blocking_call.h"
+#include "base/util/values/values_util.h"
+#include "base/values.h"
 #include "components/desks_storage/core/desk_model.h"
 #include "components/desks_storage/core/desk_template.h"
+#include "components/full_restore/restore_data.h"
 #include "components/sync/protocol/workspace_desk_specifics.pb.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "url/gurl.h"
 
 namespace desks_storage {
 
 namespace {
 
+// File extension for templates.
 constexpr char kFileExtension[] = ".template";
+// Key used in base::Value generation for the template name field.
+constexpr char kDeskTemplateNameKey[] = "template_name";
+// Key used in base::Value generation for the uuid field.
+constexpr char kDeskTemplateUuidKey[] = "uuid";
+// Key used in base::Value generation for the time created field.
+constexpr char kDeskTemplateTimeCreatedKey[] = "time_created";
+// Key used in base::Value generation for the restore data field.
+constexpr char kDeskTemplateRestoreDataKey[] = "restore_data";
+
+// Function for converting ash::DeskTemplates to base::Value for serialization.
+base::Value ConvertDeskTemplateToValue(ash::DeskTemplate* desk_template) {
+  base::Value dict(base::Value::Type::DICTIONARY);
+  dict.SetKey(kDeskTemplateUuidKey,
+              base::Value(desk_template->uuid().AsLowercaseString()));
+  dict.SetKey(kDeskTemplateNameKey,
+              base::Value(desk_template->template_name()));
+  dict.SetKey(kDeskTemplateTimeCreatedKey,
+              util::TimeToValue(desk_template->created_time()));
+  DCHECK(desk_template->desk_restore_data() != nullptr);
+  dict.SetKey(kDeskTemplateRestoreDataKey,
+              desk_template->desk_restore_data()->ConvertToValue());
+  return dict;
+}
+
+// Function for converting base::Values deserialized from template files as
+// ash::DeskTemplates.
+std::unique_ptr<ash::DeskTemplate> ConvertDeskTemplateValueToDeskTemplate(
+    base::Value& desk_template_value) {
+  absl::optional<base::Time> created_time(util::ValueToTime(
+      desk_template_value.FindKey(kDeskTemplateTimeCreatedKey)));
+  if (!created_time)
+    return nullptr;
+
+  std::string* uuid = desk_template_value.FindStringKey(kDeskTemplateUuidKey);
+  if (!uuid)
+    return nullptr;
+
+  std::string* name = desk_template_value.FindStringKey(kDeskTemplateNameKey);
+  if (!name)
+    return nullptr;
+
+  std::unique_ptr<ash::DeskTemplate> converted_value =
+      std::make_unique<ash::DeskTemplate>(*uuid, *name, created_time.value());
+
+  // Full Restore will only take in std::unique_ptr as it's constructor
+  // parameter from base::Value.  We're not allowed to use the explicit
+  // std::unique_ptr constructor so this is how we wrap the base::Value in a
+  // std::unique_ptr
+  std::unique_ptr<base::Value> restore_data_value_ptr =
+      base::Value::ToUniquePtrValue(
+          std::move(*desk_template_value.FindKey(kDeskTemplateRestoreDataKey)));
+  DCHECK(restore_data_value_ptr);
+
+  converted_value->set_desk_restore_data(
+      std::make_unique<full_restore::RestoreData>(
+          std::move(restore_data_value_ptr)));
+  return converted_value;
+}
 
 // WriteTemplateToFile is a method that takes a base::FilePath
 // |path_to_template| and a DeskTemplate unique pointer |entry|
@@ -28,17 +95,14 @@
 // and assumes that it is being called from a thread which can accept
 // such calls, please don't call this function from the main thread.
 bool WriteTemplateFile(const base::FilePath& path_to_template,
-                       std::unique_ptr<DeskTemplate> entry) {
-  std::string proto_string;
-  bool string_conversion_success =
-      entry->AsSyncProto().SerializeToString(&proto_string);
-
-  if (!string_conversion_success)
-    return false;
+                       std::unique_ptr<ash::DeskTemplate> entry) {
+  std::string json_string;
+  JSONStringValueSerializer serializer(&json_string);
+  serializer.Serialize(ConvertDeskTemplateToValue(entry.get()));
 
   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                 base::BlockingType::MAY_BLOCK);
-  bool write_success = base::WriteFile(path_to_template, proto_string);
+  bool write_success = base::WriteFile(path_to_template, json_string);
 
   if (!write_success)
     return false;
@@ -60,10 +124,10 @@
   out_uuids->push_back(entry.substr(0, extension_at));
 }
 
-// returns the fully qualified path to a template file given the file path to
+// Returns the fully qualified path to a template file given the file path to
 // the desk template directory.
 base::FilePath GetFullyQualifiedPath(base::FilePath file_path,
-                                     std::string uuid) {
+                                     const std::string& uuid) {
   std::string filename(uuid);
   filename.append(kFileExtension);
   return base::FilePath(
@@ -106,9 +170,9 @@
 // in order to complete io operations.
 DeskModel::AddOrUpdateEntryStatus AddOrUpdateEntryTask(
     const base::FilePath local_template_path,
-    std::unique_ptr<DeskTemplate> new_entry) {
-  const base::FilePath fully_qualified_path =
-      GetFullyQualifiedPath(local_template_path, new_entry->uuid());
+    std::unique_ptr<ash::DeskTemplate> new_entry) {
+  const base::FilePath fully_qualified_path = GetFullyQualifiedPath(
+      local_template_path, new_entry->uuid().AsLowercaseString());
 
   if (WriteTemplateFile(fully_qualified_path, std::move(new_entry)))
     return DeskModel::AddOrUpdateEntryStatus::kOk;
@@ -118,7 +182,7 @@
 
 struct GetEntryByUuidResult {
   DeskModel::GetEntryByUuidStatus status;
-  std::unique_ptr<DeskTemplate> desk_template;
+  std::unique_ptr<ash::DeskTemplate> desk_template;
 };
 
 // This method Handles getting the task of getting an entry by it's Uuid. Unlike
@@ -136,21 +200,26 @@
   if (!base::PathExists(fully_qualified_path))
     return {DeskModel::GetEntryByUuidStatus::kNotFound, nullptr};
 
-  std::string proto_string;
+  std::string value_string;
   bool read_success =
-      base::ReadFileToString(fully_qualified_path, &proto_string);
-
+      base::ReadFileToString(fully_qualified_path, &value_string);
   if (!read_success)
     return {DeskModel::GetEntryByUuidStatus::kFailure, nullptr};
 
-  sync_pb::WorkspaceDeskSpecifics desk_proto;
-  bool parse_success = desk_proto.ParseFromString(proto_string);
+  std::string error_message;
+  int error_code;
+  JSONStringValueDeserializer deserializer(value_string);
+  auto desk_template_value =
+      deserializer.Deserialize(&error_code, &error_message);
 
-  if (!parse_success)
+  if (!desk_template_value) {
+    DVLOG(0) << "Fail to deserialize json value from string with error code: "
+             << error_code << " and error message: " << error_message;
     return {DeskModel::GetEntryByUuidStatus::kFailure, nullptr};
+  }
 
   return {DeskModel::GetEntryByUuidStatus::kOk,
-          DeskTemplate::FromProto(desk_proto)};
+          ConvertDeskTemplateValueToDeskTemplate(*desk_template_value)};
 }
 
 // Handles replies from |GetEntryByUuidTask| and calls callback.
@@ -217,7 +286,7 @@
 LocalDeskDataManager::~LocalDeskDataManager() = default;
 
 void LocalDeskDataManager::AddOrUpdateEntry(
-    std::unique_ptr<DeskTemplate> new_entry,
+    std::unique_ptr<ash::DeskTemplate> new_entry,
     DeskModel::AddOrUpdateEntryCallback callback) {
   task_runner_->PostTaskAndReplyWithResult(
       FROM_HERE,
diff --git a/components/desks_storage/core/local_desk_data_manager.h b/components/desks_storage/core/local_desk_data_manager.h
index e6429b05..9aa0f61 100644
--- a/components/desks_storage/core/local_desk_data_manager.h
+++ b/components/desks_storage/core/local_desk_data_manager.h
@@ -14,13 +14,17 @@
 #include "base/sequenced_task_runner_helpers.h"
 #include "components/desks_storage/core/desk_model.h"
 
-namespace desks_storage {
-
+namespace ash {
 class DeskTemplate;
+}
+
+namespace desks_storage {
 
 // The LocalDeskDataManager is the local storage implementation of
 // the DeskModel interface and handles storage operations for local
 // desk templates.
+//
+// TODO(crbug: 1227215): add calls to DeskModelObserver
 class LocalDeskDataManager : public DeskModel {
  public:
   explicit LocalDeskDataManager(const base::FilePath& path);
@@ -34,7 +38,7 @@
   void DeleteAllEntries(DeleteEntryCallback callback) override;
   void GetEntryByUUID(const std::string& uuid,
                       GetEntryByUuidCallback callback) override;
-  void AddOrUpdateEntry(std::unique_ptr<DeskTemplate> new_entry,
+  void AddOrUpdateEntry(std::unique_ptr<ash::DeskTemplate> new_entry,
                         AddOrUpdateEntryCallback callback) override;
   void DeleteEntry(const std::string& uuid,
                    DeleteEntryCallback callback) override;
diff --git a/components/desks_storage/core/local_desks_data_manager_unittests.cc b/components/desks_storage/core/local_desks_data_manager_unittests.cc
index aecf5b94..6a9d6b8 100644
--- a/components/desks_storage/core/local_desks_data_manager_unittests.cc
+++ b/components/desks_storage/core/local_desks_data_manager_unittests.cc
@@ -6,12 +6,16 @@
 
 #include <string>
 
+#include "ash/public/cpp/desk_template.h"
 #include "base/files/file_path.h"
+#include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
 #include "base/test/bind.h"
 #include "base/test/task_environment.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
@@ -22,6 +26,9 @@
 
 namespace {
 
+constexpr char kJunkFileName[] = "01.template";
+constexpr char kJunkData[] = "dsjadsueAUWLKD293958";
+
 // Search |uuid_list| for |uuid_query| returns true if found false if not.
 //
 // we don't know what order the dir_reader will read the files back to us so
@@ -45,27 +52,44 @@
   EXPECT_EQ(status, DeskModel::AddOrUpdateEntryStatus::kOk);
 }
 
+void WriteJunkData(const base::FilePath& temp_dir) {
+  base::FilePath full_path = temp_dir.Append(std::string(kJunkFileName));
+
+  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
+                                                base::BlockingType::MAY_BLOCK);
+  EXPECT_TRUE(base::WriteFile(full_path, kJunkData));
+}
+
 }  // namespace
 
 class LocalDeskDataManagerTest : public testing::Test {
  public:
   LocalDeskDataManagerTest()
       : sample_desk_template_one_(
-            std::make_unique<DeskTemplate>(std::string("01"),
-                                           std::string("desk_01"),
-                                           base::Time())),
+            std::make_unique<ash::DeskTemplate>(std::string("01"),
+                                                std::string("desk_01"),
+                                                base::Time::Now())),
         sample_desk_template_two_(
-            std::make_unique<DeskTemplate>(std::string("02"),
-                                           std::string("desk_02"),
-                                           base::Time())),
+            std::make_unique<ash::DeskTemplate>(std::string("02"),
+                                                std::string("desk_02"),
+                                                base::Time::Now())),
         sample_desk_template_three_(
-            std::make_unique<DeskTemplate>(std::string("03"),
-                                           std::string("desk_03"),
-                                           base::Time())),
+            std::make_unique<ash::DeskTemplate>(std::string("03"),
+                                                std::string("desk_03"),
+                                                base::Time::Now())),
         modified_sample_desk_template_one_(
-            std::make_unique<DeskTemplate>(std::string("01"),
-                                           std::string("desk_01_mod"),
-                                           base::Time())) {}
+            std::make_unique<ash::DeskTemplate>(std::string("01"),
+                                                std::string("desk_01_mod"),
+                                                base::Time::Now())) {
+    sample_desk_template_one_->set_desk_restore_data(
+        std::make_unique<full_restore::RestoreData>());
+    sample_desk_template_two_->set_desk_restore_data(
+        std::make_unique<full_restore::RestoreData>());
+    sample_desk_template_three_->set_desk_restore_data(
+        std::make_unique<full_restore::RestoreData>());
+    modified_sample_desk_template_one_->set_desk_restore_data(
+        std::make_unique<full_restore::RestoreData>());
+  }
 
   LocalDeskDataManagerTest(const LocalDeskDataManagerTest&) = delete;
   LocalDeskDataManagerTest& operator=(const LocalDeskDataManagerTest&) = delete;
@@ -78,10 +102,10 @@
   }
 
   base::ScopedTempDir temp_dir_;
-  std::unique_ptr<DeskTemplate> sample_desk_template_one_;
-  std::unique_ptr<DeskTemplate> sample_desk_template_two_;
-  std::unique_ptr<DeskTemplate> sample_desk_template_three_;
-  std::unique_ptr<DeskTemplate> modified_sample_desk_template_one_;
+  std::unique_ptr<ash::DeskTemplate> sample_desk_template_one_;
+  std::unique_ptr<ash::DeskTemplate> sample_desk_template_two_;
+  std::unique_ptr<ash::DeskTemplate> sample_desk_template_three_;
+  std::unique_ptr<ash::DeskTemplate> modified_sample_desk_template_one_;
 };
 
 TEST_F(LocalDeskDataManagerTest, CanAddEntry) {
@@ -139,11 +163,13 @@
       std::string("01"),
       base::BindLambdaForTesting(
           [](DeskModel::GetEntryByUuidStatus status,
-             std::unique_ptr<DeskTemplate> result_template) {
+             std::unique_ptr<ash::DeskTemplate> result_template) {
             EXPECT_EQ(DeskModel::GetEntryByUuidStatus::kOk, status);
 
-            EXPECT_EQ(result_template->uuid(), std::string("01"));
-            EXPECT_EQ(result_template->name(), std::string("desk_01"));
+            EXPECT_EQ(result_template->uuid(),
+                      base::GUID::ParseCaseInsensitive(std::string("01")));
+            EXPECT_EQ(result_template->template_name(),
+                      base::UTF8ToUTF16(std::string("desk_01")));
             EXPECT_EQ(result_template->created_time(), base::Time());
           }));
 }
@@ -157,11 +183,29 @@
   data_manager.GetEntryByUUID(
       std::string("01"),
       base::BindLambdaForTesting([](DeskModel::GetEntryByUuidStatus status,
-                                    std::unique_ptr<DeskTemplate> _) {
+                                    std::unique_ptr<ash::DeskTemplate> _) {
         EXPECT_EQ(DeskModel::GetEntryByUuidStatus::kNotFound, status);
       }));
 }
 
+TEST_F(LocalDeskDataManagerTest, GetEntryByUuidFailsIfEntryHasBadData) {
+  base::test::TaskEnvironment task_environment(
+      base::test::TaskEnvironment::MainThreadType::IO);
+
+  auto task_runner = task_environment.GetMainThreadTaskRunner();
+  task_runner->PostTask(FROM_HERE,
+                        base::BindOnce(&WriteJunkData, temp_dir_.GetPath()));
+
+  LocalDeskDataManager data_manager(temp_dir_.GetPath());
+
+  data_manager.GetEntryByUUID(
+      std::string("01"),
+      base::BindLambdaForTesting([](DeskModel::GetEntryByUuidStatus status,
+                                    std::unique_ptr<ash::DeskTemplate> _) {
+        EXPECT_EQ(DeskModel::GetEntryByUuidStatus::kFailure, status);
+      }));
+}
+
 TEST_F(LocalDeskDataManagerTest, CanUpdateEntry) {
   base::test::TaskEnvironment task_environment(
       base::test::TaskEnvironment::MainThreadType::IO);
@@ -178,11 +222,13 @@
       std::string("01"),
       base::BindLambdaForTesting(
           [](DeskModel::GetEntryByUuidStatus status,
-             std::unique_ptr<DeskTemplate> result_template) {
+             std::unique_ptr<ash::DeskTemplate> result_template) {
             EXPECT_EQ(DeskModel::GetEntryByUuidStatus::kOk, status);
 
-            EXPECT_EQ(result_template->uuid(), std::string("01"));
-            EXPECT_EQ(result_template->name(), std::string("desk_01_mod"));
+            EXPECT_EQ(result_template->uuid(),
+                      base::GUID::ParseCaseInsensitive(std::string("01")));
+            EXPECT_EQ(result_template->template_name(),
+                      base::UTF8ToUTF16(std::string("desk_01_mod")));
             EXPECT_EQ(result_template->created_time(), base::Time());
           }));
 }
diff --git a/components/heap_profiling/in_process/heap_profiler_controller_unittest.cc b/components/heap_profiling/in_process/heap_profiler_controller_unittest.cc
index eb4c10d..9401e25 100644
--- a/components/heap_profiling/in_process/heap_profiler_controller_unittest.cc
+++ b/components/heap_profiling/in_process/heap_profiler_controller_unittest.cc
@@ -14,20 +14,13 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/metrics_proto/sampled_profile.pb.h"
 
-// TODO(crbug.com/961073): Fix memory leaks in tests and re-enable on LSAN.
-#ifdef LEAK_SANITIZER
-#define MAYBE_EmptyProfileIsNotEmitted DISABLED_EmptyProfileIsNotEmitted
-#else
-#define MAYBE_EmptyProfileIsNotEmitted EmptyProfileIsNotEmitted
-#endif
-
 class HeapProfilerControllerTest : public testing::Test {
  protected:
   base::test::TaskEnvironment task_environment{
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
 };
 
-TEST_F(HeapProfilerControllerTest, MAYBE_EmptyProfileIsNotEmitted) {
+TEST_F(HeapProfilerControllerTest, EmptyProfileIsNotEmitted) {
   HeapProfilerController controller;
   metrics::CallStackProfileBuilder::SetBrowserProcessReceiverCallback(
       base::BindLambdaForTesting(
diff --git a/components/history/core/browser/expire_history_backend_unittest.cc b/components/history/core/browser/expire_history_backend_unittest.cc
index b3ea47c..80ea7b7c 100644
--- a/components/history/core/browser/expire_history_backend_unittest.cc
+++ b/components/history/core/browser/expire_history_backend_unittest.cc
@@ -27,6 +27,7 @@
 #include "components/history/core/browser/history_backend_notifier.h"
 #include "components/history/core/browser/history_constants.h"
 #include "components/history/core/browser/history_database.h"
+#include "components/history/core/browser/history_types.h"
 #include "components/history/core/browser/top_sites.h"
 #include "components/history/core/browser/top_sites_impl.h"
 #include "components/history/core/browser/top_sites_observer.h"
@@ -522,22 +523,23 @@
   // Add some stub context annotations for the last URL row.
   URLRow last_row;
   ASSERT_TRUE(main_db_->GetURLRow(url_ids[2], &last_row));
+
   VisitVector visits;
   main_db_->GetVisitsForURL(url_ids[2], &visits);
   ASSERT_EQ(1U, visits.size());
-  main_db_->AddContextAnnotationsForVisit(visits[0].visit_id, {});
+  int test_visit_id = visits[0].visit_id;
+  main_db_->AddContextAnnotationsForVisit(test_visit_id, {});
 
   // Verify that the context annotation is there for that visit.
-  auto annotated_visits = main_db_->GetAllContextAnnotationsForTesting();
-  ASSERT_EQ(1U, annotated_visits.size());
-  EXPECT_EQ(visits[0].visit_id, annotated_visits[0].visit_id);
+  VisitContextAnnotations unused;
+  EXPECT_TRUE(main_db_->GetContextAnnotationsForVisit(test_visit_id, &unused));
 
   // Delete the URL and its dependencies.
   expirer_.DeleteURL(last_row.url(), base::Time::Max());
 
   // All the normal data + the favicon should be gone.
   EnsureURLInfoGone(last_row, false);
-  EXPECT_TRUE(main_db_->GetAllContextAnnotationsForTesting().empty());
+  EXPECT_FALSE(main_db_->GetContextAnnotationsForVisit(test_visit_id, &unused));
 }
 
 // DeleteURL should delete the history of starred urls, but the URL should
diff --git a/components/history/core/browser/history_backend.cc b/components/history/core/browser/history_backend.cc
index 9017009..057f80b 100644
--- a/components/history/core/browser/history_backend.cc
+++ b/components/history/core/browser/history_backend.cc
@@ -43,6 +43,7 @@
 #include "components/history/core/browser/history_database.h"
 #include "components/history/core/browser/history_database_params.h"
 #include "components/history/core/browser/history_db_task.h"
+#include "components/history/core/browser/history_types.h"
 #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"
@@ -1407,6 +1408,58 @@
   ScheduleCommit();
 }
 
+std::vector<AnnotatedVisit> HistoryBackend::GetAnnotatedVisits(
+    const QueryOptions& options) {
+  // Gets `VisitVector` matching `options`, then for each visit, gets the
+  // associated `URLRow`, `VisitContextAnnotations`, and
+  // `VisitContentAnnotations`.
+
+  TRACE_EVENT0("browser", "HistoryBackend::GetAnnotatedVisits");
+  if (!db_)
+    return {};
+
+  // TODO(tommycli): This whole method looks very similar to QueryHistoryBasic,
+  //  and even returns a similar structure. We should investigate combining the
+  //  two, while somehow still avoiding fetching unnecessary fields, such as
+  //  `VisitContextAnnotations`. Probably we need to expand `QueryOptions`.
+  VisitVector visits;
+  // Ignore the return value, as we don't care if we have more visits.
+  db_->GetVisibleVisitsInRange(options, &visits);
+  DCHECK_LE(static_cast<int>(visits.size()), options.EffectiveMaxCount());
+
+  std::vector<AnnotatedVisit> annotated_visits;
+  for (const auto& visit : visits) {
+    // Add a result row for this visit, get the URL info from the DB.
+    URLRow url_row;
+    if (!db_->GetURLRow(visit.url_id, &url_row)) {
+      DVLOG(0) << "Failed to get id " << visit.url_id << " from history.urls.";
+      continue;  // DB out of sync and URL doesn't exist, try to recover.
+    }
+
+    VisitContextAnnotations context_annotations;
+    if (!db_->GetContextAnnotationsForVisit(visit.visit_id,
+                                            &context_annotations)) {
+      // Redirects don't have context annotations. That's not an execeptional
+      // case. We just skip these as normal.
+      continue;
+    }
+
+    VisitContentAnnotations content_annotations;
+
+    // The return value of GetContentAnnotationsForVisit() is not checked for
+    // failures, because the feature flag may be legitimately switched off.
+    // Moreover, some visits may legitimately not have any content annotations.
+    // In those cases, `content_annotations` is left unchanged, and this is
+    // the intended behavior.
+    db_->GetContentAnnotationsForVisit(visit.visit_id, &content_annotations);
+
+    annotated_visits.emplace_back(url_row, visit, context_annotations,
+                                  content_annotations);
+  }
+
+  return annotated_visits;
+}
+
 ClusterIdsAndAnnotatedVisitsResult
 HistoryBackend::GetRecentClusterIdsAndAnnotatedVisits(base::Time minimum_time,
                                                       int max_results) {
@@ -1442,11 +1495,17 @@
 
   // Convert the `VisitID`s to `AnnotatedVisitRow`s.
   std::vector<AnnotatedVisitRow> recent_annotated_visit_rows;
-  base::ranges::transform(recent_visit_ids,
-                          std::back_inserter(recent_annotated_visit_rows),
-                          [&](const VisitID& visit_id) {
-                            return db_->GetAnnotatedVisit(visit_id);
-                          });
+  base::ranges::transform(
+      recent_visit_ids, std::back_inserter(recent_annotated_visit_rows),
+      [&](const VisitID& visit_id) {
+        AnnotatedVisitRow row;
+        row.visit_id = visit_id;
+        // Deliberately ignore the return values. It's okay if the annotations
+        // don't exist and the structs are left unchanged.
+        db_->GetContentAnnotationsForVisit(visit_id, &row.content_annotations);
+        db_->GetContextAnnotationsForVisit(visit_id, &row.context_annotations);
+        return row;
+      });
 
   return {recent_cluster_ids,
           AnnotatedVisitsFromRows(recent_annotated_visit_rows)};
diff --git a/components/history/core/browser/history_backend.h b/components/history/core/browser/history_backend.h
index f1bdf6c..90546ad 100644
--- a/components/history/core/browser/history_backend.h
+++ b/components/history/core/browser/history_backend.h
@@ -429,6 +429,8 @@
       VisitID visit_id,
       const VisitContextAnnotations& visit_context_annotations);
 
+  std::vector<AnnotatedVisit> GetAnnotatedVisits(const QueryOptions& options);
+
   ClusterIdsAndAnnotatedVisitsResult GetRecentClusterIdsAndAnnotatedVisits(
       base::Time minimum_time,
       int max_results);
diff --git a/components/history/core/browser/history_backend_unittest.cc b/components/history/core/browser/history_backend_unittest.cc
index ddd0594..442c811 100644
--- a/components/history/core/browser/history_backend_unittest.cc
+++ b/components/history/core/browser/history_backend_unittest.cc
@@ -41,6 +41,7 @@
 #include "components/history/core/browser/history_database_params.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/history/core/browser/history_service_observer.h"
+#include "components/history/core/browser/history_types.h"
 #include "components/history/core/browser/in_memory_database.h"
 #include "components/history/core/browser/in_memory_history_backend.h"
 #include "components/history/core/browser/keyword_search_term.h"
@@ -3145,16 +3146,21 @@
   EXPECT_EQ(u"www.baz.com/", FormatUrlForRedirectComparison(url3));
 }
 
-TEST_F(HistoryBackendTest, AddContextAnnotationsForVisit) {
+TEST_F(HistoryBackendTest, AnnotatedVisits) {
   auto last_visit_time = base::Time::Now();
   const auto add_url_and_visit = [&](std::string url) {
     // Each visit should have a unique `visit_time` to avoid deduping visits to
     // the same URL. The exact times don't matter, but we use increasing values
     // to making the test cases easy to reason about.
     last_visit_time += base::TimeDelta::FromMilliseconds(1);
-    return backend_->AddPageVisit(GURL(url), last_visit_time, 0,
-                                  ui::PageTransition::PAGE_TRANSITION_FIRST,
-                                  false, SOURCE_BROWSED, false, false);
+    return backend_->AddPageVisit(
+        GURL(url), last_visit_time, /*referring_visit=*/0,
+        // Must set this so that the visit is considered 'visible'.
+        ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
+                                  ui::PAGE_TRANSITION_CHAIN_START |
+                                  ui::PAGE_TRANSITION_CHAIN_END),
+        /*hidden=*/false, SOURCE_BROWSED, /*should_increment_typed_count=*/true,
+        /*floc_allowed=*/false);
   };
 
   const auto delete_url = [&](URLID id) { backend_->db_->DeleteURLRow(id); };
@@ -3164,17 +3170,6 @@
     backend_->db_->DeleteVisit(row);
   };
 
-  // Helper function to get all annotated visits without worrying about params.
-  const auto get_annotated_visit_rows_from_backend = [&]() {
-    const auto visit_ids =
-        backend_->db_->GetRecentAnnotatedVisitIds(base::Time::Min(), 100);
-    std::vector<AnnotatedVisitRow> visit_rows;
-    base::ranges::transform(visit_ids, std::back_inserter(visit_rows),
-                            [&](const auto& visit_id) {
-                              return backend_->db_->GetAnnotatedVisit(visit_id);
-                            });
-    return backend_->AnnotatedVisitsFromRows(visit_rows);
-  };
   // Helper function to get the # of rows in the db before the backend prunes
   // annotated visits without an associated URL. Use this to verify row count.
   const auto get_annotated_visit_row_count_in_db = [&]() {
@@ -3182,6 +3177,10 @@
         .size();
   };
 
+  // For test purposes, keep all the duplicates.
+  history::QueryOptions query_options;
+  query_options.duplicate_policy = QueryOptions::KEEP_ALL_DUPLICATES;
+
   // Happy path; annotated visits with associated URL & visits.
   ASSERT_EQ(add_url_and_visit("http://1.com/"),
             (std::pair<URLID, VisitID>{1, 1}));
@@ -3192,16 +3191,19 @@
   backend_->AddContextAnnotationsForVisit(1, {true});
   backend_->AddContextAnnotationsForVisit(3, {false});
   backend_->AddContextAnnotationsForVisit(2, {true});
+  EXPECT_EQ(backend_->GetAnnotatedVisits(query_options).size(), 3u);
   EXPECT_EQ(get_annotated_visit_row_count_in_db(), 3u);
 
   // Annotated visits should have a visit IDs.
   EXPECT_DCHECK_DEATH(backend_->AddContextAnnotationsForVisit(0, {true}));
+  EXPECT_EQ(backend_->GetAnnotatedVisits(query_options).size(), 3u);
   EXPECT_EQ(get_annotated_visit_row_count_in_db(), 3u);
 
   // Annotated visits without an associated visit should not be added.
   backend_->AddContextAnnotationsForVisit(4, {true});
   EXPECT_EQ(add_url_and_visit("http://3.com/"),
             (std::pair<URLID, VisitID>{3, 4}));
+  EXPECT_EQ(backend_->GetAnnotatedVisits(query_options).size(), 3u);
   EXPECT_EQ(get_annotated_visit_row_count_in_db(), 3u);
 
   // Annotated visits associated with a removed visit should not be added.
@@ -3209,11 +3211,11 @@
             (std::pair<URLID, VisitID>{4, 5}));
   delete_visit(5);
   backend_->AddContextAnnotationsForVisit(5, {true});
-  EXPECT_EQ(get_annotated_visit_row_count_in_db(), 3u);
+  EXPECT_EQ(backend_->GetAnnotatedVisits(query_options).size(), 3u);
 
   // Verify only the correct annotated visits are retrieved ordered recent
   // visits first.
-  auto annotated_visits = get_annotated_visit_rows_from_backend();
+  auto annotated_visits = backend_->GetAnnotatedVisits(query_options);
   ASSERT_EQ(annotated_visits.size(), 3u);
   EXPECT_EQ(annotated_visits[0].url_row.id(), 1);
   EXPECT_EQ(annotated_visits[0].url_row.url(), "http://1.com/");
@@ -3231,15 +3233,13 @@
   EXPECT_EQ(annotated_visits[2].visit_row.url_id, 1);
   EXPECT_EQ(annotated_visits[2].context_annotations.omnibox_url_copied, true);
 
-  // Annotated visits associated with a removed visit should not be retrievable.
-  // Associated URLs aren't checked.
   delete_url(2);
   delete_visit(3);
-  // The db should only return annotated visits with associated visits, but
-  // doesn't check for associated URLs.
+  // Annotated visits should be unfetchable if their associated URL or visit is
+  // removed. Notably, because of that, the row count in the DB and the fetched
+  // vector from `GetAnnotatedVisits()` differ in size here.
   EXPECT_EQ(get_annotated_visit_row_count_in_db(), 2u);
-  // The backend should check for both associated URL and visit.
-  annotated_visits = get_annotated_visit_rows_from_backend();
+  annotated_visits = backend_->GetAnnotatedVisits(query_options);
   ASSERT_EQ(annotated_visits.size(), 1u);
   EXPECT_EQ(annotated_visits[0].url_row.id(), 1);
   EXPECT_EQ(annotated_visits[0].url_row.url(), "http://1.com/");
diff --git a/components/history/core/browser/history_service.cc b/components/history/core/browser/history_service.cc
index 7be72cb..8a23ef5e 100644
--- a/components/history/core/browser/history_service.cc
+++ b/components/history/core/browser/history_service.cc
@@ -270,6 +270,19 @@
                      history_backend_, visit_id, visit_context_annotations));
 }
 
+base::CancelableTaskTracker::TaskId HistoryService::GetAnnotatedVisits(
+    const QueryOptions& options,
+    GetAnnotatedVisitsCallback callback,
+    base::CancelableTaskTracker* tracker) const {
+  DCHECK(backend_task_runner_) << "History service being called after cleanup";
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  return tracker->PostTaskAndReplyWithResult(
+      backend_task_runner_.get(), FROM_HERE,
+      base::BindOnce(&HistoryBackend::GetAnnotatedVisits, history_backend_,
+                     options),
+      std::move(callback));
+}
+
 base::CancelableTaskTracker::TaskId
 HistoryService::GetRecentClusterIdsAndAnnotatedVisits(
     base::Time minimum_time,
diff --git a/components/history/core/browser/history_service.h b/components/history/core/browser/history_service.h
index 47262e0..0f407dac 100644
--- a/components/history/core/browser/history_service.h
+++ b/components/history/core/browser/history_service.h
@@ -505,6 +505,19 @@
       VisitID visit_id,
       const VisitContextAnnotations& visit_context_annotations);
 
+  // Gets a vector of reverse-chronological `AnnotatedVisit` instances based on
+  // `options`. Uses the same deduplication and visibility logic as
+  // `HistoryService::QueryHistory()`. Notably, this method EXCLUDES from the
+  // result any visits that lack context annotations. To make a continuation
+  // call, the last item's visit time can be used as the `end_time` constraint
+  // in the next page's `options`.
+  using GetAnnotatedVisitsCallback =
+      base::OnceCallback<void(std::vector<AnnotatedVisit>)>;
+  base::CancelableTaskTracker::TaskId GetAnnotatedVisits(
+      const QueryOptions& options,
+      GetAnnotatedVisitsCallback callback,
+      base::CancelableTaskTracker* tracker) const;
+
   // Get recent recent `Cluster`s and `AnnotatedVisit`s as a flat list without
   // duplicates. Can include `AnnotatedVisit`s older than `minimum_time` if
   // they're in a `Cluster` that's newer than `minimum_time`. This is used to
diff --git a/components/history/core/browser/visit_annotations_database.cc b/components/history/core/browser/visit_annotations_database.cc
index 8762a31af..cbd7cc0 100644
--- a/components/history/core/browser/visit_annotations_database.cc
+++ b/components/history/core/browser/visit_annotations_database.cc
@@ -296,6 +296,33 @@
   }
 }
 
+bool VisitAnnotationsDatabase::GetContextAnnotationsForVisit(
+    VisitID visit_id,
+    VisitContextAnnotations* out_context_annotations) {
+  DCHECK(out_context_annotations);
+
+  sql::Statement statement(GetDB().GetCachedStatement(
+      SQL_FROM_HERE, "SELECT" HISTORY_CONTEXT_ANNOTATIONS_ROW_FIELDS
+                     "FROM context_annotations WHERE visit_id=?"));
+  statement.BindInt64(0, visit_id);
+
+  if (!statement.Step())
+    return false;
+
+  VisitID received_visit_id = statement.ColumnInt64(0);
+  DCHECK_EQ(visit_id, received_visit_id);
+
+  // TODO(tommycli): Make sure ConstructContextAnnotationsWithFlags validates
+  //  the column values against potential disk corruption, and add tests.
+  // The `VisitID` in column 0 is intentionally ignored, as it's not part of
+  // `VisitContextAnnotations`.
+  *out_context_annotations = ConstructContextAnnotationsWithFlags(
+      statement.ColumnInt64(1),
+      base::TimeDelta::FromMicroseconds(statement.ColumnInt64(2)),
+      statement.ColumnInt(3));
+  return true;
+}
+
 bool VisitAnnotationsDatabase::GetContentAnnotationsForVisit(
     VisitID visit_id,
     VisitContentAnnotations* out_content_annotations) {
@@ -311,10 +338,7 @@
     return false;
 
   VisitID received_visit_id = statement.ColumnInt64(0);
-  // We got a different visit than we asked for, something is wrong.
   DCHECK_EQ(visit_id, received_visit_id);
-  if (visit_id != received_visit_id)
-    return false;
 
   out_content_annotations->model_annotations.floc_protected_score =
       static_cast<float>(statement.ColumnDouble(1));
@@ -326,27 +350,6 @@
   return true;
 }
 
-AnnotatedVisitRow VisitAnnotationsDatabase::GetAnnotatedVisit(
-    VisitID visit_id) {
-  // TODO(manukh): Currently, this only sets the `context_annotations`. It
-  //  should also set the `content_annotations`.
-  DCHECK_GT(visit_id, 0);
-  sql::Statement statement(GetDB().GetCachedStatement(
-      SQL_FROM_HERE, "SELECT" HISTORY_CONTEXT_ANNOTATIONS_ROW_FIELDS
-                     "FROM context_annotations WHERE visit_id=?"));
-  statement.BindInt64(0, visit_id);
-
-  if (!statement.Step()) {
-    DVLOG(0) << "Failed to execute 'context_annotations' select statement:  "
-             << "visit_id = " << visit_id;
-    return {};
-  }
-
-  auto annotated_visit_row = StatementToAnnotatedVisitRow(statement);
-  DCHECK_EQ(annotated_visit_row.visit_id, visit_id);
-  return annotated_visit_row;
-}
-
 std::vector<VisitID> VisitAnnotationsDatabase::GetRecentAnnotatedVisitIds(
     base::Time minimum_time,
     int max_results) {
diff --git a/components/history/core/browser/visit_annotations_database.h b/components/history/core/browser/visit_annotations_database.h
index 9f5cef5b..d2faf44 100644
--- a/components/history/core/browser/visit_annotations_database.h
+++ b/components/history/core/browser/visit_annotations_database.h
@@ -51,17 +51,19 @@
       VisitID visit_id,
       const VisitContentAnnotations& visit_content_annotations);
 
-  // Query for a VisitContentAnnotations given a `VisitID` and returns it if
-  // present. If it's successful, `out_content_annotations` will be filled with
-  // the expected data and will return true; otherwise,
-  // `out_content_annotations` won't be changed and will return false.
+  // Query for a `VisitContentAnnotations` given `visit_id`. If it's found and
+  // valid, this method returns true, and `out_content_annotations` is filled.
+  // Otherwise, this returns false, and `out_content_annotations` is unchanged.
   bool GetContentAnnotationsForVisit(
       VisitID visit_id,
       VisitContentAnnotations* out_content_annotations);
 
-  // Get the `AnnotatedVisitRow` for `visit_id`. Returns an empty row (i.e.
-  // `visit_id` of 0) on failure.
-  AnnotatedVisitRow GetAnnotatedVisit(VisitID visit_id);
+  // Query for a `VisitContextAnnotations` given `visit_id`. If it's found and
+  // valid, this method returns true, and `out_context_annotations` is filled.
+  // Otherwise, this returns false, and `out_context_annotations` is unchanged.
+  bool GetContextAnnotationsForVisit(
+      VisitID visit_id,
+      VisitContextAnnotations* out_context_annotations);
 
   // Get recent `AnnotatedVisit`s' IDs. Does not return visits without
   // annotations.
diff --git a/components/history/core/browser/visit_annotations_database_unittest.cc b/components/history/core/browser/visit_annotations_database_unittest.cc
index 9e29963b..370ddb4 100644
--- a/components/history/core/browser/visit_annotations_database_unittest.cc
+++ b/components/history/core/browser/visit_annotations_database_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "components/history/core/browser/visit_annotations_database.h"
 
+#include "base/cxx17_backports.h"
 #include "base/test/gtest_util.h"
 #include "base/time/time.h"
 #include "components/history/core/browser/history_types.h"
@@ -118,25 +119,37 @@
   AddVisitWithTime(IntToTime(30), false);
   AddVisitWithTime(IntToTime(10), false);
 
-  const std::vector<VisitContextAnnotations> visit_contest_annotations_list = {
+  const std::vector<VisitContextAnnotations> visit_context_annotations_list = {
       {true, false, true, true, false, false},
       {false, true, false, false, false, true},
       {false, true, true, false, true, false},
   };
 
-  AddContextAnnotationsForVisit(1, visit_contest_annotations_list[0]);
-  AddContextAnnotationsForVisit(2, visit_contest_annotations_list[1]);
-  AddContextAnnotationsForVisit(3, visit_contest_annotations_list[2]);
+  // Verify `AddContextAnnotationsForVisit()` and `GetAnnotatedVisits()`.
+  AddContextAnnotationsForVisit(1, visit_context_annotations_list[0]);
+  AddContextAnnotationsForVisit(2, visit_context_annotations_list[1]);
+  AddContextAnnotationsForVisit(3, visit_context_annotations_list[2]);
 
-  const std::vector<VisitID> expected_visit_ids = {3, 2, 1};
-  EXPECT_EQ(GetRecentAnnotatedVisitIds(base::Time::Min(), 10),
-            expected_visit_ids);
-  ExpectContextAnnotations(GetAnnotatedVisit(1).context_annotations,
-                           visit_contest_annotations_list[0]);
-  ExpectContextAnnotations(GetAnnotatedVisit(2).context_annotations,
-                           visit_contest_annotations_list[1]);
-  ExpectContextAnnotations(GetAnnotatedVisit(3).context_annotations,
-                           visit_contest_annotations_list[2]);
+  for (size_t i = 0; i < base::size(visit_context_annotations_list); ++i) {
+    SCOPED_TRACE(testing::Message() << "i: " << i);
+    VisitContextAnnotations actual;
+    VisitID visit_id = i + 1;  // VisitIDs are start at 1.
+    EXPECT_TRUE(GetContextAnnotationsForVisit(visit_id, &actual));
+    ExpectContextAnnotations(actual, visit_context_annotations_list[i]);
+  }
+
+  // Verify `DeleteAnnotationsForVisit()`.
+  DeleteAnnotationsForVisit(1);
+  DeleteAnnotationsForVisit(3);
+
+  VisitContextAnnotations actual;
+  EXPECT_FALSE(GetContextAnnotationsForVisit(1, &actual));
+
+  // Visit ID = 2 is in the 1st indexed position.
+  EXPECT_TRUE(GetContextAnnotationsForVisit(2, &actual));
+  ExpectContextAnnotations(actual, visit_context_annotations_list[1]);
+
+  EXPECT_FALSE(GetContextAnnotationsForVisit(3, &actual));
 }
 
 TEST_F(VisitAnnotationsDatabaseTest, UpdateContentAnnotationsForVisit) {
diff --git a/components/history/core/browser/visit_database.h b/components/history/core/browser/visit_database.h
index e251d9c2..ca87e20e 100644
--- a/components/history/core/browser/visit_database.h
+++ b/components/history/core/browser/visit_database.h
@@ -114,12 +114,12 @@
   // begin time is inclusive, the end time is exclusive. Either time can be
   // is_null(), in which case the times in that direction are unbounded.
   //
-  // Up to `max_count` visits will be returned. If there are more visits than
-  // that, the most recent `max_count` will be returned. If 0, all visits in the
-  // range will be computed.
+  // Use `options.duplicate_policy` to control the URL deduplication policy -
+  // for instance, if only a single visit should be returned for each URL.
   //
-  // Only one visit for each URL will be returned, and it will be the most
-  // recent one in the time range.
+  // Up to `options.max_count` visits will be returned. If there are more visits
+  // than that, the most recent `options.max_count` will be returned. If 0, all
+  // visits in the range will be computed.
   //
   // Returns true if there are more results available, i.e. if the number of
   // results was restricted by `options.max_count`.
diff --git a/components/history_clusters/core/history_clusters_service.cc b/components/history_clusters/core/history_clusters_service.cc
index ed19a97..2d049d5 100644
--- a/components/history_clusters/core/history_clusters_service.cc
+++ b/components/history_clusters/core/history_clusters_service.cc
@@ -13,6 +13,7 @@
 #include "base/i18n/case_conversion.h"
 #include "base/ranges/algorithm.h"
 #include "base/strings/utf_string_conversions.h"
+#include "components/history/core/browser/history_types.h"
 #include "components/history_clusters/core/history_clusters_buildflags.h"
 #include "components/history_clusters/core/memories_features.h"
 #include "components/history_clusters/core/remote_clustering_backend.h"
@@ -258,14 +259,16 @@
           .Then(base::BindOnce(&ClustersToMojom))
           .Then(std::move(callback)));
 
-  history_service_->GetRecentClusterIdsAndAnnotatedVisits(
-      base::Time::Min(), kMaxVisitsToCluster.Get(),
+  // TODO(tommycli): Support pagination by setting `begin_time` on `options`.
+  history::QueryOptions options;
+  options.max_count = kMaxVisitsToCluster.Get();
+
+  history_service_->GetAnnotatedVisits(
+      options,
       base::BindOnce(
           [](const IncompleteVisitMap& incomplete_visits,
-             const base::Time& end_time,
-             history::ClusterIdsAndAnnotatedVisitsResult result) {
-            auto& visits = result.annotated_visits;
-
+             const history::QueryOptions& options,
+             std::vector<history::AnnotatedVisit> visits) {
             // Append incomplete visits to `visits` too, as otherwise they will
             // be mysteriously missing from the Clusters UI. They haven't
             // recorded the page end metrics yet, but that's fine.
@@ -277,9 +280,12 @@
                 continue;
               }
 
-              if (!end_time.is_null() &&
-                  incomplete_visit.visit_row.visit_time >= end_time) {
-                // Discard incomplete visits are outside the `end_time` bound.
+              const auto& visit_time = incomplete_visit.visit_row.visit_time;
+              if (visit_time < options.begin_time ||
+                  (!options.end_time.is_null() &&
+                   visit_time >= options.end_time)) {
+                // Discard incomplete visits outside the `options` time bounds.
+                // `begin_time` is inclusive, and `end_time` is exclusive.
                 continue;
               }
 
@@ -293,7 +299,7 @@
 
             return visits;
           },
-          incomplete_visit_context_annotations_, end_time)
+          incomplete_visit_context_annotations_, options)
           .Then(std::move(on_visits_callback)),
       task_tracker);
 }
diff --git a/components/history_clusters/core/history_clusters_service_test_api.h b/components/history_clusters/core/history_clusters_service_test_api.h
index 445a02d..3e82e502 100644
--- a/components/history_clusters/core/history_clusters_service_test_api.h
+++ b/components/history_clusters/core/history_clusters_service_test_api.h
@@ -30,12 +30,11 @@
     std::vector<history::AnnotatedVisit> annotated_visits;
 
     base::CancelableTaskTracker tracker;
-    history_service_->GetRecentClusterIdsAndAnnotatedVisits(
-        base::Time::Min(),
-        1000,  // Getting 1000 clusters for testing is a reasonable fake value.
+    history_service_->GetAnnotatedVisits(
+        history::QueryOptions(),
         base::BindLambdaForTesting(
-            [&](history::ClusterIdsAndAnnotatedVisitsResult result) {
-              annotated_visits = std::move(result.annotated_visits);
+            [&](std::vector<history::AnnotatedVisit> visits) {
+              annotated_visits = std::move(visits);
             }),
         &tracker);
     history::BlockUntilHistoryProcessesPendingRequests(history_service_);
diff --git a/components/history_clusters/core/history_clusters_service_unittest.cc b/components/history_clusters/core/history_clusters_service_unittest.cc
index 4f5b0b1..2418381 100644
--- a/components/history_clusters/core/history_clusters_service_unittest.cc
+++ b/components/history_clusters/core/history_clusters_service_unittest.cc
@@ -135,6 +135,14 @@
         test_clustering_backend_->last_clustered_visits();
     ASSERT_EQ(visits.size(), 2u);
     auto& visit = visits[0];
+    EXPECT_EQ(visit.visit_row.visit_id, 2);
+    EXPECT_EQ(visit.visit_row.visit_time,
+              GetHardcodedTestVisits()[1].visit_row.visit_time);
+    EXPECT_EQ(visit.visit_row.visit_duration, base::TimeDelta::FromSeconds(20));
+    EXPECT_EQ(visit.url_row.url(), "https://github.com/");
+    EXPECT_EQ(visit.context_annotations.page_end_reason, 5);
+
+    visit = visits[1];
     EXPECT_EQ(visit.visit_row.visit_id, 1);
     EXPECT_EQ(visit.visit_row.visit_time,
               GetHardcodedTestVisits()[0].visit_row.visit_time);
@@ -143,13 +151,6 @@
     EXPECT_EQ(visit.url_row.url(), "https://google.com/");
     EXPECT_EQ(visit.context_annotations.page_end_reason, 3);
 
-    visit = visits[1];
-    EXPECT_EQ(visit.visit_row.visit_id, 2);
-    EXPECT_EQ(visit.visit_row.visit_time,
-              GetHardcodedTestVisits()[1].visit_row.visit_time);
-    EXPECT_EQ(visit.visit_row.visit_duration, base::TimeDelta::FromSeconds(20));
-    EXPECT_EQ(visit.url_row.url(), "https://github.com/");
-    EXPECT_EQ(visit.context_annotations.page_end_reason, 5);
     // TODO(tommycli): Add back visit.referring_visit_id() check after updating
     //  the HistoryService test methods to support that field.
   }
diff --git a/components/network_time/DEPS b/components/network_time/DEPS
index 64f1377..85248f86 100644
--- a/components/network_time/DEPS
+++ b/components/network_time/DEPS
@@ -4,5 +4,6 @@
   "+components/prefs",
   "+net",
   "+services/network/public/cpp",
+  "+services/network/public/mojom",
   "+services/network/test",
 ]
diff --git a/components/network_time/network_time_tracker.cc b/components/network_time/network_time_tracker.cc
index c548ee66..e38ab86 100644
--- a/components/network_time/network_time_tracker.cc
+++ b/components/network_time/network_time_tracker.cc
@@ -34,6 +34,7 @@
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 
 namespace network_time {
 
diff --git a/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc b/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc
index e8117c0..317922a 100644
--- a/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc
+++ b/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc
@@ -20,6 +20,7 @@
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 #include "url/url_canon.h"
 
 namespace autofill {
diff --git a/components/password_manager/core/browser/leak_detection/leak_detection_request.cc b/components/password_manager/core/browser/leak_detection/leak_detection_request.cc
index 8a02f433..c8a2ccd 100644
--- a/components/password_manager/core/browser/leak_detection/leak_detection_request.cc
+++ b/components/password_manager/core/browser/leak_detection/leak_detection_request.cc
@@ -26,6 +26,7 @@
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 #include "url/gurl.h"
 
 namespace password_manager {
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc
index 34111b9..a825254c 100644
--- a/components/password_manager/core/browser/password_form_manager.cc
+++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -1032,7 +1032,8 @@
   const PasswordFieldPrediction* field_prediction = FindFieldPrediction(
       possible_username->form_predictions, possible_username->renderer_id);
   if (field_prediction && field_prediction->type == SINGLE_USERNAME) {
-    LogUsingPossibleUsername(client_, /*is_used*/ true, "Server predictions");
+    LogUsingPossibleUsername(client_, /*is_used*/ true,
+                             "Server predictions available");
     return true;
   } else {
     LogUsingPossibleUsername(client_, /*is_used*/ false,
diff --git a/components/password_manager/core/browser/password_form_manager.h b/components/password_manager/core/browser/password_form_manager.h
index 4f054052..ced18968 100644
--- a/components/password_manager/core/browser/password_form_manager.h
+++ b/components/password_manager/core/browser/password_form_manager.h
@@ -311,10 +311,10 @@
 
   PasswordFormDigest ConstructObservedFormDigest() const;
 
-  // Returns whether |possible_username| should be used for offering the
-  // username to save on username first flow. The decision is based on server
-  // predictions, and whether |possible_username| has a non empty value and is
-  // not expired yet.
+  // Returns whether |possible_username| should be populated in a Save/Update
+  // prompt on username first flow. The decision is based on server predictions,
+  // and whether |possible_username| has a non empty value and is not expired
+  // yet.
   bool UsePossibleUsernameToBuildCredential(
       const PossibleUsernameData* possible_username);
 
diff --git a/components/password_manager/core/browser/password_form_manager_unittest.cc b/components/password_manager/core/browser/password_form_manager_unittest.cc
index a0e0ab9..7e0a5fa 100644
--- a/components/password_manager/core/browser/password_form_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_form_manager_unittest.cc
@@ -2163,7 +2163,8 @@
             form_manager_->GetPendingCredentials().username_value);
 }
 
-// Tests that username is not taken when a possible username is not valid.
+// Tests that username is not taken if domains of possible username field
+// and submitted password form are different.
 TEST_P(PasswordFormManagerTest, UsernameFirstFlowDifferentDomains) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(features::kUsernameFirstFlow);
@@ -2189,7 +2190,7 @@
   ASSERT_TRUE(form_manager_->ProvisionallySave(submitted_form, &driver_,
                                                &possible_username_data));
 
-  // |possible_username_data| has different domain then |submitted_form|. Check
+  // |possible_username_data| has different domain than |submitted_form|. Check
   // that no username is chosen.
   EXPECT_TRUE(form_manager_->GetPendingCredentials().username_value.empty());
 }
@@ -2965,7 +2966,6 @@
 }
 
 // Tests that username is taken during username first flow.
-// Local heuristics on Android for username first flow is not supported.
 TEST_F(PasswordFormManagerTestWithMockedSaver, UsernameFirstFlow) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(features::kUsernameFirstFlow);
diff --git a/components/password_manager/core/browser/password_manager_unittest.cc b/components/password_manager/core/browser/password_manager_unittest.cc
index 936580c..cf266b0 100644
--- a/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_unittest.cc
@@ -3503,9 +3503,9 @@
   EXPECT_CALL(*store_, GetLogins(_, _))
       .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), saved_form)));
 
-  PasswordForm username_form(MakeSimpleFormWithOnlyUsernameField());
   // Simulate the user typed a previously not saved username in the username
   // form.
+  PasswordForm username_form(MakeSimpleFormWithOnlyUsernameField());
   const std::u16string username = u"newusername@gmail.com";
   ASSERT_TRUE(saved_form.username_value != username);
   EXPECT_CALL(driver_, GetLastCommittedURL())
@@ -3521,12 +3521,11 @@
   form_structure.field(0)->set_server_predictions({prediction});
   manager()->ProcessAutofillPredictions(&driver_, {&form_structure});
 
-  PasswordForm password_form(MakeSimpleFormWithOnlyPasswordField());
   // Simulate that a form which contains only 1 password field is added
   // to the page.
+  PasswordForm password_form(MakeSimpleFormWithOnlyPasswordField());
   manager()->OnPasswordFormsParsed(&driver_,
                                    {password_form.form_data} /* observed */);
-
   EXPECT_CALL(client_, IsSavingAndFillingEnabled(password_form.url))
       .WillRepeatedly(Return(true));
 
@@ -3559,8 +3558,8 @@
   EXPECT_CALL(*store_, GetLogins(_, _))
       .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), saved_form)));
 
-  PasswordForm username_form(MakeSimpleFormWithOnlyUsernameField());
   // Simulate the user typed a previously not saved username in username form.
+  PasswordForm username_form(MakeSimpleFormWithOnlyUsernameField());
   const std::u16string username = u"newusername@gmail.com";
   ASSERT_TRUE(saved_form.username_value != username);
   EXPECT_CALL(driver_, GetLastCommittedURL())
@@ -3569,12 +3568,11 @@
       &driver_, username_form.form_data.fields[0].unique_renderer_id,
       u"username", username /* value */);
 
-  PasswordForm password_form(MakeSimpleFormWithOnlyPasswordField());
   // Simulate that a form which contains only 1 field which is password is added
   // to the page.
+  PasswordForm password_form(MakeSimpleFormWithOnlyPasswordField());
   manager()->OnPasswordFormsParsed(&driver_,
                                    {password_form.form_data} /* observed */);
-
   EXPECT_CALL(client_, IsSavingAndFillingEnabled(password_form.url))
       .WillRepeatedly(Return(true));
 
@@ -3585,14 +3583,16 @@
   password_form.form_data.fields[0].value = password;
   OnPasswordFormSubmitted(password_form.form_data);
 
-  // Simulate successful submission and expect an update prompt.
+  // Simulate successful submission and expect a prompt.
   std::unique_ptr<PasswordFormManagerForUI> form_manager;
   EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
       .WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager)));
   manager()->OnPasswordFormsRendered(&driver_, {} /* observed */, true);
   ASSERT_TRUE(form_manager);
 
-  // Simulate accepting the prompt and expect updating the credential.
+  // Simulate accepting the prompt and expect updating the credential (without
+  // a server prediction, the single |username| is ignored, so the new password
+  // is associated with the old username).
   EXPECT_CALL(
       *store_,
       UpdateLogin(AllOf(
diff --git a/components/password_manager/core/browser/password_scripts_fetcher_impl.cc b/components/password_manager/core/browser/password_scripts_fetcher_impl.cc
index befcbd98..ce296b99 100644
--- a/components/password_manager/core/browser/password_scripts_fetcher_impl.cc
+++ b/components/password_manager/core/browser/password_scripts_fetcher_impl.cc
@@ -13,6 +13,7 @@
 #include "components/password_manager/core/common/password_manager_features.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 #include "url/gurl.h"
 #include "url/origin.h"
 
diff --git a/components/password_manager/core/browser/site_affiliation/affiliation_fetcher_base.cc b/components/password_manager/core/browser/site_affiliation/affiliation_fetcher_base.cc
index d2e731c8..9ecf66fd 100644
--- a/components/password_manager/core/browser/site_affiliation/affiliation_fetcher_base.cc
+++ b/components/password_manager/core/browser/site_affiliation/affiliation_fetcher_base.cc
@@ -13,6 +13,7 @@
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 
 namespace password_manager {
 
diff --git a/components/password_manager/core/browser/well_known_change_password_state_unittest.cc b/components/password_manager/core/browser/well_known_change_password_state_unittest.cc
index 1ee8483..660e1bee 100644
--- a/components/password_manager/core/browser/well_known_change_password_state_unittest.cc
+++ b/components/password_manager/core/browser/well_known_change_password_state_unittest.cc
@@ -16,6 +16,7 @@
 #include "net/base/load_flags.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 #include "services/network/test/test_shared_url_loader_factory.h"
 #include "services/network/test/test_url_loader_factory.h"
 #include "services/network/test/test_utils.h"
diff --git a/components/policy/core/common/configuration_policy_provider_test.cc b/components/policy/core/common/configuration_policy_provider_test.cc
index 076c737..5244f98 100644
--- a/components/policy/core/common/configuration_policy_provider_test.cc
+++ b/components/policy/core/common/configuration_policy_provider_test.cc
@@ -238,8 +238,6 @@
            test_harness_->policy_scope(), test_harness_->policy_source(),
            expected_value.Clone(), nullptr);
   EXPECT_TRUE(provider_->policies().Equals(expected_bundle));
-  // TODO(joaodasilva): set the policy in the POLICY_DOMAIN_EXTENSIONS too,
-  // and extend the |expected_bundle|, once all providers are ready.
 }
 
 TEST_P(ConfigurationPolicyProviderTest, Empty) {
diff --git a/components/policy/proto/chrome_device_policy.proto b/components/policy/proto/chrome_device_policy.proto
index 240fc088..b591255 100644
--- a/components/policy/proto/chrome_device_policy.proto
+++ b/components/policy/proto/chrome_device_policy.proto
@@ -149,6 +149,8 @@
   optional bool report_print_jobs = 26 [default = false];
   optional bool report_login_logout = 27 [default = false];
   optional bool report_audio_status = 28 [default = true];
+  optional bool report_network_configuration = 29 [default = true];
+  optional bool report_network_status = 30 [default = true];
 
   // Frequency to report device status, default to 3 hours.
   // If changed, the default value has to be updated in
diff --git a/components/policy/proto/device_management_backend.proto b/components/policy/proto/device_management_backend.proto
index 2731b10..961f51d 100644
--- a/components/policy/proto/device_management_backend.proto
+++ b/components/policy/proto/device_management_backend.proto
@@ -1715,6 +1715,7 @@
     TYPE_USER_SCRIPT = 6;
     TYPE_PLATFORM_APP = 7;
     TYPE_LOGIN_SCREEN_EXTENSION = 8;
+    TYPE_CHROMEOS_SYSTEM_EXTENSION = 9;
   }
   optional ExtensionType app_type = 5;
 
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index cb60549..4d68aa6 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -913,7 +913,9 @@
         'ReportDeviceActivityTimes',
         'ReportDeviceAudioStatus',
         'ReportDeviceLocation',
+        'ReportDeviceNetworkConfiguration',
         'ReportDeviceNetworkInterfaces',
+        'ReportDeviceNetworkStatus',
         'ReportDeviceHardwareStatus',
         'ReportDeviceSessionStatus',
         'ReportDeviceGraphicsStatus',
@@ -9599,6 +9601,38 @@
       'arc_support': 'This policy has no effect on the logging done by Android.',
     },
     {
+      'name': 'ReportDeviceNetworkConfiguration',
+      'owners': ['tylergarrett@google.com', 'cros-reporting-team@google.com'],
+      'type': 'main',
+      'schema': { 'type': 'boolean' },
+      'future_on': ['chrome_os'],
+      'supported_chrome_os_management': ['google_cloud'],
+      'device_only': True,
+      'features': {
+        'dynamic_refresh': True,
+      },
+      'items': [
+        {
+          'value': True,
+          'caption': 'Report network configuration',
+        },
+        {
+          'value': False,
+          'caption': 'Do not report network configuration',
+        },
+      ],
+      'example_value': False,
+      'default': True,
+      'id': 875,
+      'caption': '''Report network configuration''',
+      'tags': ['admin-sharing'],
+      'desc': '''Report users network configuration on enrolled devices.
+
+      If the policy is set to false, the information will not be reported.
+      If set to true or unset, the device's network configuration will be reported.''',
+      'arc_support': 'This policy has no effect on the logging done by Android.',
+    },
+    {
       'name': 'ReportDeviceNetworkInterfaces',
       'owners': ['cros-reporting-team@google.com', 'lbaraz@chromium.org'],
       'type': 'main',
@@ -9619,6 +9653,38 @@
       'arc_support': 'This policy has no effect on the logging done by Android.',
     },
     {
+      'name': 'ReportDeviceNetworkStatus',
+      'owners': ['tylergarrett@google.com', 'cros-reporting-team@google.com'],
+      'type': 'main',
+      'schema': { 'type': 'boolean' },
+      'future_on': ['chrome_os'],
+      'supported_chrome_os_management': ['google_cloud'],
+      'device_only': True,
+      'features': {
+        'dynamic_refresh': True,
+      },
+      'items': [
+        {
+          'value': True,
+          'caption': 'Report network status',
+        },
+        {
+          'value': False,
+          'caption': 'Do not report network status',
+        },
+      ],
+      'example_value': False,
+      'default': True,
+      'id': 876,
+      'caption': '''Report network status''',
+      'tags': ['admin-sharing'],
+      'desc': '''Report users network status on enrolled devices.
+
+      If the policy is set to false, the information will not be reported.
+      If set to true or unset, the device's network status will be reported.''',
+      'arc_support': 'This policy has no effect on the logging done by Android.',
+    },
+    {
       'name': 'ReportDeviceUsers',
       'owners': ['stepco@chromium.org', 'cros-reporting-team@google.com', 'lbaraz@chromium.org'],
       'type': 'main',
@@ -26883,7 +26949,9 @@
     'ReportDeviceAudioStatus': 'device_reporting.report_audio_status',
     'ReportDeviceBootMode': 'device_reporting.report_boot_mode',
     'ReportDeviceLocation': 'device_reporting.report_location',
+    'ReportDeviceNetworkConfiguration': 'device_reporting.report_network_configuration',
     'ReportDeviceNetworkInterfaces': 'device_reporting.report_network_interfaces',
+    'ReportDeviceNetworkStatus': 'device_reporting.report_network_status',
     'ReportDeviceUsers': 'device_reporting.report_users',
     'ReportDeviceHardwareStatus': 'device_reporting.report_hardware_status',
     'ReportDeviceSessionStatus': 'device_reporting.report_session_status',
@@ -27342,7 +27410,9 @@
         'ReportDeviceActivityTimes',
         'ReportDeviceAudioStatus',
         'ReportDeviceLocation',
+        'ReportDeviceNetworkConfiguration',
         'ReportDeviceNetworkInterfaces',
+        'ReportDeviceNetworkStatus',
         'ReportDeviceHardwareStatus',
         'ReportDeviceSessionStatus',
         'ReportDeviceGraphicsStatus',
@@ -27453,6 +27523,6 @@
   'placeholders': [],
   'deleted_policy_ids': [114, 115, 204, 205, 206, 412, 476, 544, 546, 562, 569, 578, 583, 585, 586, 587, 588, 589, 590, 591, 600, 668, 669],
   'deleted_atomic_policy_group_ids': [19],
-  'highest_id_currently_used': 874,
+  'highest_id_currently_used': 876,
   'highest_atomic_group_id_currently_used': 40
 }
diff --git a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos_unittest.cc b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos_unittest.cc
index fc463a9..2b850c0 100644
--- a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos_unittest.cc
+++ b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos_unittest.cc
@@ -10,7 +10,6 @@
 #include <string>
 #include <utility>
 
-#include "ash/components/account_manager/account_manager_ash.h"
 #include "base/bind.h"
 #include "base/containers/contains.h"
 #include "base/files/scoped_temp_dir.h"
@@ -22,6 +21,7 @@
 #include "components/account_manager_core/account_manager_facade.h"
 #include "components/account_manager_core/account_manager_facade_impl.h"
 #include "components/account_manager_core/chromeos/account_manager.h"
+#include "components/account_manager_core/chromeos/account_manager_ash.h"
 #include "components/signin/internal/identity_manager/account_tracker_service.h"
 #include "components/signin/internal/identity_manager/profile_oauth2_token_service_observer.h"
 #include "components/signin/public/base/signin_pref_names.h"
diff --git a/components/signin/internal/identity_manager/test_profile_oauth2_token_service_delegate_chromeos.cc b/components/signin/internal/identity_manager/test_profile_oauth2_token_service_delegate_chromeos.cc
index 68bf347..4b2b1ecb 100644
--- a/components/signin/internal/identity_manager/test_profile_oauth2_token_service_delegate_chromeos.cc
+++ b/components/signin/internal/identity_manager/test_profile_oauth2_token_service_delegate_chromeos.cc
@@ -6,8 +6,8 @@
 
 #include <limits>
 
-#include "ash/components/account_manager/account_manager_ash.h"
 #include "components/account_manager_core/account_manager_facade_impl.h"
+#include "components/account_manager_core/chromeos/account_manager_ash.h"
 #include "google_apis/gaia/oauth2_access_token_fetcher.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
diff --git a/components/signin/public/base/signin_metrics.h b/components/signin/public/base/signin_metrics.h
index 2b822515..c99fc42690 100644
--- a/components/signin/public/base/signin_metrics.h
+++ b/components/signin/public/base/signin_metrics.h
@@ -309,16 +309,6 @@
   kMaxValue = kFetchLstOnly,
 };
 
-// Enum values used for use with the "Signin.Reauth" histogram.
-enum AccountReauth {
-  // The user gave the wrong email when doing a reauthentication.
-  HISTOGRAM_ACCOUNT_MISSMATCH,
-  // The user was shown a reauthentication login screen.
-  HISTOGRAM_REAUTH_SHOWN,
-
-  HISTOGRAM_REAUTH_MAX
-};
-
 // Enum values used for "Signin.AccountReconcilorState.OnGaiaResponse"
 // histogram, which records the state of the AccountReconcilor when GAIA returns
 // a specific response.
diff --git a/components/signin/public/identity_manager/identity_manager_builder_unittest.cc b/components/signin/public/identity_manager/identity_manager_builder_unittest.cc
index ebfb428..3f40219 100644
--- a/components/signin/public/identity_manager/identity_manager_builder_unittest.cc
+++ b/components/signin/public/identity_manager/identity_manager_builder_unittest.cc
@@ -27,6 +27,7 @@
 #include "ash/components/account_manager/account_manager_factory.h"
 #include "components/account_manager_core/account_manager_facade_impl.h"
 #include "components/account_manager_core/chromeos/account_manager.h"
+#include "components/account_manager_core/chromeos/account_manager_ash.h"
 #endif
 
 #if defined(OS_IOS)
diff --git a/components/sync/protocol/vault.proto b/components/sync/protocol/vault.proto
index 6c5b514..5bdf3b5c 100644
--- a/components/sync/protocol/vault.proto
+++ b/components/sync/protocol/vault.proto
@@ -66,3 +66,7 @@
 message JoinSecurityDomainsResponse {
   SecurityDomain security_domain = 1;
 }
+
+message JoinSecurityDomainsErrorDetail {
+  JoinSecurityDomainsResponse already_exists_response = 1;
+}
\ No newline at end of file
diff --git a/components/sync/trusted_vault/download_keys_response_handler.cc b/components/sync/trusted_vault/download_keys_response_handler.cc
index 55121f6..5922ddb5 100644
--- a/components/sync/trusted_vault/download_keys_response_handler.cc
+++ b/components/sync/trusted_vault/download_keys_response_handler.cc
@@ -161,6 +161,7 @@
           /*status=*/TrustedVaultDownloadKeysStatus::
               kMemberNotFoundOrCorrupted);
     case TrustedVaultRequest::HttpStatus::kBadRequest:
+    case TrustedVaultRequest::HttpStatus::kConflict:
     case TrustedVaultRequest::HttpStatus::kOtherError:
       return ProcessedResponse(
           /*status=*/TrustedVaultDownloadKeysStatus::kOtherError);
diff --git a/components/sync/trusted_vault/download_keys_response_handler_unittest.cc b/components/sync/trusted_vault/download_keys_response_handler_unittest.cc
index 102e7da..9089cbd6 100644
--- a/components/sync/trusted_vault/download_keys_response_handler_unittest.cc
+++ b/components/sync/trusted_vault/download_keys_response_handler_unittest.cc
@@ -118,6 +118,13 @@
   EXPECT_THAT(
       handler()
           .ProcessResponse(
+              /*http_status=*/TrustedVaultRequest::HttpStatus::kConflict,
+              /*response_body=*/std::string())
+          .status,
+      Eq(TrustedVaultDownloadKeysStatus::kOtherError));
+  EXPECT_THAT(
+      handler()
+          .ProcessResponse(
               /*http_status=*/TrustedVaultRequest::HttpStatus::kOtherError,
               /*response_body=*/std::string())
           .status,
diff --git a/components/sync/trusted_vault/standalone_trusted_vault_backend.cc b/components/sync/trusted_vault/standalone_trusted_vault_backend.cc
index 1f0f623..d02ec92 100644
--- a/components/sync/trusted_vault/standalone_trusted_vault_backend.cc
+++ b/components/sync/trusted_vault/standalone_trusted_vault_backend.cc
@@ -532,6 +532,9 @@
 
   switch (status) {
     case TrustedVaultRegistrationStatus::kSuccess:
+    case TrustedVaultRegistrationStatus::kAlreadyRegistered:
+      // kAlreadyRegistered handled as success, because it only means that
+      // client doesn't fully handled successful device registration before.
       per_user_vault->mutable_local_device_registration_info()
           ->set_device_registered(true);
       WriteToDisk(data_, file_path_);
@@ -566,13 +569,27 @@
   // no local keys available. Detected server-side key should be stored upon
   // successful completion, but |vault_key| emptiness still needs to be checked
   // before that - there might be StoreKeys() call during handling the request.
-  if (status == TrustedVaultRegistrationStatus::kSuccess &&
-      per_user_vault->vault_key().empty()) {
-    AssignBytesToProtoString(
-        vault_key_and_version.key,
-        per_user_vault->add_vault_key()->mutable_key_material());
-    per_user_vault->set_last_vault_key_version(vault_key_and_version.version);
-    // WriteToDisk() will be called by OnDeviceRegistered().
+  switch (status) {
+    case TrustedVaultRegistrationStatus::kSuccess:
+    case TrustedVaultRegistrationStatus::kAlreadyRegistered:
+      // This method can be called only if device registration was triggered
+      // while no local keys available. Detected server-side key should be
+      // stored upon successful completion (or if device was already registered,
+      // e.g. previous response wasn't handled properly), but |vault_key|
+      // emptiness still needs to be checked before that - there might be
+      // StoreKeys() call during handling the request.
+      if (per_user_vault->vault_key().empty()) {
+        AssignBytesToProtoString(
+            vault_key_and_version.key,
+            per_user_vault->add_vault_key()->mutable_key_material());
+        per_user_vault->set_last_vault_key_version(
+            vault_key_and_version.version);
+        // WriteToDisk() will be called by OnDeviceRegistered().
+      }
+      break;
+    case TrustedVaultRegistrationStatus::kLocalDataObsolete:
+    case TrustedVaultRegistrationStatus::kOtherError:
+      break;
   }
   OnDeviceRegistered(status);
 }
diff --git a/components/sync/trusted_vault/trusted_vault_connection.h b/components/sync/trusted_vault/trusted_vault_connection.h
index fdd8ff4..046afdab 100644
--- a/components/sync/trusted_vault/trusted_vault_connection.h
+++ b/components/sync/trusted_vault/trusted_vault_connection.h
@@ -20,6 +20,9 @@
 
 enum class TrustedVaultRegistrationStatus {
   kSuccess,
+  // Used when member corresponding to authentication factor already exists and
+  // local keys that were sent as part of the request aren't stale.
+  kAlreadyRegistered,
   // Used when trusted vault request can't be completed successfully due to
   // vault key being outdated or device key being not registered.
   kLocalDataObsolete,
diff --git a/components/sync/trusted_vault/trusted_vault_connection_impl.cc b/components/sync/trusted_vault/trusted_vault_connection_impl.cc
index 190f0f2..683c824 100644
--- a/components/sync/trusted_vault/trusted_vault_connection_impl.cc
+++ b/components/sync/trusted_vault/trusted_vault_connection_impl.cc
@@ -125,6 +125,7 @@
     const std::string& response_body) {
   switch (http_status) {
     case TrustedVaultRequest::HttpStatus::kSuccess:
+    case TrustedVaultRequest::HttpStatus::kConflict:
       break;
     case TrustedVaultRequest::HttpStatus::kOtherError:
       std::move(callback).Run(TrustedVaultRegistrationStatus::kOtherError,
@@ -140,7 +141,15 @@
   }
 
   sync_pb::JoinSecurityDomainsResponse response;
-  if (!response.ParseFromString(response_body)) {
+  if (http_status == TrustedVaultRequest::HttpStatus::kConflict) {
+    sync_pb::JoinSecurityDomainsErrorDetail error_detail;
+    if (!error_detail.ParseFromString(response_body)) {
+      std::move(callback).Run(TrustedVaultRegistrationStatus::kOtherError,
+                              /*last_key_version=*/0);
+      return;
+    }
+    response = error_detail.already_exists_response();
+  } else if (!response.ParseFromString(response_body)) {
     std::move(callback).Run(TrustedVaultRegistrationStatus::kOtherError,
                             /*last_key_version=*/0);
     return;
@@ -153,8 +162,11 @@
                             /*last_key_version=*/0);
     return;
   }
-  std::move(callback).Run(TrustedVaultRegistrationStatus::kSuccess,
-                          last_key_version);
+  std::move(callback).Run(
+      http_status == TrustedVaultRequest::HttpStatus::kConflict
+          ? TrustedVaultRegistrationStatus::kAlreadyRegistered
+          : TrustedVaultRegistrationStatus::kSuccess,
+      last_key_version);
 }
 
 void ProcessDownloadKeysResponse(
@@ -181,6 +193,7 @@
     case TrustedVaultRequest::HttpStatus::kOtherError:
     case TrustedVaultRequest::HttpStatus::kNotFound:
     case TrustedVaultRequest::HttpStatus::kBadRequest:
+    case TrustedVaultRequest::HttpStatus::kConflict:
       std::move(callback).Run(TrustedVaultRecoverabilityStatus::kError);
       return;
   }
diff --git a/components/sync/trusted_vault/trusted_vault_connection_impl_unittest.cc b/components/sync/trusted_vault/trusted_vault_connection_impl_unittest.cc
index 2a82fd8..7c2b9600 100644
--- a/components/sync/trusted_vault/trusted_vault_connection_impl_unittest.cc
+++ b/components/sync/trusted_vault/trusted_vault_connection_impl_unittest.cc
@@ -386,6 +386,32 @@
 }
 
 TEST_F(TrustedVaultConnectionImplTest,
+       ShouldHandleJoinSecurityDomainsResponseWithConflictError) {
+  std::unique_ptr<SecureBoxKeyPair> key_pair = MakeTestKeyPair();
+  ASSERT_THAT(key_pair, NotNull());
+
+  base::MockCallback<TrustedVaultConnection::RegisterDeviceWithoutKeysCallback>
+      callback;
+
+  std::unique_ptr<TrustedVaultConnection::Request> request =
+      connection()->RegisterDeviceWithoutKeys(
+          /*account_info=*/CoreAccountInfo(), key_pair->public_key(),
+          callback.Get());
+  ASSERT_THAT(request, NotNull());
+
+  const int kServerConstantKeyVersion = 100;
+  EXPECT_CALL(callback,
+              Run(Eq(TrustedVaultRegistrationStatus::kAlreadyRegistered),
+                  TrustedVaultKeyAndVersionEq(GetConstantTrustedVaultKey(),
+                                              kServerConstantKeyVersion)));
+  sync_pb::JoinSecurityDomainsErrorDetail response;
+  *response.mutable_already_exists_response() = MakeJoinSecurityDomainsResponse(
+      /*current_epoch=*/kServerConstantKeyVersion);
+  EXPECT_TRUE(RespondToJoinSecurityDomainsRequest(
+      net::HTTP_CONFLICT, response.SerializeAsString()));
+}
+
+TEST_F(TrustedVaultConnectionImplTest,
        ShouldHandleJoinSecurityDomainsRequestWithEmptyResponse) {
   std::unique_ptr<SecureBoxKeyPair> key_pair = MakeTestKeyPair();
   ASSERT_THAT(key_pair, NotNull());
diff --git a/components/sync/trusted_vault/trusted_vault_request.cc b/components/sync/trusted_vault/trusted_vault_request.cc
index ce34efe0..b920b46cc 100644
--- a/components/sync/trusted_vault/trusted_vault_request.cc
+++ b/components/sync/trusted_vault/trusted_vault_request.cc
@@ -132,25 +132,31 @@
       "Sync.TrustedVaultURLFetchResponse",
       http_response_code == 0 ? net_error : http_response_code);
 
+  std::string response_content = response_body ? *response_body : std::string();
   if (http_response_code == net::HTTP_BAD_REQUEST) {
     RunCompletionCallbackAndMaybeDestroySelf(HttpStatus::kBadRequest,
-                                             std::string());
+                                             response_content);
     return;
   }
   if (http_response_code == net::HTTP_NOT_FOUND) {
     RunCompletionCallbackAndMaybeDestroySelf(HttpStatus::kNotFound,
-                                             std::string());
+                                             response_content);
+    return;
+  }
+  if (http_response_code == net::HTTP_CONFLICT) {
+    RunCompletionCallbackAndMaybeDestroySelf(HttpStatus::kConflict,
+                                             response_content);
     return;
   }
 
   if (http_response_code != net::HTTP_OK &&
       http_response_code != net::HTTP_NO_CONTENT) {
     RunCompletionCallbackAndMaybeDestroySelf(HttpStatus::kOtherError,
-                                             std::string());
+                                             response_content);
     return;
   }
   RunCompletionCallbackAndMaybeDestroySelf(HttpStatus::kSuccess,
-                                           *response_body);
+                                           response_content);
 }
 
 std::unique_ptr<network::SimpleURLLoader> TrustedVaultRequest::CreateURLLoader(
@@ -172,6 +178,7 @@
       network::SimpleURLLoader::Create(std::move(request),
                                        CreateTrafficAnnotationTag());
 
+  url_loader->SetAllowHttpErrorResults(true);
   // TODO(crbug.com/1113598): do we need to set retry options? (in particular
   // RETRY_ON_NETWORK_CHANGE).
 
diff --git a/components/sync/trusted_vault/trusted_vault_request.h b/components/sync/trusted_vault/trusted_vault_request.h
index fcc6fe0f..d797865 100644
--- a/components/sync/trusted_vault/trusted_vault_request.h
+++ b/components/sync/trusted_vault/trusted_vault_request.h
@@ -39,6 +39,8 @@
     kBadRequest,
     // Reported when server returns http status code 404 (not found).
     kNotFound,
+    // Reported when server returns http status code 409 (conflict).
+    kConflict,
     // Reported when other error occurs: unable to fetch access token, network
     // and http errors (except 400 and 404).
     kOtherError
diff --git a/components/sync/trusted_vault/trusted_vault_request_unittest.cc b/components/sync/trusted_vault/trusted_vault_request_unittest.cc
index 761e9d7..9c46308 100644
--- a/components/sync/trusted_vault/trusted_vault_request_unittest.cc
+++ b/components/sync/trusted_vault/trusted_vault_request_unittest.cc
@@ -242,6 +242,20 @@
                                    /*response_body=*/""));
 }
 
+TEST_F(TrustedVaultRequestTest,
+       ShouldHandleConflictStatusAndPopulateResponseBody) {
+  base::MockCallback<TrustedVaultRequest::CompletionCallback>
+      completion_callback;
+  std::unique_ptr<TrustedVaultRequest> request = StartNewRequestWithAccessToken(
+      kAccessToken, TrustedVaultRequest::HttpMethod::kGet,
+      /*request_body=*/absl::nullopt, completion_callback.Get());
+
+  // |completion_callback| should be called after receiving response.
+  EXPECT_CALL(completion_callback,
+              Run(TrustedVaultRequest::HttpStatus::kConflict, kResponseBody));
+  EXPECT_TRUE(RespondToHttpRequest(net::OK, net::HTTP_CONFLICT, kResponseBody));
+}
+
 TEST_F(TrustedVaultRequestTest, ShouldHandleNotFoundStatus) {
   base::MockCallback<TrustedVaultRequest::CompletionCallback>
       completion_callback;
diff --git a/components/test/data/autofill/heuristics/output/049_register_ebay.com.out b/components/test/data/autofill/heuristics/output/049_register_ebay.com.out
index f661c073..7e29d4c 100644
--- a/components/test/data/autofill/heuristics/output/049_register_ebay.com.out
+++ b/components/test/data/autofill/heuristics/output/049_register_ebay.com.out
@@ -20,8 +20,35 @@
 UNKNOWN_TYPE | birthdate2 | Date of birth, Month | 0 | firstname_1-default
 UNKNOWN_TYPE | birthdate1 | Date of birth, Day | 0 | firstname_1-default
 UNKNOWN_TYPE | birthdate3 | Year of birth, four digit format. | 0 | firstname_1-default
-UNKNOWN_TYPE | tokentext | For added security - opens in a new window or tab, please enter the verification code hidden in the image. |  | firstname_1-default
-UNKNOWN_TYPE | acceptq1 | I agree that:I accept the User Agreement - opens in a new window or tab and Privacy Policy.I may receive communications from eBay and can change my notification preferences in My eBay.I'm at least 18 years old. | 1 | firstname_1-default
+NAME_FIRST | firstname | First name |  | firstname_2-default
+NAME_LAST | lastname | Last name |  | firstname_2-default
+ADDRESS_HOME_LINE1 | address1 | Street address |  | firstname_2-default
+ADDRESS_HOME_LINE2 | address2 | Street address continued. Apartment number, floor number, suite number, etc. - optional |  | firstname_2-default
+ADDRESS_HOME_CITY | city | City |  | firstname_2-default
+ADDRESS_HOME_STATE | state | State / Province | default | firstname_2-default
+ADDRESS_HOME_ZIP | zip | ZIP / Postal code |  | firstname_2-default
+ADDRESS_HOME_COUNTRY | countryId | Country or region | 1 | firstname_2-default
+PHONE_HOME_CITY_CODE | dayphone1 | Primary telephone number |  | firstname_2-default
+PHONE_HOME_NUMBER | dayphone2 | Primary telephone number |  | firstname_2-default
+PHONE_HOME_NUMBER | dayphone3 | Primary telephone number |  | firstname_2-default
+PHONE_HOME_EXTENSION | dayphone4 | ext.: |  | firstname_2-default
+EMAIL_ADDRESS | email | Email address |  | firstname_2-default
+EMAIL_ADDRESS | retype_email | Re-enter email address |  | firstname_2-default
+UNKNOWN_TYPE | userid | Create your eBay user ID |  | firstname_2-default
+UNKNOWN_TYPE | pass | Create your password |  | firstname_2-default
+UNKNOWN_TYPE | rpass | Re-enter your password |  | firstname_2-default
+UNKNOWN_TYPE | canned | Pick a secret question | 0 | firstname_2-default
+UNKNOWN_TYPE | myanswer | Your secret answer |  | firstname_2-default
+UNKNOWN_TYPE | birthdate2 | Date of birth, Month | 0 | firstname_2-default
+UNKNOWN_TYPE | birthdate1 | Date of birth, Day | 0 | firstname_2-default
+UNKNOWN_TYPE | birthdate3 | Year of birth, four digit format. | 0 | firstname_2-default
+UNKNOWN_TYPE | tokentext | For added security - opens in a new window or tab, please enter the verification code hidden in the image. |  | firstname_2-default
+UNKNOWN_TYPE | acceptq1 | I agree that:I accept the User Agreement - opens in a new window or tab and Privacy Policy.I may receive communications from eBay and can change my notification preferences in My eBay.I'm at least 18 years old. | 1 | firstname_2-default
+UNKNOWN_TYPE | uword1 | Give us some word and we'll suggest some user IDs for you. Word 1 |  | firstname_2-default
+UNKNOWN_TYPE | uword2 | Word 2 |  | firstname_2-default
+UNKNOWN_TYPE | uword3 | Word 3 |  | firstname_2-default
+UNKNOWN_TYPE | tokentext | For added security - opens in a new window or tab, please enter the verification code hidden in the image. |  | firstname_2-default
+UNKNOWN_TYPE | acceptq1 | I agree that:I accept the User Agreement - opens in a new window or tab and Privacy Policy.I may receive communications from eBay and can change my notification preferences in My eBay.I'm at least 18 years old. | 1 | firstname_2-default
 UNKNOWN_TYPE | uword1 | Give us some word and we'll suggest some user IDs for you. Word 1 |  | uword1_1-default
 UNKNOWN_TYPE | uword2 | Word 2 |  | uword1_1-default
 UNKNOWN_TYPE | uword3 | Word 3 |  | uword1_1-default
diff --git a/components/viz/service/compositor_frame_fuzzer/compositor_frame_fuzzer_util.cc b/components/viz/service/compositor_frame_fuzzer/compositor_frame_fuzzer_util.cc
index dbdc8f5..34e5e9d 100644
--- a/components/viz/service/compositor_frame_fuzzer/compositor_frame_fuzzer_util.cc
+++ b/components/viz/service/compositor_frame_fuzzer/compositor_frame_fuzzer_util.cc
@@ -36,7 +36,8 @@
 // Normalizes value to a float in [0, 1]. Use to convert a fuzzed
 // uint32 into a percentage.
 float Normalize(uint32_t x) {
-  return static_cast<float>(x) / std::numeric_limits<uint32_t>::max();
+  return static_cast<float>(x) /
+         static_cast<float>(std::numeric_limits<uint32_t>::max());
 }
 
 gfx::Size GetSizeFromProtobuf(const proto::Size& proto_size) {
diff --git a/components/viz/service/display_embedder/skia_output_device_buffer_queue_unittest.cc b/components/viz/service/display_embedder/skia_output_device_buffer_queue_unittest.cc
index 725fd78..8c6d2778 100644
--- a/components/viz/service/display_embedder/skia_output_device_buffer_queue_unittest.cc
+++ b/components/viz/service/display_embedder/skia_output_device_buffer_queue_unittest.cc
@@ -301,7 +301,8 @@
         dependency_->GetGpuFeatureInfo(),
         dependency_->GetSharedContextState().get(),
         dependency_->GetMailboxManager(), dependency_->GetSharedImageManager(),
-        dependency_->GetGpuImageFactory(), memory_tracker_.get(), true),
+        dependency_->GetGpuImageFactory(), memory_tracker_.get(),
+        /*enable_wrapped_sk_image=*/true, /*is_for_display_compositor=*/true),
     shared_image_factory_->RegisterSharedImageBackingFactoryForTesting(
         &test_backing_factory_);
     shared_image_representation_factory_ =
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
index 16c8595a..288c33e 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -433,7 +433,8 @@
       deps->GetGpuFeatureInfo(), deps->GetSharedContextState().get(),
       deps->GetMailboxManager(), deps->GetSharedImageManager(),
       deps->GetGpuImageFactory(), memory_tracker,
-      true /* enable_wrapped_sk_image */);
+      /*enable_wrapped_sk_image=*/true,
+      /*is_for_display_compositor=*/true);
 }
 
 std::unique_ptr<gpu::SharedImageRepresentationFactory>
diff --git a/content/browser/background_fetch/background_fetch_context.cc b/content/browser/background_fetch/background_fetch_context.cc
index 9207f8f..84c8485 100644
--- a/content/browser/background_fetch/background_fetch_context.cc
+++ b/content/browser/background_fetch/background_fetch_context.cc
@@ -17,6 +17,7 @@
 #include "content/browser/background_fetch/background_fetch_request_match_params.h"
 #include "content/browser/background_fetch/background_fetch_scheduler.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/browser/storage_partition_impl.h"
 #include "content/common/background_fetch/background_fetch_types.h"
 #include "content/public/browser/background_fetch_delegate.h"
 #include "content/public/browser/browser_context.h"
@@ -31,27 +32,25 @@
 using FailureReason = blink::mojom::BackgroundFetchFailureReason;
 
 BackgroundFetchContext::BackgroundFetchContext(
-    BrowserContext* browser_context,
-    StoragePartition* storage_partition,
+    base::WeakPtr<StoragePartitionImpl> storage_partition,
     const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context,
     scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
     scoped_refptr<DevToolsBackgroundServicesContextImpl> devtools_context)
     : base::RefCountedDeleteOnSequence<BackgroundFetchContext>(
           BrowserThread::GetTaskRunnerForThread(
               ServiceWorkerContext::GetCoreThreadId())),
-      browser_context_(browser_context),
       service_worker_context_(service_worker_context),
       devtools_context_(std::move(devtools_context)),
       registration_notifier_(
           std::make_unique<BackgroundFetchRegistrationNotifier>()),
-      delegate_proxy_(browser_context_) {
+      delegate_proxy_(storage_partition) {
   // Although this lives only on the service worker core thread, it is
   // constructed on UI thread.
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(service_worker_context_);
 
   data_manager_ = std::make_unique<BackgroundFetchDataManager>(
-      browser_context_, storage_partition, service_worker_context,
+      storage_partition, service_worker_context,
       std::move(quota_manager_proxy));
   scheduler_ = std::make_unique<BackgroundFetchScheduler>(
       this, data_manager_.get(), registration_notifier_.get(), &delegate_proxy_,
diff --git a/content/browser/background_fetch/background_fetch_context.h b/content/browser/background_fetch/background_fetch_context.h
index a069a850..0b7fe97 100644
--- a/content/browser/background_fetch/background_fetch_context.h
+++ b/content/browser/background_fetch/background_fetch_context.h
@@ -34,8 +34,8 @@
 class BackgroundFetchRegistrationNotifier;
 class BackgroundFetchRequestMatchParams;
 class BackgroundFetchScheduler;
-class BrowserContext;
 class ServiceWorkerContextWrapper;
+class StoragePartitionImpl;
 
 // The BackgroundFetchContext is the central moderator of ongoing background
 // fetch requests from the Mojo service and from other callers.
@@ -51,8 +51,7 @@
   // The BackgroundFetchContext will watch the ServiceWorkerContextWrapper so
   // that it can respond to service worker events such as unregister.
   BackgroundFetchContext(
-      BrowserContext* browser_context,
-      StoragePartition* storage_partition,
+      base::WeakPtr<StoragePartitionImpl> storage_partition,
       const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context,
       scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
       scoped_refptr<DevToolsBackgroundServicesContextImpl> devtools_context);
@@ -195,9 +194,6 @@
                         int frame_tree_node_id,
                         BackgroundFetchPermission permission);
 
-  // |this| is owned, indirectly, by the BrowserContext.
-  BrowserContext* browser_context_;
-
   std::unique_ptr<BackgroundFetchDataManager> data_manager_;
   scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
   scoped_refptr<DevToolsBackgroundServicesContextImpl> devtools_context_;
diff --git a/content/browser/background_fetch/background_fetch_data_manager.cc b/content/browser/background_fetch/background_fetch_data_manager.cc
index 878eed8..d47e90c1 100644
--- a/content/browser/background_fetch/background_fetch_data_manager.cc
+++ b/content/browser/background_fetch/background_fetch_data_manager.cc
@@ -38,20 +38,19 @@
 namespace content {
 
 BackgroundFetchDataManager::BackgroundFetchDataManager(
-    BrowserContext* browser_context,
-    StoragePartition* storage_partition,
+    base::WeakPtr<StoragePartitionImpl> storage_partition,
     scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
     scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy)
     : service_worker_context_(std::move(service_worker_context)),
-      storage_partition_(storage_partition),
+      storage_partition_(std::move(storage_partition)),
       quota_manager_proxy_(std::move(quota_manager_proxy)) {
   // Constructed on the UI thread, then used on the service worker core thread.
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(browser_context);
+  DCHECK(storage_partition_);
 
   // Store the blob storage context for the given |browser_context|.
-  blob_storage_context_ =
-      base::WrapRefCounted(ChromeBlobStorageContext::GetFor(browser_context));
+  blob_storage_context_ = base::WrapRefCounted(
+      ChromeBlobStorageContext::GetFor(storage_partition_->browser_context()));
   DCHECK(blob_storage_context_);
 }
 
@@ -89,6 +88,9 @@
     return it->second;
   }
 
+  if (!storage_partition_)
+    return null_remote_;
+
   // This storage key and unique_id has never been opened before.
   mojo::Remote<blink::mojom::CacheStorage> remote;
   network::CrossOriginEmbedderPolicy cross_origin_embedder_policy;
@@ -109,6 +111,9 @@
     int64_t trace_id,
     blink::mojom::CacheStorage::OpenCallback callback) {
   auto& cache_storage = GetOrOpenCacheStorage(storage_key, unique_id);
+  if (!cache_storage)
+    return;
+
   cache_storage->Open(base::UTF8ToUTF16(unique_id), trace_id,
                       std::move(callback));
 }
@@ -119,6 +124,8 @@
     int64_t trace_id,
     blink::mojom::CacheStorage::DeleteCallback callback) {
   auto& cache_storage = GetOrOpenCacheStorage(storage_key, unique_id);
+  if (!cache_storage)
+    return;
   cache_storage->Delete(
       base::UTF8ToUTF16(unique_id), trace_id,
       base::BindOnce(&BackgroundFetchDataManager::DidDeleteCache,
@@ -142,6 +149,8 @@
     int64_t trace_id,
     blink::mojom::CacheStorage::HasCallback callback) {
   auto& cache_storage = GetOrOpenCacheStorage(storage_key, unique_id);
+  if (!cache_storage)
+    return;
   cache_storage->Has(base::UTF8ToUTF16(unique_id), trace_id,
                      std::move(callback));
 }
diff --git a/content/browser/background_fetch/background_fetch_data_manager.h b/content/browser/background_fetch/background_fetch_data_manager.h
index 5822baa..98ec751 100644
--- a/content/browser/background_fetch/background_fetch_data_manager.h
+++ b/content/browser/background_fetch/background_fetch_data_manager.h
@@ -17,6 +17,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "content/browser/background_fetch/background_fetch.pb.h"
 #include "content/browser/background_fetch/background_fetch_registration_id.h"
@@ -38,10 +39,9 @@
 class BackgroundFetchDataManagerObserver;
 class BackgroundFetchRequestInfo;
 class BackgroundFetchRequestMatchParams;
-class BrowserContext;
 class ChromeBlobStorageContext;
 class ServiceWorkerContextWrapper;
-class StoragePartition;
+class StoragePartitionImpl;
 
 // The BackgroundFetchDataManager is a wrapper around persistent storage (the
 // Service Worker database), exposing APIs for the read and write queries needed
@@ -84,8 +84,7 @@
                               scoped_refptr<BackgroundFetchRequestInfo>)>;
 
   BackgroundFetchDataManager(
-      BrowserContext* browser_context,
-      StoragePartition* storage_partition,
+      base::WeakPtr<StoragePartitionImpl> storage_partition,
       scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
       scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy);
 
@@ -244,9 +243,7 @@
 
   scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
 
-  // BackgroundFetchDataManager is owned by BackgroundFetchContext which
-  // itself is owned by the StoragePartitionImpl.
-  StoragePartition* storage_partition_;
+  base::WeakPtr<StoragePartitionImpl> storage_partition_;
 
   scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;
 
@@ -272,6 +269,7 @@
   // TODO(crbug.com/711354): Possibly update key when CORS support is added.
   std::map<std::string, mojo::Remote<blink::mojom::CacheStorage>>
       cache_storage_remote_map_;
+  mojo::Remote<blink::mojom::CacheStorage> null_remote_;
 
   base::WeakPtrFactory<BackgroundFetchDataManager> weak_ptr_factory_{this};
 
diff --git a/content/browser/background_fetch/background_fetch_delegate_proxy.cc b/content/browser/background_fetch/background_fetch_delegate_proxy.cc
index 72a5ffd..31188f67 100644
--- a/content/browser/background_fetch/background_fetch_delegate_proxy.cc
+++ b/content/browser/background_fetch/background_fetch_delegate_proxy.cc
@@ -11,6 +11,7 @@
 #include "components/download/public/common/download_url_parameters.h"
 #include "content/browser/background_fetch/background_fetch_job_controller.h"
 #include "content/browser/permissions/permission_controller_impl.h"
+#include "content/browser/storage_partition_impl.h"
 #include "content/public/browser/background_fetch_description.h"
 #include "content/public/browser/background_fetch_response.h"
 #include "content/public/browser/browser_context.h"
@@ -29,11 +30,12 @@
 class BackgroundFetchDelegateProxy::Core
     : public BackgroundFetchDelegate::Client {
  public:
-  Core(const base::WeakPtr<BackgroundFetchDelegateProxy>& parent,
-       BrowserContext* browser_context)
-      : parent_(parent), browser_context_(browser_context) {
+  Core(base::WeakPtr<BackgroundFetchDelegateProxy> parent,
+       base::WeakPtr<StoragePartitionImpl> storage_partition)
+      : parent_(std::move(parent)),
+        storage_partition_(std::move(storage_partition)) {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
-    DCHECK(browser_context_);
+    DCHECK(storage_partition_);
   }
 
   ~Core() override { DCHECK_CURRENTLY_ON(BrowserThread::UI); }
@@ -58,8 +60,7 @@
 
     BackgroundFetchPermission result = BackgroundFetchPermission::BLOCKED;
 
-    if (auto* controller =
-            PermissionControllerImpl::FromBrowserContext(browser_context_)) {
+    if (auto* controller = GetPermissionController()) {
       content::WebContents* web_contents =
           wc_getter ? wc_getter.Run() : nullptr;
       content::RenderFrameHost* rfh =
@@ -101,7 +102,7 @@
       BackgroundFetchDelegate::GetIconDisplaySizeCallback callback) {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-    if (auto* delegate = browser_context_->GetBackgroundFetchDelegate()) {
+    if (auto* delegate = GetDelegate()) {
       delegate->GetIconDisplaySize(
           base::BindOnce(&Core::ForwardGetIconDisplaySizeCallbackToParentThread,
                          weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
@@ -116,7 +117,7 @@
       std::unique_ptr<BackgroundFetchDescription> fetch_description) {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-    auto* delegate = browser_context_->GetBackgroundFetchDelegate();
+    auto* delegate = GetDelegate();
     if (delegate)
       delegate->CreateDownloadJob(GetWeakPtrOnUI(),
                                   std::move(fetch_description));
@@ -128,7 +129,7 @@
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
     DCHECK(request);
 
-    auto* delegate = browser_context_->GetBackgroundFetchDelegate();
+    auto* delegate = GetDelegate();
     if (!delegate)
       return;
 
@@ -189,14 +190,14 @@
   void Abort(const std::string& job_unique_id) {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-    if (auto* delegate = browser_context_->GetBackgroundFetchDelegate())
+    if (auto* delegate = GetDelegate())
       delegate->Abort(job_unique_id);
   }
 
   void MarkJobComplete(const std::string& job_unique_id) {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-    if (auto* delegate = browser_context_->GetBackgroundFetchDelegate())
+    if (auto* delegate = GetDelegate())
       delegate->MarkJobComplete(job_unique_id);
   }
 
@@ -205,7 +206,7 @@
                 const absl::optional<SkBitmap>& icon) {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-    if (auto* delegate = browser_context_->GetBackgroundFetchDelegate())
+    if (auto* delegate = GetDelegate())
       delegate->UpdateUI(job_unique_id, title, icon);
   }
 
@@ -233,10 +234,30 @@
       BackgroundFetchDelegate::GetUploadDataCallback callback) override;
 
  private:
+  BrowserContext* GetBrowserContext() {
+    if (!storage_partition_)
+      return nullptr;
+    return storage_partition_->browser_context();
+  }
+
+  BackgroundFetchDelegate* GetDelegate() {
+    auto* browser_context = GetBrowserContext();
+    if (!browser_context)
+      return nullptr;
+    return browser_context->GetBackgroundFetchDelegate();
+  }
+
+  PermissionControllerImpl* GetPermissionController() {
+    auto* browser_context = GetBrowserContext();
+    if (!browser_context)
+      return nullptr;
+    return PermissionControllerImpl::FromBrowserContext(browser_context);
+  }
+
   // Weak reference to the service worker core thread outer class that owns us.
   base::WeakPtr<BackgroundFetchDelegateProxy> parent_;
 
-  BrowserContext* browser_context_;
+  base::WeakPtr<StoragePartitionImpl> storage_partition_;
 
   base::WeakPtrFactory<Core> weak_ptr_factory_{this};
 
@@ -334,13 +355,14 @@
 }
 
 BackgroundFetchDelegateProxy::BackgroundFetchDelegateProxy(
-    BrowserContext* browser_context) {
+    base::WeakPtr<StoragePartitionImpl> storage_partition) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // Normally it would be unsafe to obtain a weak pointer on the UI thread from
   // a factory that lives on the service worker core thread, but it's ok in the
   // constructor as |this| can't be destroyed before the constructor finishes.
-  ui_core_.reset(new Core(weak_ptr_factory_.GetWeakPtr(), browser_context));
+  ui_core_.reset(
+      new Core(weak_ptr_factory_.GetWeakPtr(), std::move(storage_partition)));
 
   // Since this constructor runs on the UI thread, a WeakPtr can be safely
   // obtained from the Core.
diff --git a/content/browser/background_fetch/background_fetch_delegate_proxy.h b/content/browser/background_fetch/background_fetch_delegate_proxy.h
index e2dc8741..4b2ca68 100644
--- a/content/browser/background_fetch/background_fetch_delegate_proxy.h
+++ b/content/browser/background_fetch/background_fetch_delegate_proxy.h
@@ -26,7 +26,7 @@
 
 namespace content {
 
-class BrowserContext;
+class StoragePartitionImpl;
 
 // Proxy class for passing messages between BackgroundFetchJobControllers on the
 // service worker core thread and BackgroundFetchDelegate on the UI thread.
@@ -74,7 +74,8 @@
     virtual ~Controller() = default;
   };
 
-  explicit BackgroundFetchDelegateProxy(BrowserContext* browser_context);
+  explicit BackgroundFetchDelegateProxy(
+      base::WeakPtr<StoragePartitionImpl> storage_partition);
 
   ~BackgroundFetchDelegateProxy();
 
@@ -129,6 +130,9 @@
   // Called when the fetch associated |job_unique_id| is completed.
   void MarkJobComplete(const std::string& job_unique_id);
 
+  // Called when the shutdown flow has been initiated.
+  void Shutdown();
+
  private:
   class Core;
 
diff --git a/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc b/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc
index 95cb3e69..571d4d1d 100644
--- a/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc
+++ b/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
 #include "content/browser/background_fetch/background_fetch_test_base.h"
+#include "content/browser/storage_partition_impl.h"
 #include "content/public/browser/background_fetch_delegate.h"
 #include "content/public/browser/background_fetch_description.h"
 #include "content/public/browser/background_fetch_response.h"
@@ -169,7 +170,11 @@
 
 class BackgroundFetchDelegateProxyTest : public BackgroundFetchTestBase {
  public:
-  BackgroundFetchDelegateProxyTest() : delegate_proxy_(&browser_context_) {
+  BackgroundFetchDelegateProxyTest()
+      : storage_partition_factory_(static_cast<StoragePartitionImpl*>(
+            browser_context_.GetDefaultStoragePartition())) {
+    delegate_proxy_ = std::make_unique<BackgroundFetchDelegateProxy>(
+        storage_partition_factory_.GetWeakPtr());
     delegate_ = browser_context_.GetBackgroundFetchDelegate();
   }
   void DidGetIconDisplaySize(base::OnceClosure quit_closure,
@@ -183,7 +188,8 @@
  protected:
   FakeTestBrowserContext browser_context_;
   FakeBackgroundFetchDelegate* delegate_;
-  BackgroundFetchDelegateProxy delegate_proxy_;
+  std::unique_ptr<BackgroundFetchDelegateProxy> delegate_proxy_;
+  base::WeakPtrFactory<StoragePartitionImpl> storage_partition_factory_;
 };
 
 scoped_refptr<BackgroundFetchRequestInfo> CreateRequestInfo(
@@ -213,10 +219,10 @@
       /* download_total= */ 0u, /* upload_total= */ 0u,
       /* outstanding_guids= */ std::vector<std::string>(),
       /* start_paused= */ false);
-  delegate_proxy_.CreateDownloadJob(controller.weak_ptr_factory_.GetWeakPtr(),
-                                    std::move(fetch_description));
+  delegate_proxy_->CreateDownloadJob(controller.weak_ptr_factory_.GetWeakPtr(),
+                                     std::move(fetch_description));
 
-  delegate_proxy_.StartRequest(kExampleUniqueId, url::Origin(), request);
+  delegate_proxy_->StartRequest(kExampleUniqueId, url::Origin(), request);
   base::RunLoop().RunUntilIdle();
 
   EXPECT_TRUE(controller.request_started_);
@@ -240,10 +246,10 @@
       /* download_total= */ 0u, /* upload_total= */ 0u,
       /* outstanding_guids= */ std::vector<std::string>(),
       /* start_paused= */ false);
-  delegate_proxy_.CreateDownloadJob(controller.weak_ptr_factory_.GetWeakPtr(),
-                                    std::move(fetch_description));
+  delegate_proxy_->CreateDownloadJob(controller.weak_ptr_factory_.GetWeakPtr(),
+                                     std::move(fetch_description));
 
-  delegate_proxy_.StartRequest(kExampleUniqueId, url::Origin(), request);
+  delegate_proxy_->StartRequest(kExampleUniqueId, url::Origin(), request);
   base::RunLoop().RunUntilIdle();
 
   EXPECT_TRUE(controller.request_started_);
@@ -272,8 +278,8 @@
       /* download_total= */ 0u, /* upload_total= */ 0u,
       /* outstanding_guids= */ std::vector<std::string>(),
       /* start_paused= */ false);
-  delegate_proxy_.CreateDownloadJob(controller.weak_ptr_factory_.GetWeakPtr(),
-                                    std::move(fetch_description1));
+  delegate_proxy_->CreateDownloadJob(controller.weak_ptr_factory_.GetWeakPtr(),
+                                     std::move(fetch_description1));
 
   auto fetch_description2 = std::make_unique<BackgroundFetchDescription>(
       kExampleUniqueId2, url::Origin(), /* title= */ "Job 2", SkBitmap(),
@@ -282,12 +288,12 @@
       /* download_total= */ 0u, /* upload_total= */ 0u,
       /* outstanding_guids= */ std::vector<std::string>(),
       /* start_paused= */ false);
-  delegate_proxy_.CreateDownloadJob(controller2.weak_ptr_factory_.GetWeakPtr(),
-                                    std::move(fetch_description2));
+  delegate_proxy_->CreateDownloadJob(controller2.weak_ptr_factory_.GetWeakPtr(),
+                                     std::move(fetch_description2));
 
-  delegate_proxy_.StartRequest(kExampleUniqueId, url::Origin(), request);
-  delegate_proxy_.StartRequest(kExampleUniqueId2, url::Origin(), request2);
-  delegate_proxy_.Abort(kExampleUniqueId);
+  delegate_proxy_->StartRequest(kExampleUniqueId, url::Origin(), request);
+  delegate_proxy_->StartRequest(kExampleUniqueId2, url::Origin(), request2);
+  delegate_proxy_->Abort(kExampleUniqueId);
   base::RunLoop().RunUntilIdle();
 
   EXPECT_FALSE(controller.request_completed_) << "Aborted job completed";
@@ -298,7 +304,7 @@
 TEST_F(BackgroundFetchDelegateProxyTest, GetIconDisplaySize) {
   gfx::Size out_display_size;
   base::RunLoop run_loop;
-  delegate_proxy_.GetIconDisplaySize(base::BindOnce(
+  delegate_proxy_->GetIconDisplaySize(base::BindOnce(
       &BackgroundFetchDelegateProxyTest::DidGetIconDisplaySize,
       base::Unretained(this), run_loop.QuitClosure(), &out_display_size));
   run_loop.Run();
@@ -321,17 +327,17 @@
       /* outstanding_guids= */ std::vector<std::string>(),
       /* start_paused= */ false);
 
-  delegate_proxy_.CreateDownloadJob(controller.weak_ptr_factory_.GetWeakPtr(),
-                                    std::move(fetch_description));
+  delegate_proxy_->CreateDownloadJob(controller.weak_ptr_factory_.GetWeakPtr(),
+                                     std::move(fetch_description));
 
-  delegate_proxy_.StartRequest(kExampleUniqueId, url::Origin(), request);
+  delegate_proxy_->StartRequest(kExampleUniqueId, url::Origin(), request);
   base::RunLoop().RunUntilIdle();
 
   EXPECT_TRUE(controller.request_started_);
   EXPECT_TRUE(controller.request_completed_);
 
-  delegate_proxy_.UpdateUI(kExampleUniqueId, "Job 1 Complete!", absl::nullopt,
-                           base::DoNothing());
+  delegate_proxy_->UpdateUI(kExampleUniqueId, "Job 1 Complete!", absl::nullopt,
+                            base::DoNothing());
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(delegate_->ui_update_count_, 1);
 }
@@ -343,8 +349,10 @@
   EXPECT_FALSE(controller2.request_started_);
   EXPECT_FALSE(controller2.request_completed_);
 
-  BackgroundFetchDelegateProxy delegate_proxy1(&browser_context_);
-  BackgroundFetchDelegateProxy delegate_proxy2(&browser_context_);
+  BackgroundFetchDelegateProxy delegate_proxy1(
+      storage_partition_factory_.GetWeakPtr());
+  BackgroundFetchDelegateProxy delegate_proxy2(
+      storage_partition_factory_.GetWeakPtr());
 
   auto fetch_description1 = std::make_unique<BackgroundFetchDescription>(
       kExampleUniqueId, url::Origin(), /* title= */ "Job 1", SkBitmap(),
diff --git a/content/browser/background_fetch/background_fetch_event_dispatcher_unittest.cc b/content/browser/background_fetch/background_fetch_event_dispatcher_unittest.cc
index 774e501d..aed59242 100644
--- a/content/browser/background_fetch/background_fetch_event_dispatcher_unittest.cc
+++ b/content/browser/background_fetch/background_fetch_event_dispatcher_unittest.cc
@@ -35,8 +35,7 @@
   void SetUp() override {
     BackgroundFetchTestBase::SetUp();
     auto* background_fetch_context =
-        static_cast<StoragePartitionImpl*>(storage_partition())
-            ->GetBackgroundFetchContext();
+        storage_partition()->GetBackgroundFetchContext();
     event_dispatcher_ = std::make_unique<BackgroundFetchEventDispatcher>(
         background_fetch_context,
         embedded_worker_test_helper()->context_wrapper(),
diff --git a/content/browser/background_fetch/background_fetch_job_controller_unittest.cc b/content/browser/background_fetch/background_fetch_job_controller_unittest.cc
index f562e785..f42b363 100644
--- a/content/browser/background_fetch/background_fetch_job_controller_unittest.cc
+++ b/content/browser/background_fetch/background_fetch_job_controller_unittest.cc
@@ -178,14 +178,11 @@
   void SetUp() override {
     BackgroundFetchTestBase::SetUp();
 
-    StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
-        browser_context()->GetDefaultStoragePartition());
-
     delegate_proxy_ =
-        std::make_unique<BackgroundFetchDelegateProxy>(browser_context());
+        std::make_unique<BackgroundFetchDelegateProxy>(storage_partition());
 
     context_ = base::MakeRefCounted<BackgroundFetchContext>(
-        browser_context(), partition,
+        storage_partition(),
         base::WrapRefCounted(embedded_worker_test_helper()->context_wrapper()),
         /* quota_manager_proxy= */ nullptr, devtools_context());
   }
diff --git a/content/browser/background_fetch/background_fetch_scheduler_unittest.cc b/content/browser/background_fetch/background_fetch_scheduler_unittest.cc
index 327af89..32b88d2d 100644
--- a/content/browser/background_fetch/background_fetch_scheduler_unittest.cc
+++ b/content/browser/background_fetch/background_fetch_scheduler_unittest.cc
@@ -81,11 +81,10 @@
     data_manager_->InitializeOnCoreThread();
 
     delegate_proxy_ =
-        std::make_unique<BackgroundFetchDelegateProxy>(browser_context());
+        std::make_unique<BackgroundFetchDelegateProxy>(storage_partition());
 
     auto* background_fetch_context =
-        static_cast<StoragePartitionImpl*>(storage_partition())
-            ->GetBackgroundFetchContext();
+        storage_partition()->GetBackgroundFetchContext();
     scheduler_ = std::make_unique<BackgroundFetchScheduler>(
         background_fetch_context, data_manager_.get(), nullptr,
         delegate_proxy_.get(), devtools_context().get(),
diff --git a/content/browser/background_fetch/background_fetch_service_unittest.cc b/content/browser/background_fetch/background_fetch_service_unittest.cc
index 259d20f..5a93282 100644
--- a/content/browser/background_fetch/background_fetch_service_unittest.cc
+++ b/content/browser/background_fetch/background_fetch_service_unittest.cc
@@ -282,7 +282,7 @@
     BackgroundFetchTestBase::SetUp();
 
     context_ = base::MakeRefCounted<BackgroundFetchContext>(
-        browser_context(), storage_partition(),
+        storage_partition(),
         base::WrapRefCounted(embedded_worker_test_helper()->context_wrapper()),
         /* quota_manager_proxy= */ nullptr, devtools_context());
     context_->SetDataManagerForTesting(
diff --git a/content/browser/background_fetch/background_fetch_test_base.cc b/content/browser/background_fetch/background_fetch_test_base.cc
index 062294b..17f02a6 100644
--- a/content/browser/background_fetch/background_fetch_test_base.cc
+++ b/content/browser/background_fetch/background_fetch_test_base.cc
@@ -82,7 +82,8 @@
       delegate_(browser_context_.GetBackgroundFetchDelegate()),
       embedded_worker_test_helper_(base::FilePath()),
       storage_key_(blink::StorageKey(url::Origin::Create(GURL(kTestOrigin)))),
-      storage_partition_(browser_context()->GetDefaultStoragePartition()) {}
+      storage_partition_factory_(static_cast<StoragePartitionImpl*>(
+          browser_context()->GetDefaultStoragePartition())) {}
 
 BackgroundFetchTestBase::~BackgroundFetchTestBase() {
   DCHECK(set_up_called_);
@@ -199,10 +200,8 @@
 }
 
 scoped_refptr<DevToolsBackgroundServicesContextImpl>
-BackgroundFetchTestBase::devtools_context() const {
-  DCHECK(storage_partition_);
-  return static_cast<StoragePartitionImpl*>(storage_partition_)
-      ->GetDevToolsBackgroundServicesContext();
+BackgroundFetchTestBase::devtools_context() {
+  return storage_partition()->GetDevToolsBackgroundServicesContext();
 }
 
 }  // namespace content
diff --git a/content/browser/background_fetch/background_fetch_test_base.h b/content/browser/background_fetch/background_fetch_test_base.h
index 6d6aad3b2..4f8a309f 100644
--- a/content/browser/background_fetch/background_fetch_test_base.h
+++ b/content/browser/background_fetch/background_fetch_test_base.h
@@ -12,6 +12,7 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
 #include "content/browser/background_fetch/background_fetch_test_browser_context.h"
 #include "content/browser/background_fetch/background_fetch_test_service_worker.h"
 #include "content/browser/devtools/devtools_background_services_context_impl.h"
@@ -24,7 +25,7 @@
 namespace content {
 
 class ServiceWorkerRegistration;
-class StoragePartition;
+class StoragePartitionImpl;
 
 // Base class containing common functionality needed in unit tests written for
 // the Background Fetch feature.
@@ -77,13 +78,15 @@
   TestBrowserContext* browser_context() { return &browser_context_; }
 
   // Returns the once-initialized default storage partition to be used in tests.
-  StoragePartition* storage_partition() { return storage_partition_; }
+  base::WeakPtr<StoragePartitionImpl> storage_partition() {
+    return storage_partition_factory_.GetWeakPtr();
+  }
 
   // Returns the storage key that should be used for Background Fetch tests.
   const blink::StorageKey& storage_key() const { return storage_key_; }
 
   // Returns the DevTools context for logging events.
-  scoped_refptr<DevToolsBackgroundServicesContextImpl> devtools_context() const;
+  scoped_refptr<DevToolsBackgroundServicesContextImpl> devtools_context();
 
  protected:
   BrowserTaskEnvironment task_environment_;  // Must be first member.
@@ -97,7 +100,7 @@
 
   blink::StorageKey storage_key_;
 
-  StoragePartition* storage_partition_;
+  base::WeakPtrFactory<StoragePartitionImpl> storage_partition_factory_;
 
   int next_pattern_id_ = 0;
 
diff --git a/content/browser/background_fetch/background_fetch_test_data_manager.cc b/content/browser/background_fetch/background_fetch_test_data_manager.cc
index c430671..837f75ad4 100644
--- a/content/browser/background_fetch/background_fetch_test_data_manager.cc
+++ b/content/browser/background_fetch/background_fetch_test_data_manager.cc
@@ -10,9 +10,9 @@
 #include "components/services/storage/public/mojom/quota_client.mojom.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/browser/storage_partition_impl.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/storage_partition.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "storage/browser/blob/blob_storage_context.h"
 #include "storage/browser/test/mock_quota_manager.h"
@@ -62,10 +62,9 @@
 
 BackgroundFetchTestDataManager::BackgroundFetchTestDataManager(
     BrowserContext* browser_context,
-    StoragePartition* storage_partition,
+    base::WeakPtr<StoragePartitionImpl> storage_partition,
     scoped_refptr<ServiceWorkerContextWrapper> service_worker_context)
-    : BackgroundFetchDataManager(browser_context,
-                                 storage_partition,
+    : BackgroundFetchDataManager(storage_partition,
                                  service_worker_context,
                                  /* quota_manager_proxy= */ nullptr),
       browser_context_(browser_context),
diff --git a/content/browser/background_fetch/background_fetch_test_data_manager.h b/content/browser/background_fetch/background_fetch_test_data_manager.h
index d23c8cc..a1e91d1 100644
--- a/content/browser/background_fetch/background_fetch_test_data_manager.h
+++ b/content/browser/background_fetch/background_fetch_test_data_manager.h
@@ -6,6 +6,7 @@
 #define CONTENT_BROWSER_BACKGROUND_FETCH_BACKGROUND_FETCH_TEST_DATA_MANAGER_H_
 
 #include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
 #include "content/browser/background_fetch/background_fetch_data_manager.h"
 #include "content/browser/background_fetch/background_fetch_request_info.h"
 
@@ -19,7 +20,7 @@
 class CacheStorageManager;
 class ChromeBlobStorageContext;
 class ServiceWorkerContextWrapper;
-class StoragePartition;
+class StoragePartitionImpl;
 
 // Arbitrary quota that is large enough for test purposes.
 constexpr uint64_t kBackgroundFetchMaxQuotaBytes = 424242u;
@@ -31,7 +32,7 @@
  public:
   BackgroundFetchTestDataManager(
       BrowserContext* browser_context,
-      StoragePartition* storage_partition,
+      base::WeakPtr<StoragePartitionImpl> storage_partition,
       scoped_refptr<ServiceWorkerContextWrapper> service_worker_context);
 
   ~BackgroundFetchTestDataManager() override;
@@ -43,7 +44,7 @@
 
   scoped_refptr<storage::MockQuotaManager> mock_quota_manager_;
   BrowserContext* browser_context_;
-  StoragePartition* storage_partition_;
+  base::WeakPtr<StoragePartition> storage_partition_;
   scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
 
   DISALLOW_COPY_AND_ASSIGN(BackgroundFetchTestDataManager);
diff --git a/content/browser/conversions/conversion_host.cc b/content/browser/conversions/conversion_host.cc
index fa96075c..c006787 100644
--- a/content/browser/conversions/conversion_host.cc
+++ b/content/browser/conversions/conversion_host.cc
@@ -4,6 +4,8 @@
 
 #include "content/browser/conversions/conversion_host.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/check.h"
@@ -255,7 +257,7 @@
       source_type, impression.priority,
       /*impression_id=*/absl::nullopt);
 
-  conversion_manager.HandleImpression(storable_impression);
+  conversion_manager.HandleImpression(std::move(storable_impression));
 }
 
 void ConversionHost::RegisterConversion(
@@ -311,7 +313,7 @@
 
   if (conversion_page_metrics_)
     conversion_page_metrics_->OnConversion(storable_conversion);
-  conversion_manager->HandleConversion(storable_conversion);
+  conversion_manager->HandleConversion(std::move(storable_conversion));
 }
 
 void ConversionHost::NotifyImpressionNavigationInitiatedByPage() {
diff --git a/content/browser/conversions/conversion_manager.h b/content/browser/conversions/conversion_manager.h
index 2234f04..56944a99 100644
--- a/content/browser/conversions/conversion_manager.h
+++ b/content/browser/conversions/conversion_manager.h
@@ -44,11 +44,11 @@
 
   // Persists the given |impression| to storage. Called when a navigation
   // originating from an impression tag finishes.
-  virtual void HandleImpression(const StorableImpression& impression) = 0;
+  virtual void HandleImpression(StorableImpression impression) = 0;
 
   // Process a newly registered conversion. Will create and log any new
   // conversion reports to storage.
-  virtual void HandleConversion(const StorableConversion& conversion) = 0;
+  virtual void HandleConversion(StorableConversion conversion) = 0;
 
   // Get all impressions that are currently stored in this partition. Used for
   // populating WebUI.
diff --git a/content/browser/conversions/conversion_manager_impl.cc b/content/browser/conversions/conversion_manager_impl.cc
index f706085..0ff2fab8 100644
--- a/content/browser/conversions/conversion_manager_impl.cc
+++ b/content/browser/conversions/conversion_manager_impl.cc
@@ -151,23 +151,21 @@
           &IsOriginSessionOnly, std::move(special_storage_policy_));
   conversion_storage_.AsyncCall(&ConversionStorage::ClearData)
       .WithArgs(base::Time::Min(), base::Time::Max(),
-                session_only_origin_predicate);
+                std::move(session_only_origin_predicate));
 }
 
-void ConversionManagerImpl::HandleImpression(
-    const StorableImpression& impression) {
+void ConversionManagerImpl::HandleImpression(StorableImpression impression) {
   // Add the impression to storage.
   conversion_storage_.AsyncCall(&ConversionStorage::StoreImpression)
-      .WithArgs(impression);
+      .WithArgs(std::move(impression));
 }
 
-void ConversionManagerImpl::HandleConversion(
-    const StorableConversion& conversion) {
+void ConversionManagerImpl::HandleConversion(StorableConversion conversion) {
   // TODO(https://crbug.com/1043345): Add UMA for the number of conversions we
   // are logging to storage, and the number of new reports logged to storage.
   conversion_storage_
       .AsyncCall(&ConversionStorage::MaybeCreateAndStoreConversionReport)
-      .WithArgs(conversion)
+      .WithArgs(std::move(conversion))
       .Then(base::DoNothing::Once<bool>());
 
   // If we are running in debug mode, we should also schedule a task to
diff --git a/content/browser/conversions/conversion_manager_impl.h b/content/browser/conversions/conversion_manager_impl.h
index 1fb7c4b..ec41ddf 100644
--- a/content/browser/conversions/conversion_manager_impl.h
+++ b/content/browser/conversions/conversion_manager_impl.h
@@ -95,8 +95,8 @@
   ~ConversionManagerImpl() override;
 
   // ConversionManager:
-  void HandleImpression(const StorableImpression& impression) override;
-  void HandleConversion(const StorableConversion& conversion) override;
+  void HandleImpression(StorableImpression impression) override;
+  void HandleConversion(StorableConversion conversion) override;
   void GetActiveImpressionsForWebUI(
       base::OnceCallback<void(std::vector<StorableImpression>)> callback)
       override;
diff --git a/content/browser/conversions/conversion_test_utils.cc b/content/browser/conversions/conversion_test_utils.cc
index da40b28b..4d6267a 100644
--- a/content/browser/conversions/conversion_test_utils.cc
+++ b/content/browser/conversions/conversion_test_utils.cc
@@ -125,16 +125,14 @@
 
 TestConversionManager::~TestConversionManager() = default;
 
-void TestConversionManager::HandleImpression(
-    const StorableImpression& impression) {
+void TestConversionManager::HandleImpression(StorableImpression impression) {
   num_impressions_++;
   last_impression_source_type_ = impression.source_type();
   last_impression_origin_ = impression.impression_origin();
   last_attribution_source_priority_ = impression.priority();
 }
 
-void TestConversionManager::HandleConversion(
-    const StorableConversion& conversion) {
+void TestConversionManager::HandleConversion(StorableConversion conversion) {
   num_conversions_++;
 
   last_conversion_destination_ = conversion.conversion_destination();
diff --git a/content/browser/conversions/conversion_test_utils.h b/content/browser/conversions/conversion_test_utils.h
index 896ee1c9..6a3059d8 100644
--- a/content/browser/conversions/conversion_test_utils.h
+++ b/content/browser/conversions/conversion_test_utils.h
@@ -161,8 +161,8 @@
   ~TestConversionManager() override;
 
   // ConversionManager:
-  void HandleImpression(const StorableImpression& impression) override;
-  void HandleConversion(const StorableConversion& conversion) override;
+  void HandleImpression(StorableImpression impression) override;
+  void HandleConversion(StorableConversion conversion) override;
   void GetActiveImpressionsForWebUI(
       base::OnceCallback<void(std::vector<StorableImpression>)> callback)
       override;
diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h
index 2786d89..53d6c25 100644
--- a/content/browser/renderer_host/compositor_impl_android.h
+++ b/content/browser/renderer_host/compositor_impl_android.h
@@ -17,6 +17,7 @@
 #include "cc/paint/element_id.h"
 #include "cc/trees/layer_tree_host_client.h"
 #include "cc/trees/layer_tree_host_single_thread_client.h"
+#include "cc/trees/paint_holding_reason.h"
 #include "components/viz/common/frame_sinks/begin_frame_source.h"
 #include "components/viz/common/surfaces/frame_sink_id.h"
 #include "components/viz/common/surfaces/local_surface_id.h"
@@ -115,7 +116,7 @@
   void DidUpdateLayers() override;
   void BeginMainFrame(const viz::BeginFrameArgs& args) override;
   void OnDeferMainFrameUpdatesChanged(bool) override {}
-  void OnDeferCommitsChanged(bool) override {}
+  void OnDeferCommitsChanged(bool, cc::PaintHoldingReason) override {}
   void BeginMainFrameNotExpectedSoon() override {}
   void BeginMainFrameNotExpectedUntil(base::TimeTicks time) override {}
   void UpdateLayerTreeHost() override;
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index da83acf..a7584ed4 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -1262,7 +1262,7 @@
       browser_context_, service_worker_context_);
 
   background_fetch_context_ = base::MakeRefCounted<BackgroundFetchContext>(
-      browser_context_, this, service_worker_context_, quota_manager_proxy,
+      weak_factory_.GetWeakPtr(), service_worker_context_, quota_manager_proxy,
       devtools_background_services_context_);
 
   background_sync_context_ = base::MakeRefCounted<BackgroundSyncContextImpl>();
diff --git a/content/browser/web_package/prefetched_signed_exchange_cache.cc b/content/browser/web_package/prefetched_signed_exchange_cache.cc
index 86de0450..ca8e0dd 100644
--- a/content/browser/web_package/prefetched_signed_exchange_cache.cc
+++ b/content/browser/web_package/prefetched_signed_exchange_cache.cc
@@ -317,7 +317,8 @@
     options.struct_size = sizeof(MojoCreateDataPipeOptions);
     options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
     options.element_num_bytes = 1;
-    options.capacity_num_bytes = network::kDataPipeDefaultAllocationSize;
+    options.capacity_num_bytes =
+        network::features::GetDataPipeDefaultAllocationSize();
     MojoResult rv = mojo::CreateDataPipe(&options, pipe_producer_handle,
                                          pipe_consumer_handle);
     if (rv != MOJO_RESULT_OK) {
diff --git a/content/browser/web_package/signed_exchange_loader.cc b/content/browser/web_package/signed_exchange_loader.cc
index a96ed057..9009047f 100644
--- a/content/browser/web_package/signed_exchange_loader.cc
+++ b/content/browser/web_package/signed_exchange_loader.cc
@@ -315,7 +315,8 @@
   options.struct_size = sizeof(MojoCreateDataPipeOptions);
   options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
   options.element_num_bytes = 1;
-  options.capacity_num_bytes = network::kDataPipeDefaultAllocationSize;
+  options.capacity_num_bytes =
+      network::features::GetDataPipeDefaultAllocationSize();
   if (mojo::CreateDataPipe(&options, producer_handle, consumer_handle) !=
       MOJO_RESULT_OK) {
     forwarding_client_->OnComplete(
diff --git a/content/browser/web_package/web_bundle_url_loader_factory.cc b/content/browser/web_package/web_bundle_url_loader_factory.cc
index 1a8fc83..f744b1d 100644
--- a/content/browser/web_package/web_bundle_url_loader_factory.cc
+++ b/content/browser/web_package/web_bundle_url_loader_factory.cc
@@ -23,6 +23,7 @@
 #include "net/http/http_status_code.h"
 #include "net/http/http_util.h"
 #include "services/network/public/cpp/constants.h"
+#include "services/network/public/cpp/features.h"
 #include "services/network/public/mojom/url_loader.mojom.h"
 #include "services/network/public/mojom/url_response_head.mojom.h"
 #include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
@@ -134,7 +135,8 @@
     options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
     options.element_num_bytes = 1;
     options.capacity_num_bytes =
-        std::min(static_cast<uint64_t>(network::kDataPipeDefaultAllocationSize),
+        std::min(base::strict_cast<uint64_t>(
+                     network::features::GetDataPipeDefaultAllocationSize()),
                  response->payload_length);
 
     auto result =
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
index cb80a2b..4a7bcdb 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
@@ -272,11 +272,12 @@
 [ fuchsia fuchsia-board-astro ] conformance/canvas/drawingbuffer-static-canvas-test.html [ Failure ]
 crbug.com/1145861 [ fuchsia fuchsia-board-astro ] conformance/textures/misc/texture-corner-case-videos.html [ Failure ]
 crbug.com/1145861 [ fuchsia fuchsia-board-astro ] conformance/textures/misc/texture-npot-video.html [ Failure ]
-crbug.com/1210953 [ fuchsia fuchsia-board-astro ] conformance/textures/canvas/tex-2d-rgb-rgb-unsigned_short_5_6_5.html [ RetryOnFailure ]
+crbug.com/1210953 [ fuchsia fuchsia-board-astro ] conformance/textures/canvas/tex-2d-rgb-rgb-unsigned_short_5_6_5.html [ Failure ]
 crbug.com/1210953 [ fuchsia fuchsia-board-astro ] conformance/textures/canvas/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html [ RetryOnFailure ]
-crbug.com/1210953 [ fuchsia fuchsia-board-astro ] conformance/textures/canvas/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html [ RetryOnFailure ]
+crbug.com/1210953 [ fuchsia fuchsia-board-astro ] conformance/textures/canvas/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html [ Failure ]
 crbug.com/1210953 [ fuchsia fuchsia-board-astro ] conformance/textures/canvas/tex-2d-alpha-alpha-unsigned_byte.html [ RetryOnFailure ]
 crbug.com/1210953 [ fuchsia fuchsia-board-astro ] conformance/textures/canvas/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ RetryOnFailure ]
+crbug.com/1210953 [ fuchsia fuchsia-board-astro ] conformance/textures/canvas/tex-2d-luminance-luminance-unsigned_byte.html [ RetryOnFailure ]
 
 # GPU or renderer process crashes / Timed out tests
 crbug.com/1175419 [ fuchsia ] conformance/extensions/khr-parallel-shader-compile.html [ Skip ]
diff --git a/device/bluetooth/bluetooth_low_energy_scan_filter.cc b/device/bluetooth/bluetooth_low_energy_scan_filter.cc
index d20855e..a07d8c9 100644
--- a/device/bluetooth/bluetooth_low_energy_scan_filter.cc
+++ b/device/bluetooth/bluetooth_low_energy_scan_filter.cc
@@ -4,6 +4,8 @@
 
 #include "device/bluetooth/bluetooth_low_energy_scan_filter.h"
 
+#include "base/memory/ptr_util.h"
+
 namespace device {
 
 BluetoothLowEnergyScanFilter::Pattern::Pattern(
@@ -17,22 +19,32 @@
 BluetoothLowEnergyScanFilter::Pattern::Pattern(const Pattern&) = default;
 BluetoothLowEnergyScanFilter::Pattern::~Pattern() = default;
 
+// static
+std::unique_ptr<BluetoothLowEnergyScanFilter>
+BluetoothLowEnergyScanFilter::Create(
+    int16_t device_found_rssi_threshold,
+    int16_t device_lost_rssi_threshold,
+    base::TimeDelta device_found_timeout,
+    base::TimeDelta device_lost_timeout,
+    const std::vector<BluetoothLowEnergyScanFilter::Pattern>& patterns) {
+  // We use WrapUnique() here so that we can call the private constructor.
+  return base::WrapUnique(new BluetoothLowEnergyScanFilter(
+      device_found_rssi_threshold, device_lost_rssi_threshold,
+      device_found_timeout, device_lost_timeout, patterns));
+}
+
 BluetoothLowEnergyScanFilter::BluetoothLowEnergyScanFilter(
-    int16_t device_found_threshold,
-    uint16_t device_found_timeout,
-    int16_t device_lost_threshold,
-    uint16_t device_lost_timeout)
-    : device_found_threshold_(device_found_threshold),
+    int16_t device_found_rssi_threshold,
+    int16_t device_lost_rssi_threshold,
+    base::TimeDelta device_found_timeout,
+    base::TimeDelta device_lost_timeout,
+    std::vector<Pattern> patterns)
+    : device_found_rssi_threshold_(device_found_rssi_threshold),
+      device_lost_rssi_threshold_(device_lost_rssi_threshold),
       device_found_timeout_(device_found_timeout),
-      device_lost_threshold_(device_lost_threshold),
-      device_lost_timeout_(device_lost_timeout) {}
+      device_lost_timeout_(device_lost_timeout),
+      patterns_(patterns) {}
 
 BluetoothLowEnergyScanFilter::~BluetoothLowEnergyScanFilter() = default;
 
-void BluetoothLowEnergyScanFilter::AddPattern(uint8_t start_position,
-                                              AdvertisementDataType data_type,
-                                              std::vector<uint8_t> value) {
-  patterns_.emplace_back(start_position, data_type, value);
-}
-
 }  // namespace device
diff --git a/device/bluetooth/bluetooth_low_energy_scan_filter.h b/device/bluetooth/bluetooth_low_energy_scan_filter.h
index ad080ba..0af0b31 100644
--- a/device/bluetooth/bluetooth_low_energy_scan_filter.h
+++ b/device/bluetooth/bluetooth_low_energy_scan_filter.h
@@ -8,6 +8,8 @@
 #include <stddef.h>
 #include <stdint.h>
 #include <vector>
+
+#include "base/time/time.h"
 #include "device/bluetooth/bluetooth_export.h"
 
 namespace device {
@@ -48,30 +50,39 @@
     std::vector<uint8_t> value_;
   };
 
-  BluetoothLowEnergyScanFilter(int16_t device_found_threshold,
-                               uint16_t device_found_timeout,
-                               int16_t device_lost_threshold,
-                               uint16_t device_lost_timeout);
+  static std::unique_ptr<BluetoothLowEnergyScanFilter> Create(
+      int16_t device_found_rssi_threshold,
+      int16_t device_lost_rssi_threshold,
+      base::TimeDelta device_found_timeout,
+      base::TimeDelta device_lost_timeout,
+      const std::vector<Pattern>& patterns);
+
   BluetoothLowEnergyScanFilter(const BluetoothLowEnergyScanFilter&) = delete;
   BluetoothLowEnergyScanFilter& operator=(const BluetoothLowEnergyScanFilter&) =
       delete;
   ~BluetoothLowEnergyScanFilter();
 
-  void AddPattern(uint8_t start_position,
-                  AdvertisementDataType data_type,
-                  std::vector<uint8_t> value);
-
-  int16_t device_found_threshold() const { return device_found_threshold_; }
-  uint16_t device_found_timeout() const { return device_found_timeout_; }
-  int16_t device_lost_threshold() const { return device_lost_threshold_; }
-  uint16_t device_lost_timeout() const { return device_lost_timeout_; }
-  const std::vector<Pattern>& patterns() { return patterns_; }
+  int16_t device_found_rssi_threshold() const {
+    return device_found_rssi_threshold_;
+  }
+  int16_t device_lost_rssi_threshold() const {
+    return device_lost_rssi_threshold_;
+  }
+  base::TimeDelta device_found_timeout() const { return device_found_timeout_; }
+  base::TimeDelta device_lost_timeout() const { return device_lost_timeout_; }
+  const std::vector<Pattern>& patterns() const { return patterns_; }
 
  private:
-  int16_t device_found_threshold_;
-  uint16_t device_found_timeout_;
-  int16_t device_lost_threshold_;
-  uint16_t device_lost_timeout_;
+  BluetoothLowEnergyScanFilter(int16_t device_found_rssi_threshold,
+                               int16_t device_lost_rssi_threshold,
+                               base::TimeDelta device_found_timeout,
+                               base::TimeDelta device_lost_timeout,
+                               std::vector<Pattern> patterns);
+
+  int16_t device_found_rssi_threshold_;
+  int16_t device_lost_rssi_threshold_;
+  base::TimeDelta device_found_timeout_;
+  base::TimeDelta device_lost_timeout_;
   std::vector<Pattern> patterns_;
 };
 
diff --git a/device/bluetooth/chromeos/bluetooth_utils.cc b/device/bluetooth/chromeos/bluetooth_utils.cc
index 3910a36..0c309e2 100644
--- a/device/bluetooth/chromeos/bluetooth_utils.cc
+++ b/device/bluetooth/chromeos/bluetooth_utils.cc
@@ -314,4 +314,9 @@
     RecordDeviceSelectionDuration(transport_histogram_name, duration);
   }
 }
+
+void RecordPoweredState(bool is_powered) {
+  base::UmaHistogramBoolean("Bluetooth.ChromeOS.PoweredState", is_powered);
+}
+
 }  // namespace device
diff --git a/device/bluetooth/chromeos/bluetooth_utils.h b/device/bluetooth/chromeos/bluetooth_utils.h
index 3cae624..b345db44 100644
--- a/device/bluetooth/chromeos/bluetooth_utils.h
+++ b/device/bluetooth/chromeos/bluetooth_utils.h
@@ -70,6 +70,9 @@
     bool was_paired,
     BluetoothTransport transport);
 
+// Record each time the local device's Bluetooth is powered on or off.
+DEVICE_BLUETOOTH_EXPORT void RecordPoweredState(bool is_powered);
+
 }  // namespace device
 
 #endif  // DEVICE_BLUETOOTH_CHROMEOS_BLUETOOTH_UTILS_H_
diff --git a/device/bluetooth/dbus/bluetooth_advertisement_monitor_service_provider_impl.cc b/device/bluetooth/dbus/bluetooth_advertisement_monitor_service_provider_impl.cc
index 1b978b7..2a59cd5 100644
--- a/device/bluetooth/dbus/bluetooth_advertisement_monitor_service_provider_impl.cc
+++ b/device/bluetooth/dbus/bluetooth_advertisement_monitor_service_provider_impl.cc
@@ -163,25 +163,28 @@
   array_writer.OpenDictEntry(&dict_entry_writer);
   dict_entry_writer.AppendString(
       bluetooth_advertisement_monitor::kRSSIHighThreshold);
-  dict_entry_writer.AppendVariantOfInt16(filter_->device_found_threshold());
+  dict_entry_writer.AppendVariantOfInt16(
+      filter_->device_found_rssi_threshold());
   array_writer.CloseContainer(&dict_entry_writer);
 
   array_writer.OpenDictEntry(&dict_entry_writer);
   dict_entry_writer.AppendString(
       bluetooth_advertisement_monitor::kRSSIHighTimeout);
-  dict_entry_writer.AppendVariantOfUint16(filter_->device_found_timeout());
+  dict_entry_writer.AppendVariantOfUint16(
+      filter_->device_found_timeout().InSeconds());
   array_writer.CloseContainer(&dict_entry_writer);
 
   array_writer.OpenDictEntry(&dict_entry_writer);
   dict_entry_writer.AppendString(
       bluetooth_advertisement_monitor::kRSSILowThreshold);
-  dict_entry_writer.AppendVariantOfInt16(filter_->device_lost_threshold());
+  dict_entry_writer.AppendVariantOfInt16(filter_->device_lost_rssi_threshold());
   array_writer.CloseContainer(&dict_entry_writer);
 
   array_writer.OpenDictEntry(&dict_entry_writer);
   dict_entry_writer.AppendString(
       bluetooth_advertisement_monitor::kRSSILowTimeout);
-  dict_entry_writer.AppendVariantOfUint16(filter_->device_lost_timeout());
+  dict_entry_writer.AppendVariantOfUint16(
+      filter_->device_lost_timeout().InSeconds());
   array_writer.CloseContainer(&dict_entry_writer);
 
   array_writer.OpenDictEntry(&dict_entry_writer);
diff --git a/extensions/browser/api/declarative/declarative_api.cc b/extensions/browser/api/declarative/declarative_api.cc
index efd16ea..4c0b969 100644
--- a/extensions/browser/api/declarative/declarative_api.cc
+++ b/extensions/browser/api/declarative/declarative_api.cc
@@ -141,11 +141,14 @@
 ExtensionFunction::ResponseAction RulesFunction::Run() {
   EXTENSION_FUNCTION_VALIDATE(CreateParams());
 
-  std::string event_name;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &event_name));
-
-  int web_view_instance_id = 0;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(1, &web_view_instance_id));
+  const auto& list = args_->GetList();
+  EXTENSION_FUNCTION_VALIDATE(list.size() >= 2);
+  const auto& event_name_value = list[0];
+  const auto& web_view_instance_id_value = list[1];
+  EXTENSION_FUNCTION_VALIDATE(event_name_value.is_string());
+  EXTENSION_FUNCTION_VALIDATE(web_view_instance_id_value.is_int());
+  std::string event_name = event_name_value.GetString();
+  int web_view_instance_id = web_view_instance_id_value.GetInt();
 
   EXTENSION_FUNCTION_VALIDATE(extension_);
 
diff --git a/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc b/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc
index 9d8b2b22..68712fc 100644
--- a/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc
+++ b/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc
@@ -285,8 +285,11 @@
   if (!ExtensionFunction::PreRunValidation(error))
     return false;
 
-  int instance_id = 0;
-  EXTENSION_FUNCTION_PRERUN_VALIDATE(args_->GetInteger(0, &instance_id));
+  const auto& list = args_->GetList();
+  EXTENSION_FUNCTION_PRERUN_VALIDATE(list.size() >= 1);
+  const auto& instance_id_value = list[0];
+  EXTENSION_FUNCTION_PRERUN_VALIDATE(instance_id_value.is_int());
+  int instance_id = instance_id_value.GetInt();
   // TODO(780728): Remove crash key once the cause of the kill is known.
   static crash_reporter::CrashKeyString<128> name_key("webview-function");
   crash_reporter::ScopedCrashKeyString name_key_scope(&name_key, name());
@@ -436,18 +439,23 @@
   if (init_result_)
     return init_result_.value();
 
-  if (!args_->GetInteger(0, &guest_instance_id_) || !guest_instance_id_)
+  const auto& list = args_->GetList();
+  if (list.size() < 3)
     return set_init_result(VALIDATION_FAILURE);
 
-  std::string src;
-  if (!args_->GetString(1, &src))
+  guest_instance_id_ = list[0].GetIfInt().value_or(0);
+  if (guest_instance_id_ == 0)
+    return set_init_result(VALIDATION_FAILURE);
+
+  const std::string* src = list[1].GetIfString();
+  if (!src)
     return set_init_result(VALIDATION_FAILURE);
 
   // Set |guest_src_| here, but do not return false if it is invalid.
   // Instead, let it continue with the normal page load sequence,
   // which will result in the usual LOAD_ABORT event in the case where
   // the URL is invalid.
-  guest_src_ = GURL(src);
+  guest_src_ = GURL(*src);
 
   base::DictionaryValue* details_value = NULL;
   if (!args_->GetDictionary(2, &details_value))
diff --git a/extensions/browser/api/idle/idle_api.cc b/extensions/browser/api/idle/idle_api.cc
index ccedd04f..25ce7de 100644
--- a/extensions/browser/api/idle/idle_api.cc
+++ b/extensions/browser/api/idle/idle_api.cc
@@ -34,9 +34,11 @@
 IdleQueryStateFunction::~IdleQueryStateFunction() = default;
 
 ExtensionFunction::ResponseAction IdleQueryStateFunction::Run() {
-  int threshold = 0;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &threshold));
-  threshold = ClampThreshold(threshold);
+  const auto& list = args_->GetList();
+  EXTENSION_FUNCTION_VALIDATE(list.size() >= 1);
+  const auto& threshold_value = list[0];
+  EXTENSION_FUNCTION_VALIDATE(threshold_value.is_int());
+  int threshold = ClampThreshold(threshold_value.GetInt());
 
   ui::IdleState state =
       IdleManagerFactory::GetForBrowserContext(browser_context())
@@ -52,9 +54,11 @@
 IdleSetDetectionIntervalFunction::~IdleSetDetectionIntervalFunction() = default;
 
 ExtensionFunction::ResponseAction IdleSetDetectionIntervalFunction::Run() {
-  int threshold = 0;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &threshold));
-  threshold = ClampThreshold(threshold);
+  const auto& list = args_->GetList();
+  EXTENSION_FUNCTION_VALIDATE(list.size() >= 1);
+  const auto& threshold_value = list[0];
+  EXTENSION_FUNCTION_VALIDATE(threshold_value.is_int());
+  int threshold = ClampThreshold(threshold_value.GetInt());
 
   IdleManagerFactory::GetForBrowserContext(browser_context())
       ->SetThreshold(extension_id(), threshold);
diff --git a/extensions/browser/api/socket/socket_api.cc b/extensions/browser/api/socket/socket_api.cc
index 1c8193d6e..6ef45910 100644
--- a/extensions/browser/api/socket/socket_api.cc
+++ b/extensions/browser/api/socket/socket_api.cc
@@ -248,9 +248,11 @@
 }
 
 ExtensionFunction::ResponseAction SocketDestroyFunction::Work() {
-  int socket_id;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &socket_id));
-  RemoveSocket(socket_id);
+  const auto& list = args_->GetList();
+  EXTENSION_FUNCTION_VALIDATE(list.size() >= 1);
+  const auto& socket_id_value = list[0];
+  EXTENSION_FUNCTION_VALIDATE(socket_id_value.is_int());
+  RemoveSocket(socket_id_value.GetInt());
   return RespondNow(NoArguments());
 }
 
@@ -259,10 +261,18 @@
 SocketConnectFunction::~SocketConnectFunction() = default;
 
 ExtensionFunction::ResponseAction SocketConnectFunction::Work() {
-  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &socket_id_));
-  EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &hostname_));
-  int port;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(2, &port));
+  const auto& list = args_->GetList();
+  EXTENSION_FUNCTION_VALIDATE(list.size() >= 3);
+  const auto& socket_id_value = list[0];
+  const auto& hostname_value = list[1];
+  const auto& port_value = list[2];
+  EXTENSION_FUNCTION_VALIDATE(socket_id_value.is_int());
+  EXTENSION_FUNCTION_VALIDATE(hostname_value.is_string());
+  EXTENSION_FUNCTION_VALIDATE(port_value.is_int());
+  socket_id_ = socket_id_value.GetInt();
+  hostname_ = hostname_value.GetString();
+  int port = port_value.GetInt();
+
   if (!IsPortValid(port)) {
     return RespondNow(Error(kPortInvalidError));
   }
@@ -323,8 +333,11 @@
 }
 
 ExtensionFunction::ResponseAction SocketDisconnectFunction::Work() {
-  int socket_id;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &socket_id));
+  const auto& list = args_->GetList();
+  EXTENSION_FUNCTION_VALIDATE(list.size() >= 1);
+  const auto& socket_id_value = list[0];
+  EXTENSION_FUNCTION_VALIDATE(socket_id_value.is_int());
+  int socket_id = socket_id_value.GetInt();
 
   Socket* socket = GetSocket(socket_id);
   if (socket) {
@@ -339,10 +352,18 @@
 }
 
 ExtensionFunction::ResponseAction SocketBindFunction::Work() {
-  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &socket_id_));
-  EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &address_));
-  int port;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(2, &port));
+  const auto& list = args_->GetList();
+  EXTENSION_FUNCTION_VALIDATE(list.size() >= 3);
+  const auto& socket_id_value = list[0];
+  const auto& address_value = list[1];
+  const auto& port_value = list[2];
+  EXTENSION_FUNCTION_VALIDATE(socket_id_value.is_int());
+  EXTENSION_FUNCTION_VALIDATE(address_value.is_string());
+  EXTENSION_FUNCTION_VALIDATE(port_value.is_int());
+  socket_id_ = socket_id_value.GetInt();
+  address_ = address_value.GetString();
+  int port = port_value.GetInt();
+
   if (!IsPortValid(port)) {
     return RespondNow(Error(kPortInvalidError));
   }
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc
index 60377a2..1e15e033 100644
--- a/extensions/browser/api/web_request/web_request_api.cc
+++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -2573,14 +2573,15 @@
         browser_context(), args_list[2], &extra_info_spec));
   }
 
-  std::string event_name;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetString(3, &event_name));
-
-  std::string sub_event_name;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetString(4, &sub_event_name));
-
-  int web_view_instance_id = 0;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(5, &web_view_instance_id));
+  const auto& event_name_value = args_list[3];
+  const auto& sub_event_name_value = args_list[4];
+  const auto& web_view_instance_id_value = args_list[5];
+  EXTENSION_FUNCTION_VALIDATE(event_name_value.is_string());
+  EXTENSION_FUNCTION_VALIDATE(sub_event_name_value.is_string());
+  EXTENSION_FUNCTION_VALIDATE(web_view_instance_id_value.is_int());
+  std::string event_name = event_name_value.GetString();
+  std::string sub_event_name = sub_event_name_value.GetString();
+  int web_view_instance_id = web_view_instance_id_value.GetInt();
 
   int render_process_id = source_process_id();
 
@@ -2651,19 +2652,24 @@
 
 ExtensionFunction::ResponseAction
 WebRequestInternalEventHandledFunction::Run() {
-  std::string event_name;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &event_name));
+  const auto& list = args_->GetList();
+  EXTENSION_FUNCTION_VALIDATE(list.size() >= 5);
+  const auto& event_name_value = list[0];
+  const auto& sub_event_name_value = list[1];
+  const auto& request_id_str_value = list[2];
+  const auto& web_view_instance_id_value = list[3];
+  EXTENSION_FUNCTION_VALIDATE(event_name_value.is_string());
+  EXTENSION_FUNCTION_VALIDATE(sub_event_name_value.is_string());
+  EXTENSION_FUNCTION_VALIDATE(request_id_str_value.is_string());
+  EXTENSION_FUNCTION_VALIDATE(web_view_instance_id_value.is_int());
+  std::string event_name = event_name_value.GetString();
+  std::string sub_event_name = sub_event_name_value.GetString();
+  std::string request_id_str = request_id_str_value.GetString();
+  int web_view_instance_id = web_view_instance_id_value.GetInt();
 
-  std::string sub_event_name;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &sub_event_name));
-
-  std::string request_id_str;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &request_id_str));
   uint64_t request_id;
   EXTENSION_FUNCTION_VALIDATE(base::StringToUint64(request_id_str,
                                                    &request_id));
-  int web_view_instance_id = 0;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(3, &web_view_instance_id));
 
   int render_process_id = source_process_id();
 
diff --git a/extensions/common/extension.cc b/extensions/common/extension.cc
index 6678fa9..34e6325 100644
--- a/extensions/common/extension.cc
+++ b/extensions/common/extension.cc
@@ -547,6 +547,10 @@
   return manifest()->is_login_screen_extension();
 }
 
+bool Extension::is_chromeos_system_extension() const {
+  return manifest()->is_chromeos_system_extension();
+}
+
 void Extension::AddWebExtentPattern(const URLPattern& pattern) {
   // Bookmark apps are permissionless.
   if (from_bookmark())
diff --git a/extensions/common/extension.h b/extensions/common/extension.h
index ba76bac..db4ac880 100644
--- a/extensions/common/extension.h
+++ b/extensions/common/extension.h
@@ -337,6 +337,7 @@
   bool is_shared_module() const;        // Shared module
   bool is_theme() const;                // Theme
   bool is_login_screen_extension() const;  // Extension on login screen.
+  bool is_chromeos_system_extension() const;  // ChromeOS System Extension.
 
   // True if this is a platform app, hosted app, or legacy packaged app.
   bool is_app() const;
diff --git a/extensions/common/features/feature_provider_unittest.cc b/extensions/common/features/feature_provider_unittest.cc
index 223de38c..0aa35ac 100644
--- a/extensions/common/features/feature_provider_unittest.cc
+++ b/extensions/common/features/feature_provider_unittest.cc
@@ -30,7 +30,7 @@
   ASSERT_TRUE(feature);
   const std::vector<Manifest::Type>& extension_types =
       feature->extension_types();
-  EXPECT_EQ(7u, extension_types.size());
+  EXPECT_EQ(8u, extension_types.size());
   EXPECT_EQ(1, base::STLCount(extension_types, Manifest::TYPE_EXTENSION));
   EXPECT_EQ(
       1, base::STLCount(extension_types, Manifest::TYPE_LEGACY_PACKAGED_APP));
@@ -40,6 +40,8 @@
   EXPECT_EQ(1, base::STLCount(extension_types, Manifest::TYPE_SHARED_MODULE));
   EXPECT_EQ(1, base::STLCount(extension_types,
                               Manifest::TYPE_LOGIN_SCREEN_EXTENSION));
+  EXPECT_EQ(1, base::STLCount(extension_types,
+                              Manifest::TYPE_CHROMEOS_SYSTEM_EXTENSION));
 }
 
 // Tests that real manifest features have the correct availability for an
diff --git a/extensions/common/features/simple_feature.cc b/extensions/common/features/simple_feature.cc
index 8e97b8769..32798bb 100644
--- a/extensions/common/features/simple_feature.cc
+++ b/extensions/common/features/simple_feature.cc
@@ -90,6 +90,8 @@
       return "shared module";
     case Manifest::TYPE_LOGIN_SCREEN_EXTENSION:
       return "login screen extension";
+    case Manifest::TYPE_CHROMEOS_SYSTEM_EXTENSION:
+      return "chromeos system extension";
     case Manifest::NUM_LOAD_TYPES:
       NOTREACHED();
   }
diff --git a/extensions/common/manifest.cc b/extensions/common/manifest.cc
index 2ab063cf..c3d59278 100644
--- a/extensions/common/manifest.cc
+++ b/extensions/common/manifest.cc
@@ -218,6 +218,8 @@
     } else {
       type = TYPE_LEGACY_PACKAGED_APP;
     }
+  } else if (value.HasKey(keys::kChromeOSSystemExtension)) {
+    type = TYPE_CHROMEOS_SYSTEM_EXTENSION;
   } else if (for_login_screen) {
     type = TYPE_LOGIN_SCREEN_EXTENSION;
   } else {
diff --git a/extensions/common/manifest.h b/extensions/common/manifest.h
index 1eff2c2..5077aff 100644
--- a/extensions/common/manifest.h
+++ b/extensions/common/manifest.h
@@ -38,6 +38,7 @@
     TYPE_PLATFORM_APP = 6,
     TYPE_SHARED_MODULE = 7,
     TYPE_LOGIN_SCREEN_EXTENSION = 8,
+    TYPE_CHROMEOS_SYSTEM_EXTENSION = 9,
 
     // New enum values must go above here.
     NUM_LOAD_TYPES
@@ -156,6 +157,9 @@
     return type_ == TYPE_LOGIN_SCREEN_EXTENSION;
   }
   bool is_shared_module() const { return type_ == TYPE_SHARED_MODULE; }
+  bool is_chromeos_system_extension() const {
+    return type_ == TYPE_CHROMEOS_SYSTEM_EXTENSION;
+  }
 
   // These access the wrapped manifest value, returning false when the property
   // does not exist or if the manifest type can't access it.
diff --git a/extensions/common/manifest_constants.cc b/extensions/common/manifest_constants.cc
index 26e3ac7..ee6377c8 100644
--- a/extensions/common/manifest_constants.cc
+++ b/extensions/common/manifest_constants.cc
@@ -32,6 +32,7 @@
 const char kBluetooth[] = "bluetooth";
 const char kBookmarkUI[] = "bookmarks_ui";
 const char kBrowserAction[] = "browser_action";
+const char kChromeOSSystemExtension[] = "chromeos_system_extension";
 const char kCommands[] = "commands";
 const char kContentCapabilities[] = "content_capabilities";
 const char kContentSecurityPolicy[] = "content_security_policy";
diff --git a/extensions/common/manifest_constants.h b/extensions/common/manifest_constants.h
index c544c6e..a4d134e 100644
--- a/extensions/common/manifest_constants.h
+++ b/extensions/common/manifest_constants.h
@@ -35,6 +35,7 @@
 extern const char kBookmarkUI[];
 extern const char kBrowserAction[];
 extern const char kBrowseURLs[];
+extern const char kChromeOSSystemExtension[];
 extern const char kCommands[];
 extern const char kContentCapabilities[];
 extern const char kContentSecurityPolicy[];
diff --git a/google_apis/BUILD.gn b/google_apis/BUILD.gn
index 2f2ec72..457e5c44 100644
--- a/google_apis/BUILD.gn
+++ b/google_apis/BUILD.gn
@@ -174,6 +174,7 @@
   deps = [
     "//net",
     "//services/network/public/cpp",
+    "//services/network/public/mojom",
   ]
 }
 
diff --git a/google_apis/gaia/gaia_auth_fetcher.cc b/google_apis/gaia/gaia_auth_fetcher.cc
index 4f26d0e..b3d30604 100644
--- a/google_apis/gaia/gaia_auth_fetcher.cc
+++ b/google_apis/gaia/gaia_auth_fetcher.cc
@@ -36,6 +36,7 @@
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace {
diff --git a/google_apis/gaia/gaia_oauth_client.cc b/google_apis/gaia/gaia_oauth_client.cc
index 2dae57f..a4c0df2f 100644
--- a/google_apis/gaia/gaia_oauth_client.cc
+++ b/google_apis/gaia/gaia_oauth_client.cc
@@ -27,6 +27,7 @@
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 #include "url/gurl.h"
 
 namespace {
diff --git a/google_apis/gaia/oauth2_access_token_fetcher_impl.cc b/google_apis/gaia/oauth2_access_token_fetcher_impl.cc
index 9226d55c..24c8ecdd 100644
--- a/google_apis/gaia/oauth2_access_token_fetcher_impl.cc
+++ b/google_apis/gaia/oauth2_access_token_fetcher_impl.cc
@@ -21,6 +21,7 @@
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 
 namespace {
 constexpr char kGetAccessTokenBodyFormat[] =
diff --git a/google_apis/gcm/engine/checkin_request.cc b/google_apis/gcm/engine/checkin_request.cc
index 3214b80..83154c5 100644
--- a/google_apis/gcm/engine/checkin_request.cc
+++ b/google_apis/gcm/engine/checkin_request.cc
@@ -15,6 +15,7 @@
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 
 namespace gcm {
 
diff --git a/google_apis/gcm/engine/registration_request.cc b/google_apis/gcm/engine/registration_request.cc
index dab12b2..5e07366 100644
--- a/google_apis/gcm/engine/registration_request.cc
+++ b/google_apis/gcm/engine/registration_request.cc
@@ -22,6 +22,7 @@
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 #include "url/gurl.h"
 
 namespace gcm {
diff --git a/google_apis/gcm/engine/unregistration_request.cc b/google_apis/gcm/engine/unregistration_request.cc
index 47a6493f..8eed4d00 100644
--- a/google_apis/gcm/engine/unregistration_request.cc
+++ b/google_apis/gcm/engine/unregistration_request.cc
@@ -22,6 +22,7 @@
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 
 namespace gcm {
 
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index 8ce915d..1928e03 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -344,6 +344,8 @@
     "command_buffer/tests/gl_set_aggressively_free_resources_unittest.cc",
     "command_buffer/tests/gl_shared_resources_unittest.cc",
     "command_buffer/tests/gl_stream_draw_unittest.cc",
+    "command_buffer/tests/gl_test_setup_helper.cc",
+    "command_buffer/tests/gl_test_setup_helper.h",
     "command_buffer/tests/gl_test_utils.cc",
     "command_buffer/tests/gl_test_utils.h",
     "command_buffer/tests/gl_tests_main.cc",
diff --git a/gpu/command_buffer/client/raster_implementation.cc b/gpu/command_buffer/client/raster_implementation.cc
index 3c57517..c52227671 100644
--- a/gpu/command_buffer/client/raster_implementation.cc
+++ b/gpu/command_buffer/client/raster_implementation.cc
@@ -1211,6 +1211,23 @@
                      << dest_mailbox.ToDebugString() << ", " << xoffset << ", "
                      << yoffset << ", " << x << ", " << y << ", " << width
                      << ", " << height << ")");
+  if (!source_mailbox.IsSharedImage()) {
+    SetGLError(GL_INVALID_VALUE, "glCopySubTexture",
+               "source_mailbox is not a shared image.");
+    // TODO(crbug.com/1229479): This call to NOTREACHED is temporary while we
+    // investigate crbug.com/1229479. The failure with test
+    // WebRtcVideoCaptureServiceBrowserTest.
+    // FramesSentThroughTextureVirtualDeviceGetDisplayedOnPage when OOP-R
+    // Canvas is enabled does not repro on trybots, only on CI bots.
+    // Crashing here will allow us to get a client-side stack trace.
+    NOTREACHED();
+    return;
+  }
+  if (!dest_mailbox.IsSharedImage()) {
+    SetGLError(GL_INVALID_VALUE, "glCopySubTexture",
+               "dest_mailbox is not a shared image.");
+    return;
+  }
   if (width < 0) {
     SetGLError(GL_INVALID_VALUE, "glCopySubTexture", "width < 0");
     return;
diff --git a/gpu/command_buffer/service/shared_image_factory.cc b/gpu/command_buffer/service/shared_image_factory.cc
index dd5759ea..0dd058d3 100644
--- a/gpu/command_buffer/service/shared_image_factory.cc
+++ b/gpu/command_buffer/service/shared_image_factory.cc
@@ -119,11 +119,13 @@
     SharedImageManager* shared_image_manager,
     ImageFactory* image_factory,
     MemoryTracker* memory_tracker,
-    bool enable_wrapped_sk_image)
+    bool enable_wrapped_sk_image,
+    bool is_for_display_compositor)
     : mailbox_manager_(mailbox_manager),
       shared_image_manager_(shared_image_manager),
       shared_context_state_(context_state),
       memory_tracker_(std::make_unique<MemoryTypeTracker>(memory_tracker)),
+      is_for_display_compositor_(is_for_display_compositor),
       gr_context_type_(context_state ? context_state->gr_context_type()
                                      : GrContextType::kGL) {
 #if defined(OS_MAC)
@@ -508,11 +510,12 @@
   // running on a separate thread (which uses a separate GL context or
   // VkDeviceQueue).
   const bool used_by_display_compositor_gpu_thread =
-      (usage & SHARED_IMAGE_USAGE_DISPLAY) &&
+      (usage & SHARED_IMAGE_USAGE_DISPLAY || is_for_display_compositor_) &&
       shared_image_manager_->display_context_on_another_thread();
-  // If it has usage other than DISPLAY, it means that it is used by the
-  // gpu main thread.
-  const bool used_by_main_gpu_thread = usage & ~SHARED_IMAGE_USAGE_DISPLAY;
+  // If it has usage other than DISPLAY OR if it is not used just for display
+  // compositor, it means that it is used by the gpu main thread.
+  const bool used_by_main_gpu_thread =
+      usage & ~SHARED_IMAGE_USAGE_DISPLAY || !is_for_display_compositor_;
   return used_by_display_compositor_gpu_thread && used_by_main_gpu_thread;
 }
 
diff --git a/gpu/command_buffer/service/shared_image_factory.h b/gpu/command_buffer/service/shared_image_factory.h
index 4b0983d..1bb4f844 100644
--- a/gpu/command_buffer/service/shared_image_factory.h
+++ b/gpu/command_buffer/service/shared_image_factory.h
@@ -54,7 +54,8 @@
                      SharedImageManager* manager,
                      ImageFactory* image_factory,
                      MemoryTracker* tracker,
-                     bool enable_wrapped_sk_image);
+                     bool enable_wrapped_sk_image,
+                     bool is_for_display_compositor);
   ~SharedImageFactory();
 
   bool CreateSharedImage(const Mailbox& mailbox,
@@ -157,6 +158,10 @@
   SharedContextState* shared_context_state_;
   std::unique_ptr<MemoryTypeTracker> memory_tracker_;
 
+  // This is used if the factory is created on display compositor to check for
+  // sharing between threads.
+  const bool is_for_display_compositor_;
+
   // This is |shared_context_state_|'s context type. Some tests leave
   // |shared_context_state_| as nullptr, in which case this is set to a default
   /// of kGL.
diff --git a/gpu/command_buffer/service/shared_image_factory_unittest.cc b/gpu/command_buffer/service/shared_image_factory_unittest.cc
index 1ff4e117..4cea657 100644
--- a/gpu/command_buffer/service/shared_image_factory_unittest.cc
+++ b/gpu/command_buffer/service/shared_image_factory_unittest.cc
@@ -41,7 +41,8 @@
     factory_ = std::make_unique<SharedImageFactory>(
         preferences, workarounds, GpuFeatureInfo(), nullptr, &mailbox_manager_,
         &shared_image_manager_, &image_factory_, nullptr,
-        /*enable_wrapped_sk_image=*/false);
+        /*enable_wrapped_sk_image=*/false,
+        /*is_for_display_compositor=*/false);
   }
 
   void TearDown() override {
@@ -96,7 +97,7 @@
   auto other_factory = std::make_unique<SharedImageFactory>(
       preferences, workarounds, GpuFeatureInfo(), nullptr, &mailbox_manager_,
       &shared_image_manager_, &image_factory_, nullptr,
-      /*enable_wrapped_sk_image=*/false);
+      /*enable_wrapped_sk_image=*/false, /*is_for_display_compositor=*/false);
   EXPECT_FALSE(other_factory->CreateSharedImage(
       mailbox, format, size, color_space, kTopLeft_GrSurfaceOrigin,
       kPremul_SkAlphaType, surface_handle, usage));
diff --git a/gpu/command_buffer/tests/fuzzer_main.cc b/gpu/command_buffer/tests/fuzzer_main.cc
index c3546d1..268da9e9a 100644
--- a/gpu/command_buffer/tests/fuzzer_main.cc
+++ b/gpu/command_buffer/tests/fuzzer_main.cc
@@ -409,7 +409,8 @@
         gpu_preferences_, config_.workarounds, gpu_feature_info,
         context_state_.get(), &mailbox_manager_, shared_image_manager_.get(),
         nullptr /* image_factory */, nullptr /* memory_tracker */,
-        false /* enable_wrapped_sk_image */);
+        false /* enable_wrapped_sk_image */,
+        false /* is_for_display_compositor */);
     for (uint32_t usage = SHARED_IMAGE_USAGE_GLES2;
          usage <= SHARED_IMAGE_USAGE_RGB_EMULATION; usage <<= 1) {
       Mailbox::Name name;
diff --git a/gpu/command_buffer/tests/gl_test_setup_helper.cc b/gpu/command_buffer/tests/gl_test_setup_helper.cc
new file mode 100644
index 0000000..78b5b03b
--- /dev/null
+++ b/gpu/command_buffer/tests/gl_test_setup_helper.cc
@@ -0,0 +1,40 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/tests/gl_test_setup_helper.h"
+
+#include "components/viz/test/test_gpu_service_holder.h"
+#include "gpu/command_buffer/client/gles2_lib.h"
+#include "gpu/command_buffer/tests/gl_test_utils.h"
+#include "ui/gl/init/gl_factory.h"
+
+namespace gpu {
+
+GLTestSetupHelper::GLTestSetupHelper() {
+  viz::TestGpuServiceHolder::DoNotResetOnTestExit();
+  testing::TestEventListeners& listeners =
+      testing::UnitTest::GetInstance()->listeners();
+  listeners.Append(this);
+}
+
+GLTestSetupHelper::~GLTestSetupHelper() {
+  testing::TestEventListeners& listeners =
+      testing::UnitTest::GetInstance()->listeners();
+  CHECK_EQ(this, listeners.Release(this));
+}
+
+void GLTestSetupHelper::OnTestStart(const testing::TestInfo& test_info) {
+  gpu::GLTestHelper::InitializeGLDefault();
+  ::gles2::Initialize();
+}
+
+void GLTestSetupHelper::OnTestEnd(const testing::TestInfo& test_info) {
+  // Explicitly tear down the gpu-service (if active) before shutting down GL.
+  // Otherwise the gpu-service tries to access GL during tear-down and causes
+  // crashes.
+  viz::TestGpuServiceHolder::ResetInstance();
+  gl::init::ShutdownGL(/*due_to_fallback=*/false);
+}
+
+}  // namespace gpu
diff --git a/gpu/command_buffer/tests/gl_test_setup_helper.h b/gpu/command_buffer/tests/gl_test_setup_helper.h
new file mode 100644
index 0000000..402c03a
--- /dev/null
+++ b/gpu/command_buffer/tests/gl_test_setup_helper.h
@@ -0,0 +1,28 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_TESTS_GL_TEST_SETUP_HELPER_H_
+#define GPU_COMMAND_BUFFER_TESTS_GL_TEST_SETUP_HELPER_H_
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+
+// Helper class to automatically set-up and initialize GL environment before
+// every test, and tear down the environment after every test. This should
+// normally be used from base::TestSuite instances, so that it takes care of the
+// set-up/tear-down between every test, and each test does not have to do this
+// explicitly.
+class GLTestSetupHelper : public testing::EmptyTestEventListener {
+ public:
+  GLTestSetupHelper();
+  ~GLTestSetupHelper();
+
+  // testing::EmptyTestEventListener:
+  void OnTestStart(const testing::TestInfo& test_info) override;
+  void OnTestEnd(const testing::TestInfo& test_info) override;
+};
+
+}  // namespace gpu
+#endif  // GPU_COMMAND_BUFFER_TESTS_GL_TEST_SETUP_HELPER_H_
diff --git a/gpu/command_buffer/tests/gl_tests_main.cc b/gpu/command_buffer/tests/gl_tests_main.cc
index cb0166c..86ac4559 100644
--- a/gpu/command_buffer/tests/gl_tests_main.cc
+++ b/gpu/command_buffer/tests/gl_tests_main.cc
@@ -11,7 +11,7 @@
 #include "base/test/task_environment.h"
 #include "base/test/test_suite.h"
 #include "build/build_config.h"
-#include "gpu/command_buffer/client/gles2_lib.h"
+#include "gpu/command_buffer/tests/gl_test_setup_helper.h"
 #include "gpu/command_buffer/tests/gl_test_utils.h"
 #include "mojo/core/embedder/embedder.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -49,13 +49,12 @@
       ui::OzonePlatform::InitializeForGPU(params);
     }
 #endif
-  gpu::GLTestHelper::InitializeGLDefault();
-
-  ::gles2::Initialize();
+    gl_setup_ = std::make_unique<gpu::GLTestSetupHelper>();
   }
 
  private:
   std::unique_ptr<base::test::TaskEnvironment> task_environment_;
+  std::unique_ptr<gpu::GLTestSetupHelper> gl_setup_;
 };
 
 }  // namespace
diff --git a/gpu/config/gpu_finch_features.cc b/gpu/config/gpu_finch_features.cc
index ac75405..6e918b1 100644
--- a/gpu/config/gpu_finch_features.cc
+++ b/gpu/config/gpu_finch_features.cc
@@ -7,6 +7,7 @@
 #include "base/command_line.h"
 #include "build/chromeos_buildflags.h"
 #include "gpu/config/gpu_switches.h"
+#include "ui/gl/gl_features.h"
 
 #if defined(OS_ANDROID)
 #include "base/android/android_image_reader_compat.h"
@@ -135,6 +136,10 @@
 const base::Feature kCanvasOopRasterization{"CanvasOopRasterization",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Enables the use of ANGLE validation for non-WebGL contexts.
+const base::Feature kDefaultEnableANGLEValidation{
+    "DefaultEnableANGLEValidation", base::FEATURE_DISABLED_BY_DEFAULT};
+
 #if defined(OS_WIN)
 // Use a high priority for GPU process on Windows.
 const base::Feature kGpuProcessHighPriorityWin{
@@ -309,6 +314,25 @@
 #endif
 }
 
+bool IsANGLEValidationEnabled() {
+  if (!base::FeatureList::IsEnabled(kDefaultEnableANGLEValidation)) {
+    return false;
+  }
+
+  if (!UsePassthroughCommandDecoder()) {
+    return false;
+  }
+
+  // Enable ANGLE validation when OOP canvas is enabled on Windows
+#if defined(OS_WIN)
+  if (!base::FeatureList::IsEnabled(kCanvasOopRasterization)) {
+    return false;
+  }
+#endif
+
+  return true;
+}
+
 #if defined(OS_ANDROID)
 bool IsAImageReaderEnabled() {
   return base::FeatureList::IsEnabled(kAImageReader) &&
diff --git a/gpu/config/gpu_finch_features.h b/gpu/config/gpu_finch_features.h
index e77067d4..d66fe04 100644
--- a/gpu/config/gpu_finch_features.h
+++ b/gpu/config/gpu_finch_features.h
@@ -33,6 +33,8 @@
 
 GPU_EXPORT extern const base::Feature kCanvasOopRasterization;
 
+GPU_EXPORT extern const base::Feature kDefaultEnableANGLEValidation;
+
 #if defined(OS_WIN)
 GPU_EXPORT extern const base::Feature kGpuProcessHighPriorityWin;
 #endif
@@ -64,6 +66,7 @@
 
 GPU_EXPORT bool IsUsingVulkan();
 GPU_EXPORT bool IsDrDcEnabled();
+GPU_EXPORT bool IsANGLEValidationEnabled();
 
 #if defined(OS_ANDROID)
 GPU_EXPORT bool IsAImageReaderEnabled();
diff --git a/gpu/ipc/service/gpu_channel_manager.cc b/gpu/ipc/service/gpu_channel_manager.cc
index d475902e..6230fad 100644
--- a/gpu/ipc/service/gpu_channel_manager.cc
+++ b/gpu/ipc/service/gpu_channel_manager.cc
@@ -34,6 +34,7 @@
 #include "gpu/command_buffer/service/scheduler.h"
 #include "gpu/command_buffer/service/service_utils.h"
 #include "gpu/command_buffer/service/sync_point_manager.h"
+#include "gpu/config/gpu_finch_features.h"
 #include "gpu/ipc/common/gpu_client_ids.h"
 #include "gpu/ipc/common/memory_stats.h"
 #include "gpu/ipc/service/gpu_channel.h"
@@ -767,6 +768,12 @@
   use_virtualized_gl_contexts |=
       gpu_driver_bug_workarounds_.use_virtualized_gl_contexts;
 
+  bool enable_angle_validation = features::IsANGLEValidationEnabled();
+#if DCHECK_IS_ON()
+  // Force validation on for all debug builds and testing
+  enable_angle_validation = true;
+#endif
+
   const bool use_passthrough_decoder =
       gles2::PassthroughCommandDecoderSupported() &&
       gpu_preferences_.use_passthrough_cmd_decoder;
@@ -800,6 +807,8 @@
       // attribs.robust_resource_initialization = false;
     }
 
+    attribs.can_skip_validation = !enable_angle_validation;
+
     context =
         gl::init::CreateGLContext(share_group.get(), surface.get(), attribs);
     if (!context) {
@@ -856,7 +865,7 @@
 
   // Log crash reports when GL errors are generated.
   if (gl::GetGLImplementation() == gl::kGLImplementationEGLANGLE &&
-      feature_info->feature_flags().khr_debug) {
+      enable_angle_validation && feature_info->feature_flags().khr_debug) {
     static int remaining_gl_error_reports =
 #if defined(OS_ANDROID)
         // Don't generate crash reports on Android due to errors generated
diff --git a/gpu/ipc/service/gpu_memory_ablation_experiment.cc b/gpu/ipc/service/gpu_memory_ablation_experiment.cc
index fda5a14..0c682483 100644
--- a/gpu/ipc/service/gpu_memory_ablation_experiment.cc
+++ b/gpu/ipc/service/gpu_memory_ablation_experiment.cc
@@ -210,7 +210,8 @@
       channel_manager->mailbox_manager(),
       channel_manager->shared_image_manager(),
       gmb_factory ? gmb_factory->AsImageFactory() : nullptr, this,
-      features::IsUsingSkiaRenderer());
+      features::IsUsingSkiaRenderer(),
+      /*is_for_display_compositor=*/false);
 
   rep_factory_ = std::make_unique<SharedImageRepresentationFactory>(
       channel_manager->shared_image_manager(), this);
diff --git a/gpu/ipc/service/shared_image_stub.cc b/gpu/ipc/service/shared_image_stub.cc
index a1b0038..999a5e34 100644
--- a/gpu/ipc/service/shared_image_stub.cc
+++ b/gpu/ipc/service/shared_image_stub.cc
@@ -543,7 +543,8 @@
       channel_manager->mailbox_manager(),
       channel_manager->shared_image_manager(),
       gmb_factory ? gmb_factory->AsImageFactory() : nullptr, this,
-      features::IsUsingSkiaRenderer());
+      features::IsUsingSkiaRenderer(),
+      /*is_for_display_compositor=*/false);
   return ContextResult::kSuccess;
 }
 
diff --git a/gpu/ipc/shared_image_interface_in_process.cc b/gpu/ipc/shared_image_interface_in_process.cc
index c7846ec..1f84a2c 100644
--- a/gpu/ipc/shared_image_interface_in_process.cc
+++ b/gpu/ipc/shared_image_interface_in_process.cc
@@ -61,7 +61,8 @@
             display_controller->mailbox_manager(),
             display_controller->shared_image_manager(),
             display_controller->image_factory(),
-            display_controller->memory_tracker(), enable_wrapped_sk_image);
+            display_controller->memory_tracker(), enable_wrapped_sk_image,
+            /*is_for_display_compositor=*/true);
         return shared_image_factory;
       },
       display_controller);
diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg
index 5bd983b8..d2f2407f 100644
--- a/infra/config/generated/cr-buildbucket.cfg
+++ b/infra/config/generated/cr-buildbucket.cfg
@@ -49489,7 +49489,7 @@
       service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -49582,7 +49582,7 @@
       service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -49675,7 +49675,7 @@
       service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -49768,7 +49768,7 @@
       service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -49861,7 +49861,7 @@
       service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -49954,7 +49954,7 @@
       service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -52932,7 +52932,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -53035,7 +53035,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -53138,7 +53138,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -53241,7 +53241,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -53344,7 +53344,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -53447,7 +53447,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -53550,7 +53550,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -53653,7 +53653,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -53770,7 +53770,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -53873,7 +53873,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -53976,7 +53976,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -54079,7 +54079,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -54182,7 +54182,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -54285,7 +54285,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -54388,7 +54388,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -54499,7 +54499,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -54603,7 +54603,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -54706,7 +54706,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -54810,7 +54810,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -54913,7 +54913,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -55016,7 +55016,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -55119,7 +55119,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -55222,7 +55222,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -55329,7 +55329,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -55436,7 +55436,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -55539,7 +55539,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -55643,7 +55643,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -55746,7 +55746,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -55850,7 +55850,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -55953,7 +55953,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -56056,7 +56056,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -56159,7 +56159,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -56262,7 +56262,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -56365,7 +56365,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -56468,7 +56468,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -56571,7 +56571,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -56674,7 +56674,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -56777,7 +56777,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -56880,7 +56880,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -56983,7 +56983,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -57086,7 +57086,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -57189,7 +57189,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -57292,7 +57292,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -57395,7 +57395,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -57499,7 +57499,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -57602,7 +57602,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -57705,7 +57705,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -57809,7 +57809,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -57912,7 +57912,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -58015,7 +58015,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -58118,7 +58118,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -58220,7 +58220,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -58323,7 +58323,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -58426,7 +58426,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -58529,7 +58529,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -58632,7 +58632,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -58732,7 +58732,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -58861,7 +58861,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -58972,7 +58972,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -59074,7 +59074,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -59177,7 +59177,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -59279,7 +59279,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -59382,7 +59382,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -59485,7 +59485,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -59588,7 +59588,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -59690,7 +59690,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -59793,7 +59793,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -59895,7 +59895,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -59998,7 +59998,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -60100,7 +60100,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -60203,7 +60203,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -60306,7 +60306,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -60408,7 +60408,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -60509,7 +60509,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -60609,7 +60609,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -60709,7 +60709,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -60810,7 +60810,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -60911,7 +60911,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -61012,7 +61012,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -61113,7 +61113,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -61216,7 +61216,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -61319,7 +61319,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -61422,7 +61422,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -61525,7 +61525,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -61628,7 +61628,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -61731,7 +61731,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -61834,7 +61834,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -61937,7 +61937,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -62040,7 +62040,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -62143,7 +62143,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -62246,7 +62246,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -62348,7 +62348,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -62450,7 +62450,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -62552,7 +62552,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -62654,7 +62654,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -62753,7 +62753,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -62852,7 +62852,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -62951,7 +62951,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -63050,7 +63050,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -63149,7 +63149,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -63248,7 +63248,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -63347,7 +63347,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -63446,7 +63446,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -63545,7 +63545,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -63644,7 +63644,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -63743,7 +63743,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -63842,7 +63842,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -63941,7 +63941,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -64040,7 +64040,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -64139,7 +64139,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -64238,7 +64238,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -64337,7 +64337,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -64436,7 +64436,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -64535,7 +64535,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -64634,7 +64634,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -64733,7 +64733,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -64832,7 +64832,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -64931,7 +64931,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -65030,7 +65030,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -65129,7 +65129,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -65228,7 +65228,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -65325,7 +65325,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -65422,7 +65422,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -65519,7 +65519,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -65616,7 +65616,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -65713,7 +65713,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -65810,7 +65810,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -65907,7 +65907,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -66004,7 +66004,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -66101,7 +66101,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -66198,7 +66198,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -66295,7 +66295,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -66392,7 +66392,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -66489,7 +66489,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -66588,7 +66588,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -66687,7 +66687,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -66786,7 +66786,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -66885,7 +66885,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -66984,7 +66984,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -67083,7 +67083,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -67182,7 +67182,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -67281,7 +67281,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -67380,7 +67380,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -67479,7 +67479,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -67578,7 +67578,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -67677,7 +67677,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -67776,7 +67776,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -67875,7 +67875,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -67974,7 +67974,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -68073,7 +68073,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -68170,7 +68170,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -68267,7 +68267,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -68366,7 +68366,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -68468,7 +68468,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -68573,7 +68573,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -68686,7 +68686,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -68791,7 +68791,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -68904,7 +68904,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -69009,7 +69009,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -69114,7 +69114,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -69219,7 +69219,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -69331,7 +69331,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -69436,7 +69436,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -69541,7 +69541,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -69646,7 +69646,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -69751,7 +69751,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -69853,7 +69853,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -69955,7 +69955,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -70058,7 +70058,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -70161,7 +70161,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -70267,7 +70267,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -70370,7 +70370,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -70473,7 +70473,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -70576,7 +70576,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -70679,7 +70679,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -70782,7 +70782,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -70885,7 +70885,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -70989,7 +70989,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -71092,7 +71092,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -71195,7 +71195,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -71298,7 +71298,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -71401,7 +71401,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -71504,7 +71504,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -71607,7 +71607,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -71706,7 +71706,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -71809,7 +71809,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -71911,7 +71911,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -72014,7 +72014,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -72117,7 +72117,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -72224,7 +72224,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -72334,7 +72334,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -72438,7 +72438,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -72542,7 +72542,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -72643,7 +72643,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -72746,7 +72746,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -72849,7 +72849,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -72952,7 +72952,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -73049,7 +73049,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -73152,7 +73152,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -73255,7 +73255,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -73359,7 +73359,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -73462,7 +73462,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -73565,7 +73565,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -73667,7 +73667,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -73770,7 +73770,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -73873,7 +73873,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -73976,7 +73976,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -74078,7 +74078,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -74181,7 +74181,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -74291,7 +74291,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -74400,7 +74400,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -74506,7 +74506,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -74612,7 +74612,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -74718,7 +74718,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -74818,7 +74818,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -74918,7 +74918,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -75018,7 +75018,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -75118,7 +75118,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -75222,7 +75222,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -75325,7 +75325,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -75428,7 +75428,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -75531,7 +75531,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -75634,7 +75634,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -75737,7 +75737,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -75841,7 +75841,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -75944,7 +75944,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -76047,7 +76047,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -76150,7 +76150,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -76253,7 +76253,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -76357,7 +76357,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -76460,7 +76460,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -76564,7 +76564,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -76668,7 +76668,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -76771,7 +76771,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -76874,7 +76874,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -76977,7 +76977,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -77084,7 +77084,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -77187,7 +77187,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -77294,7 +77294,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -77398,7 +77398,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -77501,7 +77501,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -77604,7 +77604,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -77707,7 +77707,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -77810,7 +77810,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -77913,7 +77913,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -78016,7 +78016,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -78119,7 +78119,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -78221,7 +78221,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -78318,7 +78318,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -78421,7 +78421,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -78522,7 +78522,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -78623,7 +78623,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -78725,7 +78725,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -78825,7 +78825,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -78926,7 +78926,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -79026,7 +79026,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -79127,7 +79127,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -79232,7 +79232,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -79337,7 +79337,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -79434,7 +79434,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -79534,7 +79534,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -79634,7 +79634,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -79735,7 +79735,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -79836,7 +79836,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -79937,7 +79937,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -80038,7 +80038,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -80139,7 +80139,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -80240,7 +80240,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -80341,7 +80341,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -80442,7 +80442,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -80543,7 +80543,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -80644,7 +80644,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -80745,7 +80745,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -80846,7 +80846,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -80948,7 +80948,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -81050,7 +81050,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -81151,7 +81151,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -81252,7 +81252,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -81352,7 +81352,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -81448,7 +81448,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -81544,7 +81544,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -81647,7 +81647,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -81750,7 +81750,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -81853,7 +81853,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -81956,7 +81956,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -82059,7 +82059,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -82162,7 +82162,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -82265,7 +82265,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -82368,7 +82368,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -82471,7 +82471,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -82574,7 +82574,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -82678,7 +82678,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -82785,7 +82785,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -82886,7 +82886,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -82988,7 +82988,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -83091,7 +83091,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -83191,7 +83191,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -83291,7 +83291,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -83391,7 +83391,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -83491,7 +83491,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -83591,7 +83591,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -83691,7 +83691,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -83791,7 +83791,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -83894,7 +83894,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -83997,7 +83997,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -84100,7 +84100,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -84215,7 +84215,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -84325,7 +84325,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -84428,7 +84428,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -84531,7 +84531,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -84640,7 +84640,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -84743,7 +84743,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -84854,7 +84854,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -84956,7 +84956,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -85062,7 +85062,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -85165,7 +85165,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -85268,7 +85268,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -85372,7 +85372,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -85475,7 +85475,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -85579,7 +85579,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -85682,7 +85682,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -85785,7 +85785,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -85888,7 +85888,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -85991,7 +85991,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -86094,7 +86094,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -86190,7 +86190,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
@@ -86293,7 +86293,7 @@
       }
       experiments {
         key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
+        value: 0
       }
       experiments {
         key: "chromium.resultdb.result_sink"
diff --git a/infra/config/lib/try.star b/infra/config/lib/try.star
index 9e81d3c..cc5b92b 100644
--- a/infra/config/lib/try.star
+++ b/infra/config/lib/try.star
@@ -168,7 +168,7 @@
             fail("Try Windows builder {} must disable ATS".format(name))
 
     # TODO(crbug.com/1143122): remove this after migration.
-    experiments["chromium.chromium_tests.use_rbe_cas"] = 5
+    experiments["chromium.chromium_tests.use_rbe_cas"] = 0
 
     # Define the builder first so that any validation of luci.builder arguments
     # (e.g. bucket) occurs before we try to use it
diff --git a/ios/chrome/browser/autofill/form_structure_browsertest.mm b/ios/chrome/browser/autofill/form_structure_browsertest.mm
index 1ee24ea..d2c22c9 100644
--- a/ios/chrome/browser/autofill/form_structure_browsertest.mm
+++ b/ios/chrome/browser/autofill/form_structure_browsertest.mm
@@ -305,10 +305,14 @@
 // To disable a data driven test, please add the name of the test file
 // (i.e., "NNN_some_site.html") as a literal to the initializer_list given
 // to the failing_test_names constructor.
-const std::set<std::string>& GetFailingTestNames() {
-  static std::set<std::string>* failing_test_names =
-      new std::set<std::string>{};
-  return *failing_test_names;
+const auto& GetFailingTestNames() {
+  static std::set<std::string> failing_test_names{
+      // TODO(crbug.com/1187842): This page contains iframes. Until filling
+      // across iframes is also supported on iOS, iOS has has different
+      // expectations compared to non-iOS platforms.
+      "049_register_ebay.com.html",
+  };
+  return failing_test_names;
 }
 
 }  // namespace
diff --git a/ios/chrome/browser/crash_report/crash_helper.mm b/ios/chrome/browser/crash_report/crash_helper.mm
index a66d0c5..8aeb31a 100644
--- a/ios/chrome/browser/crash_report/crash_helper.mm
+++ b/ios/chrome/browser/crash_report/crash_helper.mm
@@ -60,7 +60,7 @@
 // begin uploading when possible.
 void ProcessIntermediateDumps() {
   crash_reporter::ProcessIntermediateDumps();
-  crash_reporter::StartProcesingPendingReports();
+  crash_reporter::StartProcessingPendingReports();
 }
 
 // Callback for logging::SetLogMessageHandler
@@ -335,7 +335,7 @@
 
 void StartUploadingReportsInRecoveryMode() {
   if (crash_reporter::IsCrashpadRunning()) {
-    crash_reporter::StartProcesingPendingReports();
+    crash_reporter::StartProcessingPendingReports();
     return;
   }
 
diff --git a/ios/chrome/browser/sync/ios_trusted_vault_client.mm b/ios/chrome/browser/sync/ios_trusted_vault_client.mm
index 0720915f..e3ccf84 100644
--- a/ios/chrome/browser/sync/ios_trusted_vault_client.mm
+++ b/ios/chrome/browser/sync/ios_trusted_vault_client.mm
@@ -64,7 +64,15 @@
 
   ios::GetChromeBrowserProvider()
       .GetChromeTrustedVaultService()
-      ->MarkLocalKeysAsStale(identity, std::move(callback));
+      ->MarkLocalKeysAsStale(identity,
+                             base::BindOnce(
+                                 [](base::OnceCallback<void(bool)> callback) {
+                                   // Since false positives are allowed in the
+                                   // API, always return true, indicating that
+                                   // something may have changed.
+                                   std::move(callback).Run(true);
+                                 },
+                                 std::move(callback)));
 }
 
 void IOSTrustedVaultClient::GetIsRecoverabilityDegraded(
diff --git a/ios/chrome/browser/ui/authentication/signin/trusted_vault_reauthentication/trusted_vault_reauthentication_coordinator.mm b/ios/chrome/browser/ui/authentication/signin/trusted_vault_reauthentication/trusted_vault_reauthentication_coordinator.mm
index 484f018..35b645e 100644
--- a/ios/chrome/browser/ui/authentication/signin/trusted_vault_reauthentication/trusted_vault_reauthentication_coordinator.mm
+++ b/ios/chrome/browser/ui/authentication/signin/trusted_vault_reauthentication/trusted_vault_reauthentication_coordinator.mm
@@ -120,8 +120,8 @@
       };
   switch (self.intent) {
     case SigninTrustedVaultDialogIntentFetchKeys:
-      trustedVaultService->ReauthenticationForFetchKeys(
-          self.identity, self.baseViewController, callback);
+      trustedVaultService->Reauthentication(self.identity,
+                                            self.baseViewController, callback);
       break;
     case SigninTrustedVaultDialogIntentDegradedRecoverability:
       trustedVaultService->FixDegradedRecoverability(
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
index ee66e877..5e1afdb4 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
@@ -52,6 +52,7 @@
 #import "ios/chrome/common/ui/util/constraints_ui_util.h"
 #import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #import "ios/public/provider/chrome/browser/discover_feed/discover_feed_provider.h"
+#import "ios/public/provider/chrome/browser/discover_feed/discover_feed_view_controller_configuration.h"
 #import "ios/web/public/navigation/navigation_context.h"
 #import "ios/web/public/navigation/navigation_item.h"
 #import "ios/web/public/navigation/navigation_manager.h"
@@ -238,11 +239,15 @@
   // Requests a Discover feed here if the correct flags and prefs are enabled.
   if ([self shouldUseRefactoredNTP]) {
     self.ntpViewController = [[NewTabPageViewController alloc] init];
+    DiscoverFeedViewControllerConfiguration* viewControllerConfig =
+        [[DiscoverFeedViewControllerConfiguration alloc] init];
+    viewControllerConfig.browser = self.browser;
+    viewControllerConfig.scrollDelegate = self.ntpViewController;
+    viewControllerConfig.previewDelegate = self;
     self.discoverFeedViewController =
         ios::GetChromeBrowserProvider()
             .GetDiscoverFeedProvider()
-            ->NewFeedViewControllerWithScrollDelegate(self.browser,
-                                                      self.ntpViewController);
+            ->NewFeedViewControllerWithConfiguration(viewControllerConfig);
   }
 
   if (self.discoverFeedViewController) {
diff --git a/ios/components/webui/sync_internals/sync_internals_ui.h b/ios/components/webui/sync_internals/sync_internals_ui.h
index a03bff8..b33b15b 100644
--- a/ios/components/webui/sync_internals/sync_internals_ui.h
+++ b/ios/components/webui/sync_internals/sync_internals_ui.h
@@ -17,7 +17,7 @@
 // The implementation for the chrome://sync-internals page.
 class SyncInternalsUI : public web::WebUIIOSController {
  public:
-  explicit SyncInternalsUI(web::WebUIIOS* web_ui, const std::string& host);
+  SyncInternalsUI(web::WebUIIOS* web_ui, const std::string& host);
   ~SyncInternalsUI() override;
 
  private:
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
index 294415c..8176183 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-eebdf0a85ce8085fbbcf42579111fa4c3418996f
\ No newline at end of file
+e14a4ef87866965768ad2aa6c0d605f8095098a4
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
index 43c769e..1864406 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-adeefd9cfa4078969cd9937208d78a9f532f9c79
\ No newline at end of file
+2316846bc43dec35168165237123a6969991b729
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
index c2eac16..dd59036 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-480e499c8b4c47f96b5197cebc75d63efb5f397b
\ No newline at end of file
+13d147316769c843f7de634fbe6d182ba311165f
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1
index 284d86c..b4e014d9 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-5ca0156a9d89d443ae9200bdb36cfae254448191
\ No newline at end of file
+c95674414d97bdf912fec57839af96b596847cec
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
index eea2845..701af136 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-6274430d3b63eb7ddc4c1a7b9a8765ebc150b01a
\ No newline at end of file
+9856096d2f82a8a87d6bc144de61229cd9a62f46
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
index 05a9be3..1f38b50e 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-b91d37f0b10f188955eb78c42924d4d818258594
\ No newline at end of file
+41c5e70fd097f04c3f44391dc01d8d5bdbc69998
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
index b43bbb3..6be32ab 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-a4c7cba55059d7e238e7222eecb3eee2ca8dfcbd
\ No newline at end of file
+0a9c74478dc4bd2b6e7c080a46c440c16dec1805
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
index acdc5c8c..6ae78e5 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-ff79848ac321e4b3a7fdd4ba8c05af9a522a0d40
\ No newline at end of file
+86034b1d2aa0d1b11e926075794bb393bb7420b1
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
index d69955a7..eb3bc375 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-152687dae7e567f04d3cb0e4523c8a725c2c01c1
\ No newline at end of file
+0482972ed0a37f56ea6be9dfb8e9bc0653e1b7b7
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
index d44e290..c2a0736 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-f1e9028654939f9dec9e8974a4192e7304bc7b87
\ No newline at end of file
+86055b37639e9ef1c954578a484a44487a3b78a1
\ No newline at end of file
diff --git a/ios/public/provider/chrome/browser/signin/chrome_trusted_vault_service.h b/ios/public/provider/chrome/browser/signin/chrome_trusted_vault_service.h
index 2a52356..46e5487 100644
--- a/ios/public/provider/chrome/browser/signin/chrome_trusted_vault_service.h
+++ b/ios/public/provider/chrome/browser/signin/chrome_trusted_vault_service.h
@@ -44,16 +44,13 @@
       base::OnceCallback<void(const TrustedVaultSharedKeyList&)> callback) = 0;
 
   // Invoked when the result of FetchKeys() contains keys that are not
-  // up-to-date. |cb| is run upon completion and returns false if the call did
-  // not make any difference (e.g. the operation is unsupported) or true if
-  // some change may have occurred (which indicates a second FetchKeys() attempt
-  // is worth). During the execution, before |cb| is invoked, the behavior is
+  // up-to-date. During the execution, before |cb| is invoked, the behavior is
   // unspecified if FetchKeys() is invoked, that is, FetchKeys() may or may not
   // treat existing keys as stale (only guaranteed upon completion of
   // MarkLocalKeysAsStale()).
   // TODO(crbug.com/1100278): Make pure virtual.
   virtual void MarkLocalKeysAsStale(ChromeIdentity* chrome_identity,
-                                    base::OnceCallback<void(bool)> callback);
+                                    base::OnceClosure callback);
 
   // Returns whether recoverability of the keys is degraded and user action is
   // required to add a new method.
@@ -65,16 +62,10 @@
   // purpose of extending the set of keys returned via FetchKeys(). Once the
   // reauth is done and the UI is dismissed, |callback| is called. |callback| is
   // not called if the reauthentication is canceled.
-  // TODO(crbug.com/1100278): Remove this function and adopt
-  // ReauthenticationForFetchKeys() exclusively.
   virtual void Reauthentication(ChromeIdentity* chrome_identity,
                                 UIViewController* presentingViewController,
-                                void (^callback)(BOOL success, NSError* error));
-  // TODO(crbug.com/1100278): Make pure.
-  virtual void ReauthenticationForFetchKeys(
-      ChromeIdentity* chrome_identity,
-      UIViewController* presentingViewController,
-      void (^callback)(BOOL success, NSError* error));
+                                void (^callback)(BOOL success,
+                                                 NSError* error)) = 0;
 
   // Presents the trusted vault key reauthentication UI for |identity| for the
   // purpose of improving recoverability as returned via
@@ -98,7 +89,7 @@
       void (^callback)(BOOL success, NSError* error));
 
   // Cancels the presented trusted vault reauthentication UI, triggered via
-  // either ReauthenticationForFetchKeys() or via
+  // either Reauthentication() or via
   // FixDegradedRecoverability(). The reauthentication callback
   // will not be called. If no reauthentication dialog is not present,
   // |callback| is called synchronously.
diff --git a/ios/public/provider/chrome/browser/signin/chrome_trusted_vault_service.mm b/ios/public/provider/chrome/browser/signin/chrome_trusted_vault_service.mm
index d60436e..7f3a1ed69 100644
--- a/ios/public/provider/chrome/browser/signin/chrome_trusted_vault_service.mm
+++ b/ios/public/provider/chrome/browser/signin/chrome_trusted_vault_service.mm
@@ -24,21 +24,7 @@
 
 void ChromeTrustedVaultService::MarkLocalKeysAsStale(
     ChromeIdentity* chrome_identity,
-    base::OnceCallback<void(bool)> callback) {
-  std::move(callback).Run(false);
-}
-
-void ChromeTrustedVaultService::Reauthentication(
-    ChromeIdentity* chrome_identity,
-    UIViewController* presentingViewController,
-    void (^callback)(BOOL success, NSError* error)) {}
-
-void ChromeTrustedVaultService::ReauthenticationForFetchKeys(
-    ChromeIdentity* chrome_identity,
-    UIViewController* presentingViewController,
-    void (^callback)(BOOL success, NSError* error)) {
-  Reauthentication(chrome_identity, presentingViewController, callback);
-}
+    base::OnceClosure callback) {}
 
 void ChromeTrustedVaultService::ReauthenticationForOptIn(
     ChromeIdentity* chrome_identity,
diff --git a/ios/public/provider/chrome/browser/signin/fake_chrome_trusted_vault_service.h b/ios/public/provider/chrome/browser/signin/fake_chrome_trusted_vault_service.h
index 823786d..535673e 100644
--- a/ios/public/provider/chrome/browser/signin/fake_chrome_trusted_vault_service.h
+++ b/ios/public/provider/chrome/browser/signin/fake_chrome_trusted_vault_service.h
@@ -31,10 +31,10 @@
                                  UIViewController* presentingViewController,
                                  void (^callback)(BOOL success,
                                                   NSError* error)) override;
-  void ReauthenticationForFetchKeys(
-      ChromeIdentity* chrome_identity,
-      UIViewController* presenting_view_controller,
-      void (^callback)(BOOL success, NSError* error)) override;
+  void Reauthentication(ChromeIdentity* chrome_identity,
+                        UIViewController* presenting_view_controller,
+                        void (^callback)(BOOL success,
+                                         NSError* error)) override;
   void CancelDialog(BOOL animated, void (^callback)(void)) override;
 
   // Simulates user cancel the reauth dialog.
diff --git a/ios/public/provider/chrome/browser/signin/fake_chrome_trusted_vault_service.mm b/ios/public/provider/chrome/browser/signin/fake_chrome_trusted_vault_service.mm
index ae4e89d..33e5e38 100644
--- a/ios/public/provider/chrome/browser/signin/fake_chrome_trusted_vault_service.mm
+++ b/ios/public/provider/chrome/browser/signin/fake_chrome_trusted_vault_service.mm
@@ -66,7 +66,7 @@
     UIViewController* presentingViewController,
     void (^callback)(BOOL success, NSError* error)) {}
 
-void FakeChromeTrustedVaultService::ReauthenticationForFetchKeys(
+void FakeChromeTrustedVaultService::Reauthentication(
     ChromeIdentity* chrome_identity,
     UIViewController* presenting_view_controller,
     void (^callback)(BOOL success, NSError* error)) {
diff --git a/ios/web/public/webui/web_ui_ios.h b/ios/web/public/webui/web_ui_ios.h
index a77320d..1a6811c 100644
--- a/ios/web/public/webui/web_ui_ios.h
+++ b/ios/web/public/webui/web_ui_ios.h
@@ -57,7 +57,7 @@
   // object.
   virtual void ProcessWebUIIOSMessage(const GURL& source_url,
                                       const std::string& message,
-                                      const base::ListValue& args) = 0;
+                                      const base::Value& args) = 0;
 
   // Call a Javascript function.  This is asynchronous; there's no way to get
   // the result of the call, and should be thought of more like sending a
diff --git a/ios/web/public/webui/web_ui_ios_controller.h b/ios/web/public/webui/web_ui_ios_controller.h
index 0cc1024..3beb237 100644
--- a/ios/web/public/webui/web_ui_ios_controller.h
+++ b/ios/web/public/webui/web_ui_ios_controller.h
@@ -7,11 +7,10 @@
 
 #include <string>
 
-
 class GURL;
 
 namespace base {
-class ListValue;
+class Value;
 }
 
 namespace web {
@@ -22,7 +21,7 @@
 // manages the data source and message handlers.
 class WebUIIOSController {
  public:
-  explicit WebUIIOSController(WebUIIOS* web_ui, const std::string& host)
+  WebUIIOSController(WebUIIOS* web_ui, const std::string& host)
       : web_ui_(web_ui), host_(host) {}
   virtual ~WebUIIOSController() {}
 
@@ -30,7 +29,7 @@
   // Return true if the message handling was overridden.
   virtual bool OverrideHandleWebUIIOSMessage(const GURL& source_url,
                                              const std::string& message,
-                                             const base::ListValue& args);
+                                             const base::Value& args);
 
   WebUIIOS* web_ui() const { return web_ui_; }
 
diff --git a/ios/web/webui/web_ui_ios_controller.cc b/ios/web/webui/web_ui_ios_controller.cc
index 64f0f71..7ce42df7 100644
--- a/ios/web/webui/web_ui_ios_controller.cc
+++ b/ios/web/webui/web_ui_ios_controller.cc
@@ -9,7 +9,7 @@
 bool WebUIIOSController::OverrideHandleWebUIIOSMessage(
     const GURL& source_url,
     const std::string& message,
-    const base::ListValue& args) {
+    const base::Value& args) {
   return false;
 }
 
diff --git a/ios/web/webui/web_ui_ios_impl.h b/ios/web/webui/web_ui_ios_impl.h
index 5d4aed29..7deecbf3d 100644
--- a/ios/web/webui/web_ui_ios_impl.h
+++ b/ios/web/webui/web_ui_ios_impl.h
@@ -39,7 +39,7 @@
                                const MessageCallback& callback) override;
   void ProcessWebUIIOSMessage(const GURL& source_url,
                               const std::string& message,
-                              const base::ListValue& args) override;
+                              const base::Value& args) override;
   void CallJavascriptFunction(
       const std::string& function_name,
       const std::vector<const base::Value*>& args) override;
diff --git a/ios/web/webui/web_ui_ios_impl.mm b/ios/web/webui/web_ui_ios_impl.mm
index 404c5aee..12ee9c96 100644
--- a/ios/web/webui/web_ui_ios_impl.mm
+++ b/ios/web/webui/web_ui_ios_impl.mm
@@ -135,14 +135,14 @@
       DLOG(WARNING) << "JS message parameter not found: arguments";
       return;
     }
-    ProcessWebUIIOSMessage(current_url, *message_content,
-                           base::Value::AsListValue(*arguments));
+    ProcessWebUIIOSMessage(current_url, *message_content, *arguments);
   }
 }
 
 void WebUIIOSImpl::ProcessWebUIIOSMessage(const GURL& source_url,
                                           const std::string& message,
-                                          const base::ListValue& args) {
+                                          const base::Value& args) {
+  DCHECK(args.is_list());
   if (controller_->OverrideHandleWebUIIOSMessage(source_url, message, args))
     return;
 
@@ -151,7 +151,7 @@
       message_callbacks_.find(message);
   if (callback != message_callbacks_.end()) {
     // Forward this message and content on.
-    callback->second.Run(&args);
+    callback->second.Run(&base::Value::AsListValue(args));
   }
 }
 
diff --git a/ios/web_view/BUILD.gn b/ios/web_view/BUILD.gn
index 906df9f..0649f2d 100644
--- a/ios/web_view/BUILD.gn
+++ b/ios/web_view/BUILD.gn
@@ -325,6 +325,7 @@
     "//net:extras",
     "//services/metrics/public/cpp:metrics_cpp",
     "//services/network:network_service",
+    "//third_party/abseil-cpp:absl",
     "//ui/base",
     "//url",
   ]
diff --git a/ios/web_view/internal/cwv_flags.mm b/ios/web_view/internal/cwv_flags.mm
index 4fcadfa..4999160 100644
--- a/ios/web_view/internal/cwv_flags.mm
+++ b/ios/web_view/internal/cwv_flags.mm
@@ -24,6 +24,7 @@
 #include "components/sync/base/sync_base_switches.h"
 #include "components/sync/driver/sync_driver_switches.h"
 #include "ios/web_view/internal/app/application_context.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -120,45 +121,38 @@
       _flagsStorage.get(), flags_ui::kGeneralAccessFlagsOnly, supportedFeatures,
       unsupportedFeatures,
       base::BindRepeating(&ios_web_view::SkipConditionalFeatureEntry));
-  for (size_t i = 0; i < supportedFeatures.size(); i++) {
-    base::DictionaryValue* featureEntry;
-    if (!supportedFeatures[i].GetAsDictionary(&featureEntry)) {
-      NOTREACHED();
-    }
-    std::string internalName;
-    if (!featureEntry->GetString("internal_name", &internalName)) {
-      NOTREACHED();
-    }
-    if (internalName == ios_web_view::kUseSyncSandboxFlagName) {
-      bool enabled;
-      if (!featureEntry->GetBoolean("enabled", &enabled)) {
-        NOTREACHED();
-      }
-      usesSyncSandbox = enabled;
-    } else if (internalName == ios_web_view::kUseWalletSandboxFlagName) {
-      base::ListValue* options;
-      if (!featureEntry->GetList("options", &options)) {
-        NOTREACHED();
-      }
-      for (size_t j = 0; j < options->GetSize(); j++) {
-        base::DictionaryValue* option;
-        if (!options->GetDictionary(j, &option)) {
-          NOTREACHED();
-        }
-        std::string internalName;
-        if (!option->GetString("internal_name", &internalName)) {
-          NOTREACHED();
-        }
-        if (internalName == ios_web_view::kUseWalletSandboxFlagNameEnabled) {
-          bool selected;
-          if (!option->GetBoolean("selected", &selected)) {
-            NOTREACHED();
-          }
-          usesWalletSandbox = selected;
+
+  for (const base::Value& supportedFeature : supportedFeatures) {
+    DCHECK(supportedFeature.is_dict());
+
+    const std::string* internalName =
+        supportedFeature.FindStringKey("internal_name");
+    DCHECK(internalName);
+
+    if (*internalName == ios_web_view::kUseSyncSandboxFlagName) {
+      absl::optional<bool> maybeEnabled =
+          supportedFeature.FindBoolKey("enabled");
+      DCHECK(maybeEnabled.has_value());
+      usesSyncSandbox = *maybeEnabled;
+    } else if (*internalName == ios_web_view::kUseWalletSandboxFlagName) {
+      const base::Value* options = supportedFeature.FindListKey("options");
+      DCHECK(options);
+
+      for (const base::Value& option : options->GetList()) {
+        DCHECK(option.is_dict());
+
+        const std::string* internalName = option.FindStringKey("internal_name");
+        DCHECK(internalName);
+
+        if (*internalName == ios_web_view::kUseWalletSandboxFlagNameEnabled) {
+          absl::optional<bool> maybeSelected = option.FindBoolKey("selected");
+          DCHECK(maybeSelected.has_value());
+          usesWalletSandbox = *maybeSelected;
         }
       }
     }
   }
+
   return usesSyncSandbox && usesWalletSandbox;
 }
 
diff --git a/ios/web_view/internal/webui/web_view_sync_internals_ui.h b/ios/web_view/internal/webui/web_view_sync_internals_ui.h
index 602c5bd..b95a22b 100644
--- a/ios/web_view/internal/webui/web_view_sync_internals_ui.h
+++ b/ios/web_view/internal/webui/web_view_sync_internals_ui.h
@@ -19,12 +19,11 @@
 // ios/web_view specific SyncInternalsUI.
 class WebViewSyncInternalsUI : public SyncInternalsUI {
  public:
-  explicit WebViewSyncInternalsUI(web::WebUIIOS* web_ui,
-                                  const std::string& host);
+  WebViewSyncInternalsUI(web::WebUIIOS* web_ui, const std::string& host);
   ~WebViewSyncInternalsUI() override;
   bool OverrideHandleWebUIIOSMessage(const GURL& source_url,
                                      const std::string& message,
-                                     const base::ListValue& args) override;
+                                     const base::Value& args) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(WebViewSyncInternalsUI);
diff --git a/ios/web_view/internal/webui/web_view_sync_internals_ui.mm b/ios/web_view/internal/webui/web_view_sync_internals_ui.mm
index 56327f3..9604262 100644
--- a/ios/web_view/internal/webui/web_view_sync_internals_ui.mm
+++ b/ios/web_view/internal/webui/web_view_sync_internals_ui.mm
@@ -21,7 +21,7 @@
 bool WebViewSyncInternalsUI::OverrideHandleWebUIIOSMessage(
     const GURL& source_url,
     const std::string& message,
-    const base::ListValue& args) {
+    const base::Value& args) {
   // ios/web_view only supports sync in transport mode. Explicitly override sync
   // start and stop messages and perform a no op.
   return message == syncer::sync_ui_util::kRequestStart ||
diff --git a/media/gpu/test/image_quality_metrics.cc b/media/gpu/test/image_quality_metrics.cc
index da56c4df..40eea6d7 100644
--- a/media/gpu/test/image_quality_metrics.cc
+++ b/media/gpu/test/image_quality_metrics.cc
@@ -138,11 +138,12 @@
 double ComputeSimilarity(const VideoFrame* frame1,
                          const VideoFrame* frame2,
                          SimilarityMetrics mode) {
-  ASSERT_TRUE_OR_RETURN(frame1->IsMappable() && frame2->IsMappable(),
-                        std::numeric_limits<std::size_t>::max());
+  ASSERT_TRUE_OR_RETURN(
+      frame1->IsMappable() && frame2->IsMappable(),
+      static_cast<double>(std::numeric_limits<std::size_t>::max()));
   ASSERT_TRUE_OR_RETURN(
       frame1->visible_rect().size() == frame2->visible_rect().size(),
-      std::numeric_limits<std::size_t>::max());
+      static_cast<double>(std::numeric_limits<std::size_t>::max()));
   // Ideally, frame1->BitDepth() should be the same as frame2->BitDepth()
   // always. But in the 10 bit case, the 10 bit frame can be carried with P016LE
   // whose bit depth is regarded to be 16. This is due to a lack of NV12 10-bit
@@ -151,7 +152,7 @@
   ASSERT_TRUE_OR_RETURN(
       (frame1->BitDepth() == 8 && frame1->BitDepth() == frame2->BitDepth()) ||
           std::min(frame1->BitDepth(), frame2->BitDepth()) == 10,
-      std::numeric_limits<std::size_t>::max());
+      static_cast<double>(std::numeric_limits<std::size_t>::max()));
   const size_t bit_depth = std::min(frame1->BitDepth(), frame2->BitDepth());
   const VideoPixelFormat common_format =
       bit_depth == 8 ? PIXEL_FORMAT_I420 : PIXEL_FORMAT_YUV420P10;
diff --git a/net/cookies/canonical_cookie.cc b/net/cookies/canonical_cookie.cc
index 468d50b..3a16752 100644
--- a/net/cookies/canonical_cookie.cc
+++ b/net/cookies/canonical_cookie.cc
@@ -424,12 +424,14 @@
   }
   *status = CookieInclusionStatus();
 
-  ParsedCookie parsed_cookie(cookie_line);
+  ParsedCookie parsed_cookie(cookie_line, status);
 
   if (!parsed_cookie.IsValid()) {
     DVLOG(net::cookie_util::kVlogSetCookies)
         << "WARNING: Couldn't parse cookie";
-    status->AddExclusionReason(CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE);
+    // TODO(crbug.com/1228815): Apply more specific exclusion reasons.
+    DCHECK(status->HasExclusionReason(
+        CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE));
     // Don't continue, because an invalid ParsedCookie doesn't have any
     // attributes.
     // TODO(chlily): Log metrics.
diff --git a/net/cookies/cookie_inclusion_status.h b/net/cookies/cookie_inclusion_status.h
index 454d2bde..8ac90a9 100644
--- a/net/cookies/cookie_inclusion_status.h
+++ b/net/cookies/cookie_inclusion_status.h
@@ -59,7 +59,9 @@
 
     // Statuses only applied when creating/setting cookies:
 
-    // Cookie was malformed and could not be stored.
+    // Cookie was malformed and could not be stored, due to problem(s) while
+    // parsing.
+    // TODO(crbug.com/1228815): Use more specific reasons for parsing errors.
     EXCLUDE_FAILURE_TO_STORE = 11,
     // Attempted to set a cookie from a scheme that does not support cookies.
     EXCLUDE_NONCOOKIEABLE_SCHEME = 12,
diff --git a/net/cookies/parsed_cookie.cc b/net/cookies/parsed_cookie.cc
index 7ffbcfbb..a8a449c 100644
--- a/net/cookies/parsed_cookie.cc
+++ b/net/cookies/parsed_cookie.cc
@@ -48,6 +48,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_util.h"
 #include "net/cookies/cookie_constants.h"
+#include "net/cookies/cookie_inclusion_status.h"
 #include "net/http/http_util.h"
 
 namespace {
@@ -151,15 +152,34 @@
 
 namespace net {
 
-ParsedCookie::ParsedCookie(const std::string& cookie_line) {
+ParsedCookie::ParsedCookie(const std::string& cookie_line,
+                           CookieInclusionStatus* status_out) {
+  // Put a pointer on the stack so the rest of the function can assign to it if
+  // the default nullptr is passed in.
+  CookieInclusionStatus blank_status;
+  if (status_out == nullptr) {
+    status_out = &blank_status;
+  }
+
   if (cookie_line.size() > kMaxCookieSize) {
     DVLOG(1) << "Not parsing cookie, too large: " << cookie_line.size();
+    // TODO(crbug.com/1228815): Apply more specific exclusion reasons.
+    status_out->AddExclusionReason(
+        CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE);
     return;
   }
 
-  ParseTokenValuePairs(cookie_line);
-  if (!pairs_.empty())
+  ParseTokenValuePairs(cookie_line, *status_out);
+  if (IsValid()) {
     SetupAttributes();
+  } else if (status_out->IsInclude()) {
+    // TODO(crbug.com/1228815): Apply more specific exclusion reasons.
+    status_out->AddExclusionReason(
+        CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE);
+  }
+
+  // Status should indicate exclusion if the resulting ParsedCookie is invalid.
+  DCHECK(IsValid() || !status_out->IsInclude());
 
   if (IsValid())
     RecordCookieAttributeValueLengthHistograms();
@@ -391,7 +411,8 @@
 }
 
 // Parse all token/value pairs and populate pairs_.
-void ParsedCookie::ParseTokenValuePairs(const std::string& cookie_line) {
+void ParsedCookie::ParseTokenValuePairs(const std::string& cookie_line,
+                                        CookieInclusionStatus& status_out) {
   pairs_.clear();
 
   // Ok, here we go.  We should be expecting to be starting somewhere
@@ -404,8 +425,12 @@
   std::string::const_iterator end = FindFirstTerminator(cookie_line);
 
   // Exit early for an empty cookie string.
-  if (it == end)
+  if (it == end) {
+    // TODO(crbug.com/1228815): Apply more specific exclusion reasons.
+    status_out.AddExclusionReason(
+        CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE);
     return;
+  }
 
   for (int pair_num = 0; it != end; ++pair_num) {
     TokenValuePair pair;
@@ -452,6 +477,9 @@
 
     // Ignore cookies with neither name nor value.
     if (pair_num == 0 && (pair.first.empty() && pair.second.empty())) {
+      // TODO(crbug.com/1228815): Apply more specific exclusion reasons.
+      status_out.AddExclusionReason(
+          CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE);
       pairs_.clear();
       break;
     }
@@ -464,6 +492,9 @@
     // http://crbug.com/238041.
     if (!IsValidCookieAttributeValue(pair.first) ||
         !IsValidCookieAttributeValue(pair.second)) {
+      // TODO(crbug.com/1228815): Apply more specific exclusion reasons.
+      status_out.AddExclusionReason(
+          CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE);
       pairs_.clear();
       break;
     }
diff --git a/net/cookies/parsed_cookie.h b/net/cookies/parsed_cookie.h
index b93dcc7..cd2897b 100644
--- a/net/cookies/parsed_cookie.h
+++ b/net/cookies/parsed_cookie.h
@@ -16,6 +16,8 @@
 
 namespace net {
 
+class CookieInclusionStatus;
+
 class NET_EXPORT ParsedCookie {
  public:
   typedef std::pair<std::string, std::string> TokenValuePair;
@@ -27,7 +29,12 @@
   // Construct from a cookie string like "BLAH=1; path=/; domain=.google.com"
   // Format is according to RFC 6265. Cookies with both name and value empty
   // will be considered invalid.
-  ParsedCookie(const std::string& cookie_line);
+  // `status_out` is a nullable output param which will be populated with
+  // informative exclusion reasons if the resulting ParsedCookie is invalid.
+  // The CookieInclusionStatus will not be altered if the resulting ParsedCookie
+  // is valid.
+  explicit ParsedCookie(const std::string& cookie_line,
+                        CookieInclusionStatus* status_out = nullptr);
   ~ParsedCookie();
 
   // You should not call any other methods except for SetName/SetValue on the
@@ -123,7 +130,8 @@
   static bool IsValidCookieAttributeValue(const std::string& value);
 
  private:
-  void ParseTokenValuePairs(const std::string& cookie_line);
+  void ParseTokenValuePairs(const std::string& cookie_line,
+                            CookieInclusionStatus& status_out);
   void SetupAttributes();
 
   // Sets a key/value pair for a cookie. |index| has to point to one of the
diff --git a/net/disk_cache/simple/simple_entry_impl.cc b/net/disk_cache/simple/simple_entry_impl.cc
index f3ef30d0..69db7cf 100644
--- a/net/disk_cache/simple/simple_entry_impl.cc
+++ b/net/disk_cache/simple/simple_entry_impl.cc
@@ -163,9 +163,6 @@
   static_assert(std::extent<decltype(data_size_)>() ==
                     std::extent<decltype(have_written_)>(),
                 "arrays should be the same size");
-  static_assert(std::extent<decltype(data_size_)>() ==
-                    std::extent<decltype(crc_check_state_)>(),
-                "arrays should be the same size");
   ResetEntry();
   NetLogSimpleEntryConstruction(net_log_,
                                 net::NetLogEventType::SIMPLE_CACHE_ENTRY,
@@ -670,9 +667,6 @@
   std::memset(crc32s_, 0, sizeof(crc32s_));
   std::memset(have_written_, 0, sizeof(have_written_));
   std::memset(data_size_, 0, sizeof(data_size_));
-  for (size_t i = 0; i < base::size(crc_check_state_); ++i) {
-    crc_check_state_[i] = CRC_CHECK_NEVER_READ_AT_ALL;
-  }
 }
 
 void SimpleEntryImpl::ReturnEntryToCaller() {
@@ -989,14 +983,6 @@
     synchronous_entry_ = nullptr;
     prioritized_task_runner_->PostTaskAndReply(
         FROM_HERE, std::move(task), std::move(reply), entry_priority_);
-
-    for (int i = 0; i < kSimpleEntryStreamCount; ++i) {
-      if (!have_written_[i]) {
-        SIMPLE_CACHE_UMA(ENUMERATION,
-                         "CheckCRCResult", cache_type_,
-                         crc_check_state_[i], CRC_CHECK_MAX);
-      }
-    }
   } else {
     CloseOperationComplete(std::move(results));
   }
@@ -1452,7 +1438,6 @@
         stream_1_prefetch_data_ = prefetched.data;
 
       // The crc was read in SimpleSynchronousEntry.
-      crc_check_state_[stream] = CRC_CHECK_DONE;
       crc32s_[stream] = prefetched.stream_crc32;
       crc32s_end_offset_[stream] = in_results->entry_stat.data_size(stream);
     }
@@ -1529,29 +1514,16 @@
   DCHECK(read_result);
   int result = read_result->result;
 
-  if (result > 0 &&
-      crc_check_state_[stream_index] == CRC_CHECK_NEVER_READ_AT_ALL) {
-    crc_check_state_[stream_index] = CRC_CHECK_NEVER_READ_TO_END;
-  }
-
   if (read_result->crc_updated) {
     if (result > 0) {
       DCHECK_EQ(crc32s_end_offset_[stream_index], offset);
       crc32s_end_offset_[stream_index] += result;
       crc32s_[stream_index] = read_result->updated_crc32;
     }
-
-    if (read_result->crc_performed_verify)
-      crc_check_state_[stream_index] = CRC_CHECK_DONE;
   }
 
   if (result < 0) {
     crc32s_end_offset_[stream_index] = 0;
-  } else {
-    if (crc_check_state_[stream_index] == CRC_CHECK_NEVER_READ_TO_END &&
-        offset + result == GetDataSize(stream_index)) {
-      crc_check_state_[stream_index] = CRC_CHECK_NOT_DONE;
-    }
   }
 
   if (net_log_.IsCapturing()) {
diff --git a/net/disk_cache/simple/simple_entry_impl.h b/net/disk_cache/simple/simple_entry_impl.h
index a63952d4..9a133e6 100644
--- a/net/disk_cache/simple/simple_entry_impl.h
+++ b/net/disk_cache/simple/simple_entry_impl.h
@@ -183,15 +183,6 @@
     DOOM_COMPLETED,
   };
 
-  // Used in histograms, please only add entries at the end.
-  enum CheckCrcResult {
-    CRC_CHECK_NEVER_READ_TO_END = 0,
-    CRC_CHECK_NOT_DONE = 1,
-    CRC_CHECK_DONE = 2,
-    CRC_CHECK_NEVER_READ_AT_ALL = 3,
-    CRC_CHECK_MAX = 4,
-  };
-
   ~SimpleEntryImpl() override;
 
   // Must be used to invoke a client-provided completion callback for an
@@ -420,10 +411,6 @@
   // contains stream |index|.
   bool have_written_[kSimpleEntryStreamCount];
 
-  // Reflects how much CRC checking has been done with the entry. This state is
-  // reported on closing each entry stream.
-  CheckCrcResult crc_check_state_[kSimpleEntryStreamCount];
-
   // The |synchronous_entry_| is the worker thread object that performs IO on
   // entries. It's owned by this SimpleEntryImpl whenever |executing_operation_|
   // is false (i.e. when an operation is not pending on the worker pool). When
diff --git a/net/disk_cache/simple/simple_synchronous_entry.cc b/net/disk_cache/simple/simple_synchronous_entry.cc
index 2866764..3943482 100644
--- a/net/disk_cache/simple/simple_synchronous_entry.cc
+++ b/net/disk_cache/simple/simple_synchronous_entry.cc
@@ -540,16 +540,12 @@
       if (in_entry_op.request_verify_crc &&
           in_entry_op.offset + bytes_read ==
               entry_stat->data_size(in_entry_op.index)) {
-        out_result->crc_performed_verify = true;
         int checksum_result =
             CheckEOFRecord(file.get(), in_entry_op.index, *entry_stat,
                            out_result->updated_crc32);
         if (checksum_result < 0) {
-          out_result->crc_verify_ok = false;
           out_result->result = checksum_result;
           return;
-        } else {
-          out_result->crc_verify_ok = true;
         }
       }
     }
diff --git a/net/disk_cache/simple/simple_synchronous_entry.h b/net/disk_cache/simple/simple_synchronous_entry.h
index ae61f04c..120c674 100644
--- a/net/disk_cache/simple/simple_synchronous_entry.h
+++ b/net/disk_cache/simple/simple_synchronous_entry.h
@@ -143,15 +143,10 @@
   };
 
   struct ReadResult {
-    ReadResult()
-        : crc_updated(false),
-          crc_performed_verify(false),
-          crc_verify_ok(false) {}
+    ReadResult() : crc_updated(false) {}
     int result;
     uint32_t updated_crc32;  // only relevant if crc_updated set
     bool crc_updated;
-    bool crc_performed_verify;  // only relevant if crc_updated set
-    bool crc_verify_ok;         // only relevant if crc_updated set
   };
 
   struct WriteRequest {
diff --git a/net/quic/quic_http3_logger.cc b/net/quic/quic_http3_logger.cc
index 8132bfe..4410a3737 100644
--- a/net/quic/quic_http3_logger.cc
+++ b/net/quic/quic_http3_logger.cc
@@ -337,25 +337,4 @@
       });
 }
 
-void QuicHttp3Logger::OnPushPromiseFrameSent(
-    quic::QuicStreamId stream_id,
-    quic::QuicStreamId push_id,
-    const spdy::Http2HeaderBlock& header_block) {
-  if (!net_log_.IsCapturing()) {
-    return;
-  }
-  net_log_.AddEvent(
-      NetLogEventType::HTTP3_PUSH_PROMISE_SENT,
-      [stream_id, push_id, &header_block](NetLogCaptureMode capture_mode) {
-        base::Value dict(base::Value::Type::DICTIONARY);
-        dict.SetKey("stream_id",
-                    NetLogNumberValue(static_cast<uint64_t>(stream_id)));
-        dict.SetKey("push_id",
-                    NetLogNumberValue(static_cast<uint64_t>(push_id)));
-        dict.SetKey("headers",
-                    ElideHttp2HeaderBlockForNetLog(header_block, capture_mode));
-        return dict;
-      });
-}
-
 }  // namespace net
diff --git a/net/quic/quic_http3_logger.h b/net/quic/quic_http3_logger.h
index 976d70a..c22fc79f 100644
--- a/net/quic/quic_http3_logger.h
+++ b/net/quic/quic_http3_logger.h
@@ -59,10 +59,6 @@
                        quic::QuicByteCount payload_length) override;
   void OnHeadersFrameSent(quic::QuicStreamId stream_id,
                           const spdy::Http2HeaderBlock& header_block) override;
-  void OnPushPromiseFrameSent(
-      quic::QuicStreamId stream_id,
-      quic::QuicStreamId push_id,
-      const spdy::Http2HeaderBlock& header_block) override;
 
  private:
   NetLogWithSource net_log_;
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index d1310ff..ae18046 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -1753,8 +1753,8 @@
         kIncludeVersion, !kFin, DEFAULT_PRIORITY, 0,
         &spdy_request_headers_frame_length, {header, kUploadData}));
     AddWrite(ConstructClientAckPacket(packet_number++, 3, 1));
-    AddWrite(client_maker_.MakeRstPacket(
-        packet_number++, true, stream_id_, quic::QUIC_STREAM_NO_ERROR,
+    AddWrite(client_maker_.MakeAckAndRstPacket(
+        packet_number++, true, stream_id_, quic::QUIC_STREAM_NO_ERROR, 4, 1,
         /* include_stop_sending_if_v99 = */ false));
   } else {
     AddWrite(ConstructRequestHeadersAndDataFramesPacket(
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc
index 7f57840..519e2c45 100644
--- a/net/quic/quic_network_transaction_unittest.cc
+++ b/net/quic/quic_network_transaction_unittest.cc
@@ -3780,7 +3780,7 @@
   if (VersionUsesHttp3(version_.transport_version)) {
     quic_data.AddWrite(
         SYNCHRONOUS,
-        client_maker_->MakeRstAckAndDataPacket(
+        client_maker_->MakeAckRstAndDataPacket(
             packet_num++, true, GetNthClientInitiatedBidirectionalStreamId(0),
             quic::QUIC_HEADERS_TOO_LARGE, 1, 1, GetQpackDecoderStreamId(),
             false, StreamCancellationQpackDecoderInstruction(0)));
@@ -4049,7 +4049,7 @@
   if (VersionUsesHttp3(version_.transport_version)) {
     mock_quic_data.AddWrite(
         SYNCHRONOUS,
-        client_maker_->MakeRstAckAndDataPacket(
+        client_maker_->MakeAckRstAndDataPacket(
             packet_num++, /*include_version=*/true,
             GetNthClientInitiatedBidirectionalStreamId(1),
             quic::QUIC_HEADERS_TOO_LARGE, 3, 2, GetQpackDecoderStreamId(),
@@ -5409,7 +5409,7 @@
   if (VersionUsesHttp3(version_.transport_version)) {
     mock_quic_data.AddWrite(
         SYNCHRONOUS,
-        client_maker_->MakeRstAckAndDataPacket(
+        client_maker_->MakeAckRstAndDataPacket(
             packet_num++, false, GetNthClientInitiatedBidirectionalStreamId(0),
             quic::QUIC_STREAM_CANCELLED, 1, 1, GetQpackDecoderStreamId(), false,
             StreamCancellationQpackDecoderInstruction(0)));
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index c77847c..d9bdae1 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -2087,8 +2087,11 @@
         ASYNC, server_maker_.MakeRstPacket(1, false, stream_id,
                                            quic::QUIC_STREAM_CANCELLED));
     socket_data.AddRead(
-        ASYNC, server_maker_.MakeMaxStreamsPacket(4, true, 52,
+        ASYNC, server_maker_.MakeMaxStreamsPacket(2, true, 52,
                                                   /*unidirectional=*/false));
+    socket_data.AddWrite(SYNCHRONOUS,
+                         client_maker_.MakeAckPacket(packet_num++, 2, 1));
+
   } else {
     socket_data.AddWrite(
         SYNCHRONOUS, client_maker_.MakeRstPacket(1, true, stream_id,
diff --git a/pdf/post_message_sender.cc b/pdf/post_message_sender.cc
index 8815223..16fa7686 100644
--- a/pdf/post_message_sender.cc
+++ b/pdf/post_message_sender.cc
@@ -33,6 +33,7 @@
   if (!container_)
     return;
 
+  v8::Isolate::Scope isolate_scope(isolate_);
   v8::HandleScope handle_scope(isolate_);
   v8::Local<v8::Context> context =
       container_->GetDocument().GetFrame()->MainWorldScriptContext();
diff --git a/remoting/base/BUILD.gn b/remoting/base/BUILD.gn
index 1985124..3bad42ac 100644
--- a/remoting/base/BUILD.gn
+++ b/remoting/base/BUILD.gn
@@ -99,6 +99,7 @@
     "//remoting/proto/remoting/v1:directory_proto",
     "//remoting/proto/remoting/v1:telemetry_messages",
     "//services/network/public/cpp",
+    "//services/network/public/mojom",
     "//third_party/libvpx",
     "//third_party/libyuv",
     "//third_party/webrtc_overrides:webrtc_component",
diff --git a/remoting/base/DEPS b/remoting/base/DEPS
index da6fdba..feffae7a 100644
--- a/remoting/base/DEPS
+++ b/remoting/base/DEPS
@@ -4,6 +4,7 @@
   "+mojo/core/embedder",
   "+net",
   "+services/network/public/cpp",
+  "+services/network/public/mojom",
   "+services/network/test",
   "+third_party/breakpad",
   "+third_party/google_trust_services",
diff --git a/remoting/base/chromium_url_request.cc b/remoting/base/chromium_url_request.cc
index 24694a1..c00cc00 100644
--- a/remoting/base/chromium_url_request.cc
+++ b/remoting/base/chromium_url_request.cc
@@ -12,6 +12,7 @@
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 
 namespace remoting {
 
diff --git a/remoting/base/protobuf_http_request_base.cc b/remoting/base/protobuf_http_request_base.cc
index 2571bde..366bdbf 100644
--- a/remoting/base/protobuf_http_request_base.cc
+++ b/remoting/base/protobuf_http_request_base.cc
@@ -8,6 +8,7 @@
 #include "remoting/base/protobuf_http_request_config.h"
 #include "remoting/base/scoped_protobuf_http_request.h"
 #include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 
 namespace remoting {
 
diff --git a/remoting/host/it2me/it2me_host.cc b/remoting/host/it2me/it2me_host.cc
index 36bcebb..f2e3016 100644
--- a/remoting/host/it2me/it2me_host.cc
+++ b/remoting/host/it2me/it2me_host.cc
@@ -14,6 +14,7 @@
 #include "base/strings/string_util.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
 #include "build/chromeos_buildflags.h"
 #include "components/policy/policy_constants.h"
 #include "net/url_request/url_request_context_getter.h"
@@ -58,6 +59,11 @@
 typedef ValidatingAuthenticator::ValidationCallback ValidationCallback;
 typedef ValidatingAuthenticator::ResultCallback ValidationResultCallback;
 
+// The amount of time to wait before destroying the signal strategy.  This delay
+// ensures there is time for the session-terminate message to be sent.
+constexpr base::TimeDelta kDestroySignalingDelay =
+    base::TimeDelta::FromSeconds(2);
+
 }  // namespace
 
 It2MeHost::DeferredConnectContext::DeferredConnectContext() = default;
@@ -552,7 +558,19 @@
   host_status_logger_ = nullptr;
   log_to_server_ = nullptr;
   ftl_signaling_connector_ = nullptr;
-  signal_strategy_ = nullptr;
+
+  if (signal_strategy_) {
+    // Delay destruction of the signaling strategy by a few seconds to give it
+    // a chance to send any outgoing messages (e.g. session-terminate) so the
+    // other end of the connection can display and log an accurate disconnect
+    // reason.
+    host_context_->network_task_runner()->PostDelayedTask(
+        FROM_HERE,
+        base::BindOnce([](std::unique_ptr<SignalStrategy> signaling) {},
+                       std::move(signal_strategy_)),
+        kDestroySignalingDelay);
+  }
+
   host_event_logger_ = nullptr;
 
   // Post tasks to delete UI objects on the UI thread.
diff --git a/services/network/public/cpp/constants.h b/services/network/public/cpp/constants.h
index 0008d46..aca1ea3 100644
--- a/services/network/public/cpp/constants.h
+++ b/services/network/public/cpp/constants.h
@@ -11,9 +11,6 @@
 
 namespace network {
 
-// The default buffer size of DataPipe which is used to send the content body.
-static constexpr size_t kDataPipeDefaultAllocationSize = 512 * 1024;
-
 // The default Accept header value to use if none were specified.
 COMPONENT_EXPORT(NETWORK_CPP)
 extern const char kDefaultAcceptHeaderValue[];
diff --git a/services/network/public/cpp/features.cc b/services/network/public/cpp/features.cc
index 039ff5a..fc8b3cd 100644
--- a/services/network/public/cpp/features.cc
+++ b/services/network/public/cpp/features.cc
@@ -4,6 +4,8 @@
 
 #include "services/network/public/cpp/features.h"
 
+#include "base/metrics/field_trial_params.h"
+#include "base/numerics/safe_conversions.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 
@@ -217,5 +219,23 @@
 const base::Feature kSCTAuditingRetryAndPersistReports{
     "SCTAuditingRetryAndPersistReports", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// This feature will be used for tuning several loading-related data pipe
+// parameters. See crbug.com/1041006.
+const base::Feature kLoaderDataPipeTuningFeature{
+    "LoaderDataPipeTuning", base::FEATURE_DISABLED_BY_DEFAULT};
+
+namespace {
+// The default buffer size of DataPipe which is used to send the content body.
+static constexpr uint32_t kDataPipeDefaultAllocationSize = 512 * 1024;
+constexpr base::FeatureParam<int> kDataPipeAllocationSize{
+    &kLoaderDataPipeTuningFeature, "allocation_size_bytes",
+    base::saturated_cast<int>(kDataPipeDefaultAllocationSize)};
+}  // namespace
+
+// static
+uint32_t GetDataPipeDefaultAllocationSize() {
+  return base::saturated_cast<uint32_t>(kDataPipeAllocationSize.Get());
+}
+
 }  // namespace features
 }  // namespace network
diff --git a/services/network/public/cpp/features.h b/services/network/public/cpp/features.h
index ce73424..718f9987 100644
--- a/services/network/public/cpp/features.h
+++ b/services/network/public/cpp/features.h
@@ -85,6 +85,12 @@
 COMPONENT_EXPORT(NETWORK_CPP)
 extern const base::Feature kSCTAuditingRetryAndPersistReports;
 
+COMPONENT_EXPORT(NETWORK_CPP)
+extern const base::Feature kLoaderDataPipeTuningFeature;
+
+COMPONENT_EXPORT(NETWORK_CPP)
+extern uint32_t GetDataPipeDefaultAllocationSize();
+
 }  // namespace features
 }  // namespace network
 
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index 6b7f07b..a5ba517 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -1355,7 +1355,8 @@
   options.struct_size = sizeof(MojoCreateDataPipeOptions);
   options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
   options.element_num_bytes = 1;
-  options.capacity_num_bytes = kDataPipeDefaultAllocationSize;
+  options.capacity_num_bytes =
+      network::features::GetDataPipeDefaultAllocationSize();
   MojoResult result =
       mojo::CreateDataPipe(&options, response_body_stream_, consumer_handle_);
   if (result != MOJO_RESULT_OK) {
diff --git a/sql/statement.cc b/sql/statement.cc
index c3b55c3..8197751 100644
--- a/sql/statement.cc
+++ b/sql/statement.cc
@@ -15,7 +15,6 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
-#include "build/build_config.h"  // TODO(crbug.com/866218): Remove this include.
 #include "third_party/sqlite/sqlite3.h"
 
 namespace sql {
@@ -32,9 +31,7 @@
     : ref_(std::move(ref)) {}
 
 Statement::~Statement() {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // !defined(OS_ANDROID)
 
   // Free the resources associated with this statement. We assume there's only
   // one statement active for a given sqlite3_stmt at any time, so this won't
@@ -43,27 +40,21 @@
 }
 
 void Statement::Assign(scoped_refptr<Database::StatementRef> ref) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // !defined(OS_ANDROID)
 
   Reset(true);
   ref_ = std::move(ref);
 }
 
 void Statement::Clear() {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // !defined(OS_ANDROID)
 
   Assign(base::MakeRefCounted<Database::StatementRef>(nullptr, nullptr, false));
   succeeded_ = false;
 }
 
 bool Statement::CheckValid() const {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // !defined(OS_ANDROID)
 
   // Allow operations to fail silently if a statement was invalidated
   // because the database was closed by an error handler.
@@ -73,9 +64,7 @@
 }
 
 int Statement::StepInternal() {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
   if (!CheckValid())
     return SQLITE_ERROR;
@@ -88,9 +77,7 @@
 }
 
 bool Statement::Run() {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
 #if DCHECK_IS_ON()
   DCHECK(!run_called_) << "Run() must be called exactly once";
@@ -101,9 +88,7 @@
 }
 
 bool Statement::Step() {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
 #if DCHECK_IS_ON()
   DCHECK(!run_called_) << "Run() must not be mixed with Step()";
@@ -113,9 +98,7 @@
 }
 
 void Statement::Reset(bool clear_bound_vars) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
   absl::optional<base::ScopedBlockingCall> scoped_blocking_call;
   ref_->InitScopedBlockingCall(FROM_HERE, &scoped_blocking_call);
@@ -143,17 +126,13 @@
 }
 
 bool Statement::Succeeded() const {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
   return is_valid() && succeeded_;
 }
 
 void Statement::BindNull(int param_index) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
 #if DCHECK_IS_ON()
   DCHECK(!run_called_) << __func__ << " must not be called after Run()";
@@ -171,17 +150,13 @@
 }
 
 void Statement::BindBool(int param_index, bool val) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
   return BindInt64(param_index, val ? 1 : 0);
 }
 
 void Statement::BindInt(int param_index, int val) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
 #if DCHECK_IS_ON()
   DCHECK(!run_called_) << __func__ << " must not be called after Run()";
@@ -199,9 +174,7 @@
 }
 
 void Statement::BindInt64(int param_index, int64_t val) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
 #if DCHECK_IS_ON()
   DCHECK(!run_called_) << __func__ << " must not be called after Run()";
@@ -220,9 +193,7 @@
 }
 
 void Statement::BindDouble(int param_index, double val) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
 #if DCHECK_IS_ON()
   DCHECK(!run_called_) << __func__ << " must not be called after Run()";
@@ -241,9 +212,7 @@
 }
 
 void Statement::BindTime(int param_index, base::Time val) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
 #if DCHECK_IS_ON()
   DCHECK(!run_called_) << __func__ << " must not be called after Run()";
@@ -263,9 +232,7 @@
 }
 
 void Statement::BindCString(int param_index, const char* val) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
 #if DCHECK_IS_ON()
   DCHECK(!run_called_) << __func__ << " must not be called after Run()";
@@ -293,9 +260,7 @@
 }
 
 void Statement::BindString(int param_index, base::StringPiece value) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
 #if DCHECK_IS_ON()
   DCHECK(!run_called_) << __func__ << " must not be called after Run()";
@@ -331,17 +296,13 @@
 }
 
 void Statement::BindString16(int param_index, base::StringPiece16 value) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
   return BindString(param_index, base::UTF16ToUTF8(value));
 }
 
 void Statement::BindBlob(int param_index, base::span<const uint8_t> value) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
 #if DCHECK_IS_ON()
   DCHECK(!run_called_) << __func__ << " must not be called after Run()";
@@ -381,9 +342,7 @@
 }
 
 int Statement::ColumnCount() const {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
   if (!is_valid())
     return 0;
@@ -403,9 +362,7 @@
               "NULL mismatch");
 
 ColumnType Statement::GetColumnType(int col) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
 #if DCHECK_IS_ON()
   DCHECK(!run_called_) << __func__ << " can be used after Step(), not Run()";
@@ -416,16 +373,12 @@
 }
 
 bool Statement::ColumnBool(int column_index) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
   return static_cast<bool>(ColumnInt64(column_index));
 }
 
 int Statement::ColumnInt(int column_index) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
 #if DCHECK_IS_ON()
   DCHECK(!run_called_) << __func__ << " can be used after Step(), not Run()";
@@ -442,9 +395,7 @@
 }
 
 int64_t Statement::ColumnInt64(int column_index) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
 #if DCHECK_IS_ON()
   DCHECK(!run_called_) << __func__ << " can be used after Step(), not Run()";
@@ -461,9 +412,7 @@
 }
 
 double Statement::ColumnDouble(int column_index) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
 #if DCHECK_IS_ON()
   DCHECK(!run_called_) << __func__ << " can be used after Step(), not Run()";
@@ -480,9 +429,7 @@
 }
 
 base::Time Statement::ColumnTime(int column_index) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
 #if DCHECK_IS_ON()
   DCHECK(!run_called_) << __func__ << " can be used after Step(), not Run()";
@@ -501,9 +448,7 @@
 }
 
 std::string Statement::ColumnString(int column_index) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
 #if DCHECK_IS_ON()
   DCHECK(!run_called_) << __func__ << " can be used after Step(), not Run()";
@@ -527,9 +472,7 @@
 }
 
 std::u16string Statement::ColumnString16(int column_index) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
 #if DCHECK_IS_ON()
   DCHECK(!run_called_) << __func__ << " can be used after Step(), not Run()";
@@ -547,9 +490,7 @@
 }
 
 int Statement::ColumnByteLength(int column_index) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
 #if DCHECK_IS_ON()
   DCHECK(!run_called_) << __func__ << " can be used after Step(), not Run()";
@@ -566,9 +507,7 @@
 }
 
 const void* Statement::ColumnBlob(int column_index) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
 #if DCHECK_IS_ON()
   DCHECK(!run_called_) << __func__ << " can be used after Step(), not Run()";
@@ -585,9 +524,7 @@
 }
 
 bool Statement::ColumnBlobAsString(int column_index, std::string* result) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
 #if DCHECK_IS_ON()
   DCHECK(!run_called_) << __func__ << " can be used after Step(), not Run()";
@@ -612,9 +549,7 @@
 
 bool Statement::ColumnBlobAsVector(int column_index,
                                    std::vector<char>* result) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
 #if DCHECK_IS_ON()
   DCHECK(!run_called_) << __func__ << " can be used after Step(), not Run()";
@@ -642,26 +577,20 @@
 
 bool Statement::ColumnBlobAsVector(int column_index,
                                    std::vector<uint8_t>* result) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
   return ColumnBlobAsVector(column_index,
                             reinterpret_cast<std::vector<char>*>(result));
 }
 
 const char* Statement::GetSQLStatement() {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
   return sqlite3_sql(ref_->stmt());
 }
 
 int Statement::CheckError(int err) {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // OS_ANDROID
 
   // Please don't add DCHECKs here, OnSqliteError() already has them.
   succeeded_ = (err == SQLITE_OK || err == SQLITE_ROW || err == SQLITE_DONE);
diff --git a/sql/statement.h b/sql/statement.h
index 91871fc..c87ce494 100644
--- a/sql/statement.h
+++ b/sql/statement.h
@@ -16,8 +16,8 @@
 #include "base/memory/ref_counted.h"
 #include "base/sequence_checker.h"
 #include "base/strings/string_piece_forward.h"
+#include "base/thread_annotations.h"
 #include "base/time/time.h"
-#include "build/build_config.h"  // TODO(crbug.com/866218): Remove this include.
 #include "sql/database.h"
 
 namespace sql {
@@ -79,9 +79,7 @@
   // middle of executing a command if there is a serious error and the database
   // has to be reset.
   bool is_valid() const {
-#if !defined(OS_ANDROID)  // TODO(crbug.com/866218): Remove this conditional
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#endif  // !defined(OS_ANDROID)
 
     return ref_->is_valid();
   }
@@ -227,15 +225,16 @@
   // The actual sqlite statement. This may be unique to us, or it may be cached
   // by the Database, which is why it's ref-counted. This pointer is
   // guaranteed non-null.
-  scoped_refptr<Database::StatementRef> ref_;
+  scoped_refptr<Database::StatementRef> ref_
+      GUARDED_BY_CONTEXT(sequence_checker_);
 
   // See Succeeded() for what this holds.
-  bool succeeded_ = false;
+  bool succeeded_ GUARDED_BY_CONTEXT(sequence_checker_) = false;
 
 #if DCHECK_IS_ON()
   // Used to DCHECK() that Bind*() is called before Step() or Run() are called.
-  bool step_called_ = false;
-  bool run_called_ = false;
+  bool step_called_ GUARDED_BY_CONTEXT(sequence_checker_) = false;
+  bool run_called_ GUARDED_BY_CONTEXT(sequence_checker_) = false;
 #endif  // DCHECK_IS_ON()
 
   SEQUENCE_CHECKER(sequence_checker_);
diff --git a/sql/transaction.cc b/sql/transaction.cc
index c5319002..0bf18ec 100644
--- a/sql/transaction.cc
+++ b/sql/transaction.cc
@@ -5,6 +5,7 @@
 #include "sql/transaction.h"
 
 #include "base/check.h"
+#include "base/sequence_checker.h"
 #include "sql/database.h"
 
 namespace sql {
@@ -12,17 +13,20 @@
 Transaction::Transaction(Database* database) : database_(database) {}
 
 Transaction::~Transaction() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (is_open_)
     database_->RollbackTransaction();
 }
 
 bool Transaction::Begin() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!is_open_) << "Beginning a transaction twice!";
   is_open_ = database_->BeginTransaction();
   return is_open_;
 }
 
 void Transaction::Rollback() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(is_open_) << "Attempting to roll back a nonexistent transaction. "
                    << "Did you remember to call Begin() and check its return?";
   is_open_ = false;
@@ -30,6 +34,7 @@
 }
 
 bool Transaction::Commit() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(is_open_) << "Attempting to commit a nonexistent transaction. "
                    << "Did you remember to call Begin() and check its return?";
   is_open_ = false;
diff --git a/sql/transaction.h b/sql/transaction.h
index 069936fb..d092a97 100644
--- a/sql/transaction.h
+++ b/sql/transaction.h
@@ -6,11 +6,17 @@
 #define SQL_TRANSACTION_H_
 
 #include "base/component_export.h"
+#include "base/sequence_checker.h"
+#include "base/thread_annotations.h"
 
 namespace sql {
 
 class Database;
 
+// Automatically rolls back uncommitted transactions when going out of scope.
+//
+// This class is not thread-safe. Each instance must be used from a single
+// sequence.
 class COMPONENT_EXPORT(SQL) Transaction {
  public:
   // Creates the scoped transaction object. You MUST call Begin() to begin the
@@ -26,7 +32,10 @@
   ~Transaction();
 
   // Returns true when there is a transaction that has been successfully begun.
-  bool is_open() const { return is_open_; }
+  bool is_open() const {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    return is_open_;
+  }
 
   // Begins the transaction. This uses the default sqlite "deferred" transaction
   // type, which means that the DB lock is lazily acquired the next time the
@@ -47,11 +56,13 @@
   bool Commit();
 
  private:
-  Database* database_;
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  Database* const database_;
 
   // True when the transaction is open, false when it's already been committed
   // or rolled back.
-  bool is_open_ = false;
+  bool is_open_ GUARDED_BY_CONTEXT(sequence_checker_) = false;
 };
 
 }  // namespace sql
diff --git a/storage/browser/blob/blob_url_loader.cc b/storage/browser/blob/blob_url_loader.cc
index 72325e7..2790484 100644
--- a/storage/browser/blob/blob_url_loader.cc
+++ b/storage/browser/blob/blob_url_loader.cc
@@ -25,9 +25,11 @@
 #include "net/http/http_util.h"
 #include "net/url_request/url_request.h"
 #include "services/network/public/cpp/constants.h"
+#include "services/network/public/cpp/features.h"
 #include "services/network/public/mojom/url_response_head.mojom.h"
 #include "storage/browser/blob/blob_data_handle.h"
 #include "storage/browser/blob/mojo_blob_reader.h"
+#include "third_party/blink/public/common/blob/blob_utils.h"
 
 namespace storage {
 
@@ -154,7 +156,8 @@
   options.struct_size = sizeof(MojoCreateDataPipeOptions);
   options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
   options.element_num_bytes = 1;
-  options.capacity_num_bytes = network::kDataPipeDefaultAllocationSize;
+  options.capacity_num_bytes =
+      blink::BlobUtils::GetDataPipeCapacity(blink::BlobUtils::kUnknownSize);
   if (mojo::CreateDataPipe(&options, producer_handle, consumer_handle) !=
       MOJO_RESULT_OK) {
     OnComplete(net::ERR_INSUFFICIENT_RESOURCES, 0);
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index e298f97..825e95f09 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -25062,6 +25062,9 @@
     ],
     "gtest_tests": [
       {
+        "args": [
+          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
+        ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -25077,8 +25080,8 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "absl_hardening_tests",
-        "test_id_prefix": "ninja://third_party/abseil-cpp:absl_hardening_tests/"
+        "test": "color_unittests",
+        "test_id_prefix": "ninja://ui/color:color_unittests/"
       },
       {
         "args": [
@@ -25099,8 +25102,8 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "accessibility_unittests",
-        "test_id_prefix": "ninja://ui/accessibility:accessibility_unittests/"
+        "test": "courgette_unittests",
+        "test_id_prefix": "ninja://courgette:courgette_unittests/"
       },
       {
         "args": [
@@ -25121,8 +25124,8 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "aura_unittests",
-        "test_id_prefix": "ninja://ui/aura:aura_unittests/"
+        "test": "fuchsia_mojo_unittests",
+        "test_id_prefix": "ninja://fuchsia/mojom:fuchsia_mojo_unittests/"
       },
       {
         "args": [
@@ -25143,8 +25146,8 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "base_unittests",
-        "test_id_prefix": "ninja://base:base_unittests/"
+        "test": "gcm_unit_tests",
+        "test_id_prefix": "ninja://google_apis/gcm:gcm_unit_tests/"
       },
       {
         "args": [
@@ -25165,8 +25168,8 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "base_util_unittests",
-        "test_id_prefix": "ninja://base/util:base_util_unittests/"
+        "test": "gwp_asan_unittests",
+        "test_id_prefix": "ninja://components/gwp_asan:gwp_asan_unittests/"
       },
       {
         "args": [
@@ -25187,8 +25190,8 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "blink_common_unittests",
-        "test_id_prefix": "ninja://third_party/blink/common:blink_common_unittests/"
+        "test": "jingle_unittests",
+        "test_id_prefix": "ninja://jingle:jingle_unittests/"
       },
       {
         "args": [
@@ -25209,8 +25212,8 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "blink_heap_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform/heap:blink_heap_unittests/"
+        "test": "message_center_unittests",
+        "test_id_prefix": "ninja://ui/message_center:message_center_unittests/"
       },
       {
         "args": [
@@ -25231,12 +25234,12 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "blink_platform_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform:blink_platform_unittests/"
+        "test": "midi_unittests",
+        "test_id_prefix": "ninja://media/midi:midi_unittests/"
       },
       {
         "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.blink_unittests.filter",
+          "--child-arg=--ozone-platform=headless",
           "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
         ],
         "merge": {
@@ -25254,8 +25257,8 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "blink_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/controller:blink_unittests/"
+        "test": "ozone_gl_unittests",
+        "test_id_prefix": "ninja://ui/ozone/gl:ozone_gl_unittests/"
       },
       {
         "args": [
@@ -25276,8 +25279,8 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "boringssl_crypto_tests",
-        "test_id_prefix": "ninja://third_party/boringssl:boringssl_crypto_tests/"
+        "test": "ozone_unittests",
+        "test_id_prefix": "ninja://ui/ozone:ozone_unittests/"
       },
       {
         "args": [
@@ -25298,8 +25301,8 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "boringssl_ssl_tests",
-        "test_id_prefix": "ninja://third_party/boringssl:boringssl_ssl_tests/"
+        "test": "ui_touch_selection_unittests",
+        "test_id_prefix": "ninja://ui/touch_selection:ui_touch_selection_unittests/"
       },
       {
         "args": [
@@ -25320,8 +25323,8 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "capture_unittests",
-        "test_id_prefix": "ninja://media/capture:capture_unittests/"
+        "test": "views_examples_unittests",
+        "test_id_prefix": "ninja://ui/views/examples:views_examples_unittests/"
       },
       {
         "args": [
@@ -25342,8 +25345,8 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "cast_runner_browsertests",
-        "test_id_prefix": "ninja://fuchsia/runners:cast_runner_browsertests/"
+        "test": "views_unittests",
+        "test_id_prefix": "ninja://ui/views:views_unittests/"
       },
       {
         "args": [
@@ -25364,8 +25367,8 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "cast_runner_integration_tests",
-        "test_id_prefix": "ninja://fuchsia/runners:cast_runner_integration_tests/"
+        "test": "wm_unittests",
+        "test_id_prefix": "ninja://ui/wm:wm_unittests/"
       },
       {
         "args": [
@@ -25386,847 +25389,8 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "cast_runner_unittests",
-        "test_id_prefix": "ninja://fuchsia/runners:cast_runner_unittests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "cc_unittests",
-        "test_id_prefix": "ninja://cc:cc_unittests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "compositor_unittests",
-        "test_id_prefix": "ninja://ui/compositor:compositor_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.content_unittests.filter",
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "content_unittests",
-        "test_id_prefix": "ninja://content/test:content_unittests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cr_fuchsia_base_unittests",
-        "test_id_prefix": "ninja://fuchsia/base:cr_fuchsia_base_unittests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cronet_tests",
-        "test_id_prefix": "ninja://components/cronet:cronet_tests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cronet_unittests",
-        "test_id_prefix": "ninja://components/cronet:cronet_unittests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "crypto_unittests",
-        "test_id_prefix": "ninja://crypto:crypto_unittests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "display_unittests",
-        "test_id_prefix": "ninja://ui/display:display_unittests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "events_unittests",
-        "test_id_prefix": "ninja://ui/events:events_unittests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gfx_unittests",
-        "test_id_prefix": "ninja://ui/gfx:gfx_unittests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gin_unittests",
-        "test_id_prefix": "ninja://gin:gin_unittests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "google_apis_unittests",
-        "test_id_prefix": "ninja://google_apis:google_apis_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gpu_unittests",
-        "test_id_prefix": "ninja://gpu:gpu_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.headless_browsertests.filter",
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "headless_browsertests",
-        "test_id_prefix": "ninja://headless:headless_browsertests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "headless_unittests",
-        "test_id_prefix": "ninja://headless:headless_unittests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "http_service_tests",
-        "test_id_prefix": "ninja://fuchsia/http:http_service_tests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ipc_tests",
-        "test_id_prefix": "ninja://ipc:ipc_tests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "latency_unittests",
-        "test_id_prefix": "ninja://ui/latency:latency_unittests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "media_unittests",
-        "test_id_prefix": "ninja://media:media_unittests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "mojo_unittests",
-        "test_id_prefix": "ninja://mojo:mojo_unittests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "native_theme_unittests",
-        "test_id_prefix": "ninja://ui/native_theme:native_theme_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.net_unittests.filter",
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 4
-        },
-        "test": "net_unittests",
-        "test_id_prefix": "ninja://net:net_unittests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "perfetto_unittests",
-        "test_id_prefix": "ninja://third_party/perfetto:perfetto_unittests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "service_manager_unittests",
-        "test_id_prefix": "ninja://services/service_manager/tests:service_manager_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.services_unittests.filter",
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "services_unittests",
-        "test_id_prefix": "ninja://services:services_unittests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "shell_dialogs_unittests",
-        "test_id_prefix": "ninja://ui/shell_dialogs:shell_dialogs_unittests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "skia_unittests",
-        "test_id_prefix": "ninja://skia:skia_unittests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "snapshot_unittests",
-        "test_id_prefix": "ninja://ui/snapshot:snapshot_unittests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "sql_unittests",
-        "test_id_prefix": "ninja://sql:sql_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.storage_unittests.filter",
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "storage_unittests",
-        "test_id_prefix": "ninja://storage:storage_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.ui_base_unittests.filter",
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ui_base_unittests",
-        "test_id_prefix": "ninja://ui/base:ui_base_unittests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "url_unittests",
-        "test_id_prefix": "ninja://url:url_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.viz_unittests.filter",
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "viz_unittests",
-        "test_id_prefix": "ninja://components/viz:viz_unittests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "web_engine_browsertests",
-        "test_id_prefix": "ninja://fuchsia/engine:web_engine_browsertests/"
-      },
-      {
-        "args": [
-          "--child-arg=--vmodule=test_navigation_listener=1"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "web_engine_integration_tests",
-        "test_id_prefix": "ninja://fuchsia/engine:web_engine_integration_tests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "web_engine_unittests",
-        "test_id_prefix": "ninja://fuchsia/engine:web_engine_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "web_runner_integration_tests",
-        "test_id_prefix": "ninja://fuchsia/runners:web_runner_integration_tests/"
-      },
-      {
-        "args": [
-          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "arm64",
-              "inside_docker": "1",
-              "os": "Ubuntu-20.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "wtf_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform/wtf:wtf_unittests/"
+        "test": "zlib_unittests",
+        "test_id_prefix": "ninja://third_party/zlib:zlib_unittests/"
       }
     ]
   },
@@ -27399,8 +26563,8 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "cast_runner_browsertests",
-        "test_id_prefix": "ninja://fuchsia/runners:cast_runner_browsertests/"
+        "test": "color_unittests",
+        "test_id_prefix": "ninja://ui/color:color_unittests/"
       },
       {
         "args": [
@@ -27420,8 +26584,8 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "cast_runner_integration_tests",
-        "test_id_prefix": "ninja://fuchsia/runners:cast_runner_integration_tests/"
+        "test": "courgette_unittests",
+        "test_id_prefix": "ninja://courgette:courgette_unittests/"
       },
       {
         "args": [
@@ -27441,8 +26605,8 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "cast_runner_unittests",
-        "test_id_prefix": "ninja://fuchsia/runners:cast_runner_unittests/"
+        "test": "fuchsia_mojo_unittests",
+        "test_id_prefix": "ninja://fuchsia/mojom:fuchsia_mojo_unittests/"
       },
       {
         "args": [
@@ -27462,8 +26626,8 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "cr_fuchsia_base_unittests",
-        "test_id_prefix": "ninja://fuchsia/base:cr_fuchsia_base_unittests/"
+        "test": "gcm_unit_tests",
+        "test_id_prefix": "ninja://google_apis/gcm:gcm_unit_tests/"
       },
       {
         "args": [
@@ -27483,29 +26647,8 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "web_engine_browsertests",
-        "test_id_prefix": "ninja://fuchsia/engine:web_engine_browsertests/"
-      },
-      {
-        "args": [
-          "--child-arg=--vmodule=test_navigation_listener=1"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "kvm": "1",
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "web_engine_integration_tests",
-        "test_id_prefix": "ninja://fuchsia/engine:web_engine_integration_tests/"
+        "test": "gwp_asan_unittests",
+        "test_id_prefix": "ninja://components/gwp_asan:gwp_asan_unittests/"
       },
       {
         "args": [
@@ -27525,10 +26668,13 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "web_engine_unittests",
-        "test_id_prefix": "ninja://fuchsia/engine:web_engine_unittests/"
+        "test": "jingle_unittests",
+        "test_id_prefix": "ninja://jingle:jingle_unittests/"
       },
       {
+        "args": [
+          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
+        ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -27543,8 +26689,177 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "web_runner_integration_tests",
-        "test_id_prefix": "ninja://fuchsia/runners:web_runner_integration_tests/"
+        "test": "message_center_unittests",
+        "test_id_prefix": "ninja://ui/message_center:message_center_unittests/"
+      },
+      {
+        "args": [
+          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "midi_unittests",
+        "test_id_prefix": "ninja://media/midi:midi_unittests/"
+      },
+      {
+        "args": [
+          "--child-arg=--ozone-platform=headless",
+          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "ozone_gl_unittests",
+        "test_id_prefix": "ninja://ui/ozone/gl:ozone_gl_unittests/"
+      },
+      {
+        "args": [
+          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "ozone_unittests",
+        "test_id_prefix": "ninja://ui/ozone:ozone_unittests/"
+      },
+      {
+        "args": [
+          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "ui_touch_selection_unittests",
+        "test_id_prefix": "ninja://ui/touch_selection:ui_touch_selection_unittests/"
+      },
+      {
+        "args": [
+          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "views_examples_unittests",
+        "test_id_prefix": "ninja://ui/views/examples:views_examples_unittests/"
+      },
+      {
+        "args": [
+          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "views_unittests",
+        "test_id_prefix": "ninja://ui/views:views_unittests/"
+      },
+      {
+        "args": [
+          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "wm_unittests",
+        "test_id_prefix": "ninja://ui/wm:wm_unittests/"
+      },
+      {
+        "args": [
+          "--runner-logs-dir=${ISOLATED_OUTDIR}/runner_logs"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "zlib_unittests",
+        "test_id_prefix": "ninja://third_party/zlib:zlib_unittests/"
       }
     ],
     "isolated_scripts": [
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 8cad6dc..22ef052 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -842,6 +842,10 @@
     "script": "//testing/scripts/run_flatbuffers_unittests.py",
     "type": "script",
   },
+  "fuchsia_mojo_unittests": {
+    "label": "//fuchsia/mojom:fuchsia_mojo_unittests",
+    "type": "console_test_launcher",
+  },
   "fuchsia_sizes": {
     "label": "//fuchsia/release:fuchsia_sizes",
     "type": "generated_script",
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 1a4c01a..6e582305e 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -1104,6 +1104,10 @@
     ],
   },
   'components_browsertests': {
+    'remove_from': [
+      'fuchsia-fyi-arm64-rel',  # https://crbug.com/961457
+      'fuchsia-fyi-x64-rel',  # https://crbug.com/961457
+    ],
     'modifications': {
       'android-11-x86-fyi-rel': {
         'swarming': {
@@ -1121,9 +1125,7 @@
       'fuchsia-code-coverage',  # https://crbug.com/961457
       'fuchsia-fyi-arm64-dbg',  # https://crbug.com/961457
       'fuchsia-fyi-arm64-femu',  # https://crbug.com/961457
-      'fuchsia-fyi-arm64-rel',  # https://crbug.com/961457
       'fuchsia-fyi-x64-dbg',  # https://crbug.com/961457
-      'fuchsia-fyi-x64-rel',  # https://crbug.com/961457
       'ToTFuchsia x64',  # https://crbug.com/961457
       'ToTFuchsiaOfficial',  # https://crbug.com/961457
     ],
@@ -1187,8 +1189,9 @@
     'remove_from': [
       'CrWinAsan(dll)', # https://crbug.com/935598
       'android-lollipop-arm-rel', # crbug.com/1133002
-      # http://crbug.com/1060245#c30: due to low utility and capacity.
-      'android-marshmallow-arm64-rel',
+      'android-marshmallow-arm64-rel', # http://crbug.com/1060245#c30: due to low utility and capacity.
+      'fuchsia-fyi-arm64-rel',  # https://crbug.com/1164534
+      'fuchsia-fyi-x64-rel',  # https://crbug.com/1164534
     ],
     'modifications': {
       'Cast Audio Linux': {
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 185aa6f..87d3c19 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -1599,6 +1599,63 @@
       },
     },
 
+    'fuchsia_experimental_gtests': {
+      'color_unittests': {
+        'mixins': ['fuchsia_runner_logs'],
+      },
+      'components_browsertests': {
+        'mixins': ['fuchsia_runner_logs'],
+      },
+      'content_browsertests': {
+        'mixins': ['fuchsia_runner_logs'],
+      },
+      'courgette_unittests': {
+        'mixins': ['fuchsia_runner_logs'],
+      },
+      'fuchsia_mojo_unittests': {
+        'mixins': ['fuchsia_runner_logs'],
+      },
+      'gcm_unit_tests': {
+        'mixins': ['fuchsia_runner_logs'],
+      },
+      'gwp_asan_unittests': {
+        'mixins': ['fuchsia_runner_logs'],
+      },
+      'jingle_unittests': {
+        'mixins': ['fuchsia_runner_logs'],
+      },
+      'message_center_unittests': {
+        'mixins': ['fuchsia_runner_logs'],
+      },
+      'midi_unittests': {
+        'mixins': ['fuchsia_runner_logs'],
+      },
+      'ozone_gl_unittests': {
+        'mixins': ['fuchsia_runner_logs'],
+        'args': [
+          '--child-arg=--ozone-platform=headless',
+        ],
+      },
+      'ozone_unittests': {
+        'mixins': ['fuchsia_runner_logs'],
+      },
+      'ui_touch_selection_unittests': {
+        'mixins': ['fuchsia_runner_logs'],
+      },
+      'views_examples_unittests': {
+        'mixins': ['fuchsia_runner_logs'],
+      },
+      'views_unittests': {
+        'mixins': ['fuchsia_runner_logs'],
+      },
+      'wm_unittests': {
+        'mixins': ['fuchsia_runner_logs'],
+      },
+      'zlib_unittests': {
+        'mixins': ['fuchsia_runner_logs'],
+      },
+    },
+
     'fuchsia_gpu_telemetry_tests': {
       'context_lost_validating': {
         'isolate_name': 'fuchsia_telemetry_gpu_integration_test',
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 8b86704..3965b94c 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -2863,7 +2863,7 @@
           'all',
         ],
         'test_suites': {
-          'gtest_tests': 'fuchsia_gtests',
+          'gtest_tests': 'fuchsia_experimental_gtests',
         },
         'mixins': [
           'arm64',
@@ -2908,7 +2908,7 @@
         },
         'test_suites': {
           'gpu_telemetry_tests': 'fuchsia_gpu_telemetry_tests',
-          'gtest_tests': 'web_engine_gtests',
+          'gtest_tests': 'fuchsia_experimental_gtests',
         },
       },
       'ios-asan': {
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index aed62f4..dc109abd 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -5530,28 +5530,6 @@
             ]
         }
     ],
-    "OmniboxOnDeviceHeadSuggestBigModel": [
-        {
-            "platforms": [
-                "windows",
-                "mac",
-                "chromeos",
-                "chromeos_lacros",
-                "linux"
-            ],
-            "experiments": [
-                {
-                    "name": "500K",
-                    "params": {
-                        "ForceModelLocaleConstraint": "500000"
-                    },
-                    "enable_features": [
-                        "OmniboxOnDeviceHeadProviderIncognito"
-                    ]
-                }
-            ]
-        }
-    ],
     "OmniboxPedalsBatch2": [
         {
             "platforms": [
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom
index 327efd9..bf1047f0 100644
--- a/third_party/blink/public/mojom/web_feature/web_feature.mojom
+++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -2694,9 +2694,9 @@
   kV8FontManager_Query_Method = 3386,
   kAudioContextBaseLatency = 3387,
   kV8Window_GetScreens_Method = 3388,
-  kV8Window_IsMultiScreen_Method = 3389,
-  kV8Window_Onscreenschange_AttributeGetter = 3390,
-  kV8Window_Onscreenschange_AttributeSetter = 3391,
+  kOBSOLETE_V8Window_IsMultiScreen_Method = 3389,
+  kOBSOLETE_V8Window_Onscreenschange_AttributeGetter = 3390,
+  kOBSOLETE_V8Window_Onscreenschange_AttributeSetter = 3391,
   kDOMWindowOpenPositioningFeaturesCrossScreen = 3392,
   kDOMWindowSetWindowRectCrossScreen = 3393,
   kFullscreenCrossScreen = 3394,
diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni
index 171bae0e..0a5bc95 100644
--- a/third_party/blink/renderer/bindings/generated_in_modules.gni
+++ b/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -227,8 +227,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_close_event_init.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_collected_client_data.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_collected_client_data.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_select_event_init.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_select_event_init.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_selection_result.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_selection_result.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_compute_pressure_observer_options.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_compute_pressure_observer_options.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_compute_pressure_observer_update.cc",
@@ -1505,8 +1505,6 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_clipboard_item.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_close_event.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_close_event.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_select_event.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_select_event.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_compression_stream.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_compression_stream.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_compute_pressure_observer.cc",
diff --git a/third_party/blink/renderer/bindings/idl_in_modules.gni b/third_party/blink/renderer/bindings/idl_in_modules.gni
index d0f877e..6b462f1a 100644
--- a/third_party/blink/renderer/bindings/idl_in_modules.gni
+++ b/third_party/blink/renderer/bindings/idl_in_modules.gni
@@ -229,8 +229,7 @@
           "//third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.idl",
           "//third_party/blink/renderer/modules/eventsource/event_source.idl",
           "//third_party/blink/renderer/modules/eventsource/event_source_init.idl",
-          "//third_party/blink/renderer/modules/eyedropper/color_select_event.idl",
-          "//third_party/blink/renderer/modules/eyedropper/color_select_event_init.idl",
+          "//third_party/blink/renderer/modules/eyedropper/color_selection_result.idl",
           "//third_party/blink/renderer/modules/eyedropper/eye_dropper.idl",
           "//third_party/blink/renderer/modules/file_system_access/data_transfer_item_file_system_access.idl",
           "//third_party/blink/renderer/modules/file_system_access/directory_picker_options.idl",
diff --git a/third_party/blink/renderer/core/DEPS b/third_party/blink/renderer/core/DEPS
index e576aa7..1c88f94e 100644
--- a/third_party/blink/renderer/core/DEPS
+++ b/third_party/blink/renderer/core/DEPS
@@ -62,6 +62,7 @@
     "+cc/trees/browser_controls_params.h",
     "+cc/trees/layer_tree_host.h",
     "+cc/trees/paint_holding_commit_trigger.h",
+    "+cc/trees/paint_holding_reason.h",
     "+cc/trees/ukm_manager.h",
     "+components/performance_manager/public/mojom/coordination_unit.mojom-blink.h",
     "+components/performance_manager/public/mojom/web_memory.mojom-blink.h",
diff --git a/third_party/blink/renderer/core/animation/animation.cc b/third_party/blink/renderer/core/animation/animation.cc
index d9ee626..545dcd7f 100644
--- a/third_party/blink/renderer/core/animation/animation.cc
+++ b/third_party/blink/renderer/core/animation/animation.cc
@@ -854,6 +854,15 @@
   AnimationPlayState old_play_state = CalculateAnimationPlayState();
   absl::optional<AnimationTimeDelta> old_current_time = CurrentTimeInternal();
 
+  // In some cases, we need to preserve the progress of the animation between
+  // the old timeline and the new one. We do this by storing the progress using
+  // the old current time and the effect end based on the old timeline. Pending
+  // spec issue: https://github.com/w3c/csswg-drafts/issues/6452
+  double progress = 0;
+  if (old_current_time && !EffectEnd().is_zero()) {
+    progress = old_current_time.value() / EffectEnd();
+  }
+
   CancelAnimationOnCompositor();
 
   // 3. Let the timeline of the animation be the new timeline.
@@ -873,7 +882,8 @@
     document_->Timeline().AnimationAttached(this);
   SetOutdated();
 
-  // Update content timing to be based on new timeline type
+  // Update content timing to be based on new timeline type. This ensures that
+  // EffectEnd() is returning a value appropriate to the new timeline.
   if (content_ && timeline_)
     content_->InvalidateNormalizedTiming();
 
@@ -899,7 +909,8 @@
           if (old_current_time) {
             reset_current_time_on_resume_ = true;
             start_time_ = absl::nullopt;
-            SetHoldTimeAndPhase(old_current_time, TimelinePhase::kInactive);
+            SetHoldTimeAndPhase(progress * EffectEnd(),
+                                TimelinePhase::kInactive);
           } else if (PendingInternal()) {
             start_time_ = boundary_time;
           }
@@ -910,7 +921,7 @@
       }
     } else if (old_current_time && old_timeline &&
                !old_timeline->IsMonotonicallyIncreasing()) {
-      SetCurrentTimeInternal(old_current_time.value());
+      SetCurrentTimeInternal(progress * EffectEnd());
     }
   }
 
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5
index ce8e89b6..4eb8fdc 100644
--- a/third_party/blink/renderer/core/css/css_properties.json5
+++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -2641,22 +2641,7 @@
       wrapper_pointer_name: "Persistent",
       default_value: "ListStyleTypeData::CreateCounterStyle(\"disc\", nullptr)",
       type_name: "ListStyleTypeData",
-      keywords: [
-        "disc", "circle", "square", "disclosure-open", "disclosure-closed",
-        "decimal", "decimal-leading-zero",
-        "arabic-indic", "bengali", "cambodian", "khmer", "devanagari",
-        "gujarati", "gurmukhi", "kannada", "lao", "malayalam", "mongolian",
-        "myanmar", "oriya", "persian", "urdu", "telugu", "tibetan", "thai",
-        "lower-roman", "upper-roman", "lower-greek", "lower-alpha",
-        "lower-latin", "upper-alpha", "upper-latin", "cjk-earthly-branch",
-        "cjk-heavenly-stem", "ethiopic-halehame", "ethiopic-halehame-am",
-        "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "hangul",
-        "hangul-consonant", "korean-hangul-formal", "korean-hanja-formal",
-        "korean-hanja-informal", "hebrew", "armenian", "lower-armenian",
-        "upper-armenian", "georgian", "cjk-ideographic", "simp-chinese-formal",
-        "simp-chinese-informal", "trad-chinese-formal", "trad-chinese-informal",
-        "hiragana", "katakana", "hiragana-iroha", "katakana-iroha", "none"
-      ],
+      keywords: ["disc", "decimal", "none"],
       style_builder_custom_functions: ["initial", "inherit", "value"],
       tree_scoped_value: true,
     },
diff --git a/third_party/blink/renderer/core/css/css_value_id_mappings.h b/third_party/blink/renderer/core/css/css_value_id_mappings.h
index b7e13c7..0076e64a 100644
--- a/third_party/blink/renderer/core/css/css_value_id_mappings.h
+++ b/third_party/blink/renderer/core/css/css_value_id_mappings.h
@@ -177,132 +177,6 @@
 }
 
 template <>
-inline EListStyleType CssValueIDToPlatformEnum(CSSValueID v) {
-  switch (v) {
-    case CSSValueID::kDisc:
-      return EListStyleType::kDisc;
-    case CSSValueID::kCircle:
-      return EListStyleType::kCircle;
-    case CSSValueID::kSquare:
-      return EListStyleType::kSquare;
-    case CSSValueID::kDisclosureOpen:
-      return EListStyleType::kDisclosureOpen;
-    case CSSValueID::kDisclosureClosed:
-      return EListStyleType::kDisclosureClosed;
-    case CSSValueID::kDecimal:
-      return EListStyleType::kDecimal;
-    case CSSValueID::kDecimalLeadingZero:
-      return EListStyleType::kDecimalLeadingZero;
-    case CSSValueID::kArabicIndic:
-      return EListStyleType::kArabicIndic;
-    case CSSValueID::kBengali:
-      return EListStyleType::kBengali;
-    case CSSValueID::kCambodian:
-      return EListStyleType::kCambodian;
-    case CSSValueID::kKhmer:
-      return EListStyleType::kKhmer;
-    case CSSValueID::kDevanagari:
-      return EListStyleType::kDevanagari;
-    case CSSValueID::kGujarati:
-      return EListStyleType::kGujarati;
-    case CSSValueID::kGurmukhi:
-      return EListStyleType::kGurmukhi;
-    case CSSValueID::kKannada:
-      return EListStyleType::kKannada;
-    case CSSValueID::kLao:
-      return EListStyleType::kLao;
-    case CSSValueID::kMalayalam:
-      return EListStyleType::kMalayalam;
-    case CSSValueID::kMongolian:
-      return EListStyleType::kMongolian;
-    case CSSValueID::kMyanmar:
-      return EListStyleType::kMyanmar;
-    case CSSValueID::kOriya:
-      return EListStyleType::kOriya;
-    case CSSValueID::kPersian:
-      return EListStyleType::kPersian;
-    case CSSValueID::kUrdu:
-      return EListStyleType::kUrdu;
-    case CSSValueID::kTelugu:
-      return EListStyleType::kTelugu;
-    case CSSValueID::kTibetan:
-      return EListStyleType::kTibetan;
-    case CSSValueID::kThai:
-      return EListStyleType::kThai;
-    case CSSValueID::kLowerRoman:
-      return EListStyleType::kLowerRoman;
-    case CSSValueID::kUpperRoman:
-      return EListStyleType::kUpperRoman;
-    case CSSValueID::kLowerGreek:
-      return EListStyleType::kLowerGreek;
-    case CSSValueID::kLowerAlpha:
-      return EListStyleType::kLowerAlpha;
-    case CSSValueID::kLowerLatin:
-      return EListStyleType::kLowerLatin;
-    case CSSValueID::kUpperAlpha:
-      return EListStyleType::kUpperAlpha;
-    case CSSValueID::kUpperLatin:
-      return EListStyleType::kUpperLatin;
-    case CSSValueID::kCjkEarthlyBranch:
-      return EListStyleType::kCjkEarthlyBranch;
-    case CSSValueID::kCjkHeavenlyStem:
-      return EListStyleType::kCjkHeavenlyStem;
-    case CSSValueID::kEthiopicHalehame:
-      return EListStyleType::kEthiopicHalehame;
-    case CSSValueID::kEthiopicHalehameAm:
-      return EListStyleType::kEthiopicHalehameAm;
-    case CSSValueID::kEthiopicHalehameTiEr:
-      return EListStyleType::kEthiopicHalehameTiEr;
-    case CSSValueID::kEthiopicHalehameTiEt:
-      return EListStyleType::kEthiopicHalehameTiEt;
-    case CSSValueID::kHangul:
-      return EListStyleType::kHangul;
-    case CSSValueID::kHangulConsonant:
-      return EListStyleType::kHangulConsonant;
-    case CSSValueID::kKoreanHangulFormal:
-      return EListStyleType::kKoreanHangulFormal;
-    case CSSValueID::kKoreanHanjaFormal:
-      return EListStyleType::kKoreanHanjaFormal;
-    case CSSValueID::kKoreanHanjaInformal:
-      return EListStyleType::kKoreanHanjaInformal;
-    case CSSValueID::kHebrew:
-      return EListStyleType::kHebrew;
-    case CSSValueID::kArmenian:
-      return EListStyleType::kArmenian;
-    case CSSValueID::kLowerArmenian:
-      return EListStyleType::kLowerArmenian;
-    case CSSValueID::kUpperArmenian:
-      return EListStyleType::kUpperArmenian;
-    case CSSValueID::kGeorgian:
-      return EListStyleType::kGeorgian;
-    case CSSValueID::kCjkIdeographic:
-      return EListStyleType::kCjkIdeographic;
-    case CSSValueID::kSimpChineseFormal:
-      return EListStyleType::kSimpChineseFormal;
-    case CSSValueID::kSimpChineseInformal:
-      return EListStyleType::kSimpChineseInformal;
-    case CSSValueID::kTradChineseFormal:
-      return EListStyleType::kTradChineseFormal;
-    case CSSValueID::kTradChineseInformal:
-      return EListStyleType::kTradChineseInformal;
-    case CSSValueID::kHiragana:
-      return EListStyleType::kHiragana;
-    case CSSValueID::kKatakana:
-      return EListStyleType::kKatakana;
-    case CSSValueID::kHiraganaIroha:
-      return EListStyleType::kHiraganaIroha;
-    case CSSValueID::kKatakanaIroha:
-      return EListStyleType::kKatakanaIroha;
-    case CSSValueID::kNone:
-      return EListStyleType::kNone;
-    default:
-      break;
-  }
-
-  return EListStyleType::kNone;
-}
-
-template <>
 inline EUserSelect CssValueIDToPlatformEnum(CSSValueID v) {
   if (v == CSSValueID::kAuto)
     return EUserSelect::kAuto;
@@ -365,134 +239,6 @@
 }
 
 template <>
-inline CSSValueID PlatformEnumToCSSValueID(EListStyleType v) {
-  switch (v) {
-    case EListStyleType::kDisc:
-      return CSSValueID::kDisc;
-    case EListStyleType::kCircle:
-      return CSSValueID::kCircle;
-    case EListStyleType::kSquare:
-      return CSSValueID::kSquare;
-    case EListStyleType::kDisclosureOpen:
-      return CSSValueID::kDisclosureOpen;
-    case EListStyleType::kDisclosureClosed:
-      return CSSValueID::kDisclosureClosed;
-    case EListStyleType::kDecimal:
-      return CSSValueID::kDecimal;
-    case EListStyleType::kDecimalLeadingZero:
-      return CSSValueID::kDecimalLeadingZero;
-    case EListStyleType::kArabicIndic:
-      return CSSValueID::kArabicIndic;
-    case EListStyleType::kBengali:
-      return CSSValueID::kBengali;
-    case EListStyleType::kCambodian:
-      return CSSValueID::kCambodian;
-    case EListStyleType::kKhmer:
-      return CSSValueID::kKhmer;
-    case EListStyleType::kDevanagari:
-      return CSSValueID::kDevanagari;
-    case EListStyleType::kGujarati:
-      return CSSValueID::kGujarati;
-    case EListStyleType::kGurmukhi:
-      return CSSValueID::kGurmukhi;
-    case EListStyleType::kKannada:
-      return CSSValueID::kKannada;
-    case EListStyleType::kLao:
-      return CSSValueID::kLao;
-    case EListStyleType::kMalayalam:
-      return CSSValueID::kMalayalam;
-    case EListStyleType::kMongolian:
-      return CSSValueID::kMongolian;
-    case EListStyleType::kMyanmar:
-      return CSSValueID::kMyanmar;
-    case EListStyleType::kOriya:
-      return CSSValueID::kOriya;
-    case EListStyleType::kPersian:
-      return CSSValueID::kPersian;
-    case EListStyleType::kUrdu:
-      return CSSValueID::kUrdu;
-    case EListStyleType::kTelugu:
-      return CSSValueID::kTelugu;
-    case EListStyleType::kTibetan:
-      return CSSValueID::kTibetan;
-    case EListStyleType::kThai:
-      return CSSValueID::kThai;
-    case EListStyleType::kLowerRoman:
-      return CSSValueID::kLowerRoman;
-    case EListStyleType::kUpperRoman:
-      return CSSValueID::kUpperRoman;
-    case EListStyleType::kLowerGreek:
-      return CSSValueID::kLowerGreek;
-    case EListStyleType::kLowerAlpha:
-      return CSSValueID::kLowerAlpha;
-    case EListStyleType::kLowerLatin:
-      return CSSValueID::kLowerLatin;
-    case EListStyleType::kUpperAlpha:
-      return CSSValueID::kUpperAlpha;
-    case EListStyleType::kUpperLatin:
-      return CSSValueID::kUpperLatin;
-    case EListStyleType::kCjkEarthlyBranch:
-      return CSSValueID::kCjkEarthlyBranch;
-    case EListStyleType::kCjkHeavenlyStem:
-      return CSSValueID::kCjkHeavenlyStem;
-    case EListStyleType::kEthiopicHalehame:
-      return CSSValueID::kEthiopicHalehame;
-    case EListStyleType::kEthiopicHalehameAm:
-      return CSSValueID::kEthiopicHalehameAm;
-    case EListStyleType::kEthiopicHalehameTiEr:
-      return CSSValueID::kEthiopicHalehameTiEr;
-    case EListStyleType::kEthiopicHalehameTiEt:
-      return CSSValueID::kEthiopicHalehameTiEt;
-    case EListStyleType::kHangul:
-      return CSSValueID::kHangul;
-    case EListStyleType::kHangulConsonant:
-      return CSSValueID::kHangulConsonant;
-    case EListStyleType::kKoreanHangulFormal:
-      return CSSValueID::kKoreanHangulFormal;
-    case EListStyleType::kKoreanHanjaFormal:
-      return CSSValueID::kKoreanHanjaFormal;
-    case EListStyleType::kKoreanHanjaInformal:
-      return CSSValueID::kKoreanHanjaInformal;
-    case EListStyleType::kHebrew:
-      return CSSValueID::kHebrew;
-    case EListStyleType::kArmenian:
-      return CSSValueID::kArmenian;
-    case EListStyleType::kLowerArmenian:
-      return CSSValueID::kLowerArmenian;
-    case EListStyleType::kUpperArmenian:
-      return CSSValueID::kUpperArmenian;
-    case EListStyleType::kGeorgian:
-      return CSSValueID::kGeorgian;
-    case EListStyleType::kCjkIdeographic:
-      return CSSValueID::kCjkIdeographic;
-    case EListStyleType::kSimpChineseFormal:
-      return CSSValueID::kSimpChineseFormal;
-    case EListStyleType::kSimpChineseInformal:
-      return CSSValueID::kSimpChineseInformal;
-    case EListStyleType::kTradChineseFormal:
-      return CSSValueID::kTradChineseFormal;
-    case EListStyleType::kTradChineseInformal:
-      return CSSValueID::kTradChineseInformal;
-    case EListStyleType::kHiragana:
-      return CSSValueID::kHiragana;
-    case EListStyleType::kKatakana:
-      return CSSValueID::kKatakana;
-    case EListStyleType::kHiraganaIroha:
-      return CSSValueID::kHiraganaIroha;
-    case EListStyleType::kKatakanaIroha:
-      return CSSValueID::kKatakanaIroha;
-    case EListStyleType::kNone:
-      return CSSValueID::kNone;
-    case EListStyleType::kString:
-      NOTREACHED();
-      break;
-  }
-
-  NOTREACHED();
-  return CSSValueID::kDisc;
-}
-
-template <>
 inline PageOrientation CssValueIDToPlatformEnum(CSSValueID v) {
   if (v == CSSValueID::kUpright)
     return PageOrientation::kUpright;
diff --git a/third_party/blink/renderer/core/css/css_value_keywords.json5 b/third_party/blink/renderer/core/css/css_value_keywords.json5
index f7db0210..cbcede64 100644
--- a/third_party/blink/renderer/core/css/css_value_keywords.json5
+++ b/third_party/blink/renderer/core/css/css_value_keywords.json5
@@ -430,65 +430,9 @@
     "inside",
     //
     // list-style-type
-    // The order of this enum must match the order found in CSSParserFastPaths::IsValidKeywordPropertyAndValue().
     //
     "disc",
-    "circle",
-    "square",
-    "disclosure-open",
-    "disclosure-closed",
     "decimal",
-    "decimal-leading-zero",
-    "arabic-indic",
-    "bengali",
-    "cambodian",
-    "khmer",
-    "devanagari",
-    "gujarati",
-    "gurmukhi",
-    "kannada",
-    "lao",
-    "malayalam",
-    "mongolian",
-    "myanmar",
-    "oriya",
-    "persian",
-    "urdu",
-    "telugu",
-    "tibetan",
-    "thai",
-    "lower-roman",
-    "upper-roman",
-    "lower-greek",
-    "lower-alpha",
-    "lower-latin",
-    "upper-alpha",
-    "upper-latin",
-    "cjk-earthly-branch",
-    "cjk-heavenly-stem",
-    "ethiopic-halehame",
-    "ethiopic-halehame-am",
-    "ethiopic-halehame-ti-er",
-    "ethiopic-halehame-ti-et",
-    "hangul",
-    "hangul-consonant",
-    "korean-hangul-formal",
-    "korean-hanja-formal",
-    "korean-hanja-informal",
-    "hebrew",
-    "armenian",
-    "lower-armenian",
-    "upper-armenian",
-    "georgian",
-    "cjk-ideographic",
-    "simp-chinese-formal",
-    "simp-chinese-informal",
-    "trad-chinese-formal",
-    "trad-chinese-informal",
-    "hiragana",
-    "katakana",
-    "hiragana-iroha",
-    "katakana-iroha",
     //none
     //
     // The order must match the order found in IsDisplayOutside().
@@ -1011,7 +955,7 @@
     "filled",
     "open",
     "dot",
-    // circle
+    "circle",
     "double-circle",
     "triangle",
     "sesame",
@@ -1142,7 +1086,7 @@
     // stroke-linecap
     "butt",
     // round
-    // square
+    "square",
 
     // stroke-linejoin
     "miter",
diff --git a/third_party/blink/renderer/core/document_transition/document_transition.cc b/third_party/blink/renderer/core/document_transition/document_transition.cc
index 4c52d1a..55ab927a 100644
--- a/third_party/blink/renderer/core/document_transition/document_transition.cc
+++ b/third_party/blink/renderer/core/document_transition/document_transition.cc
@@ -4,16 +4,20 @@
 
 #include "third_party/blink/renderer/core/document_transition/document_transition.h"
 
+#include "base/trace_event/trace_event.h"
 #include "cc/document_transition/document_transition_request.h"
+#include "cc/trees/paint_holding_reason.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_document_transition_prepare_options.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_document_transition_start_options.h"
+#include "third_party/blink/renderer/core/dom/abort_signal.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/dom_node_ids.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
 #include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
+#include "third_party/blink/renderer/core/page/chrome_client.h"
 #include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
@@ -24,6 +28,9 @@
 namespace blink {
 namespace {
 
+const char kAbortedFromPrepare[] = "Aborted due to prepare() call";
+const char kAbortedFromSignal[] = "Aborted due to abortSignal";
+
 DocumentTransition::Request::Effect ParseEffect(const String& input) {
   using MapType = HashMap<String, DocumentTransition::Request::Effect>;
   DEFINE_STATIC_LOCAL(
@@ -70,6 +77,7 @@
   visitor->Trace(prepare_promise_resolver_);
   visitor->Trace(start_promise_resolver_);
   visitor->Trace(active_shared_elements_);
+  visitor->Trace(signal_);
 
   ScriptWrappable::Trace(visitor);
   ActiveScriptWrappable::Trace(visitor);
@@ -86,6 +94,8 @@
     start_promise_resolver_ = nullptr;
   }
   active_shared_elements_.clear();
+  signal_ = nullptr;
+  StopDeferringCommits();
 }
 
 bool DocumentTransition::HasPendingActivity() const {
@@ -100,12 +110,7 @@
     ExceptionState& exception_state) {
   // Reject any previous prepare promises.
   if (state_ == State::kPreparing || state_ == State::kPrepared) {
-    if (prepare_promise_resolver_) {
-      prepare_promise_resolver_->Reject(MakeGarbageCollected<DOMException>(
-          DOMExceptionCode::kAbortError, "Aborted due to prepare() call"));
-      prepare_promise_resolver_ = nullptr;
-    }
-    state_ = State::kIdle;
+    CancelPendingTransition(kAbortedFromPrepare);
   }
 
   // Get the sequence id before any early outs so we will correctly process
@@ -128,6 +133,19 @@
     return ScriptPromise();
   }
 
+  if (options->hasAbortSignal()) {
+    if (options->abortSignal()->aborted()) {
+      exception_state.ThrowDOMException(DOMExceptionCode::kAbortError,
+                                        kAbortedFromSignal);
+      return ScriptPromise();
+    }
+
+    signal_ = options->abortSignal();
+    signal_->AddAlgorithm(WTF::Bind(&DocumentTransition::Abort,
+                                    WrapWeakPersistent(this),
+                                    WrapWeakPersistent(signal_.Get())));
+  }
+
   // We're going to be creating a new transition, parse the options.
   auto effect = ParseRootTransition(options);
   if (options->hasSharedElements())
@@ -148,6 +166,15 @@
   return prepare_promise_resolver_->Promise();
 }
 
+void DocumentTransition::Abort(AbortSignal* signal) {
+  // There is no RemoveAlgorithm() method on AbortSignal so compare the signal
+  // bound to this callback to the one last passed to start().
+  if (signal_ != signal)
+    return;
+
+  CancelPendingTransition(kAbortedFromSignal);
+}
+
 ScriptPromise DocumentTransition::start(
     ScriptState* script_state,
     const DocumentTransitionStartOptions* options,
@@ -159,6 +186,8 @@
     return ScriptPromise();
   }
 
+  signal_ = nullptr;
+  StopDeferringCommits();
   if (options->hasSharedElements())
     SetActiveSharedElements(options->sharedElements());
 
@@ -212,6 +241,9 @@
   DCHECK(state_ == State::kPreparing);
   DCHECK(prepare_promise_resolver_);
 
+  // Defer commits before resolving the promise to ensure any updates made in
+  // the callback are deferred.
+  StartDeferringCommits();
   prepare_promise_resolver_->Resolve();
   prepare_promise_resolver_ = nullptr;
   state_ = State::kPrepared;
@@ -324,4 +356,54 @@
   }
 }
 
+void DocumentTransition::StartDeferringCommits() {
+  DCHECK(!deferring_commits_);
+
+  if (!document_->GetPage() || !document_->View())
+    return;
+
+  // Don't do paint holding if it could already be in progress for first
+  // contentful paint.
+  if (document_->View()->WillDoPaintHoldingForFCP())
+    return;
+
+  // Based on the viz side timeout to hold snapshots for 5 seconds.
+  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
+      "blink", "DocumentTransition::DeferringCommits", this);
+  constexpr base::TimeDelta kTimeout = base::TimeDelta::FromSeconds(4);
+  deferring_commits_ =
+      document_->GetPage()->GetChromeClient().StartDeferringCommits(
+          *document_->GetFrame(), kTimeout,
+          cc::PaintHoldingReason::kDocumentTransition);
+}
+
+void DocumentTransition::StopDeferringCommits() {
+  if (!deferring_commits_)
+    return;
+
+  TRACE_EVENT_NESTABLE_ASYNC_END0("blink",
+                                  "DocumentTransition::DeferringCommits", this);
+  deferring_commits_ = false;
+  if (!document_->GetPage())
+    return;
+
+  document_->GetPage()->GetChromeClient().StopDeferringCommits(
+      *document_->GetFrame(),
+      cc::PaintHoldingCommitTrigger::kDocumentTransition);
+}
+
+void DocumentTransition::CancelPendingTransition(const char* abort_message) {
+  DCHECK(state_ == State::kPreparing || state_ == State::kPrepared)
+      << "Can not cancel transition at state : " << static_cast<int>(state_);
+
+  if (prepare_promise_resolver_) {
+    prepare_promise_resolver_->Reject(MakeGarbageCollected<DOMException>(
+        DOMExceptionCode::kAbortError, abort_message));
+    prepare_promise_resolver_ = nullptr;
+  }
+  StopDeferringCommits();
+  state_ = State::kIdle;
+  signal_ = nullptr;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/document_transition/document_transition.h b/third_party/blink/renderer/core/document_transition/document_transition.h
index 67a6863..0f1a7e6d 100644
--- a/third_party/blink/renderer/core/document_transition/document_transition.h
+++ b/third_party/blink/renderer/core/document_transition/document_transition.h
@@ -20,6 +20,7 @@
 
 namespace blink {
 
+class AbortSignal;
 class Document;
 class DocumentTransitionPrepareOptions;
 class DocumentTransitionStartOptions;
@@ -87,12 +88,24 @@
   void SetActiveSharedElements(HeapVector<Member<Element>> elements);
   void InvalidateActiveElements();
 
+  // Used to defer visual updates between transition prepare finishing and
+  // transition start to allow the page to set up the final scene
+  // asynchronously.
+  void StartDeferringCommits();
+  void StopDeferringCommits();
+
+  // Allow canceling a transition until it reaches start().
+  void CancelPendingTransition(const char* abort_message);
+
+  void Abort(AbortSignal* signal);
+
   Member<Document> document_;
 
   State state_ = State::kIdle;
 
   Member<ScriptPromiseResolver> prepare_promise_resolver_;
   Member<ScriptPromiseResolver> start_promise_resolver_;
+  Member<AbortSignal> signal_;
 
   // `active_shared_elements_` represents elements that are identified as shared
   // during the current step of the transition. Specifically, it represents
@@ -118,6 +131,8 @@
   // The document tag identifies the document to which this transition belongs.
   // It's unique among other local documents.
   uint32_t document_tag_ = 0u;
+
+  bool deferring_commits_ = false;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/document_transition/document_transition_prepare_options.idl b/third_party/blink/renderer/core/document_transition/document_transition_prepare_options.idl
index cb52fd68c6..71cba28 100644
--- a/third_party/blink/renderer/core/document_transition/document_transition_prepare_options.idl
+++ b/third_party/blink/renderer/core/document_transition/document_transition_prepare_options.idl
@@ -20,4 +20,5 @@
 dictionary DocumentTransitionPrepareOptions {
   RootTransitionType rootTransition;
   sequence<Element?> sharedElements;
+  AbortSignal abortSignal;
 };
diff --git a/third_party/blink/renderer/core/document_transition/document_transition_test.cc b/third_party/blink/renderer/core/document_transition/document_transition_test.cc
index 06594b7..541ccb7 100644
--- a/third_party/blink/renderer/core/document_transition/document_transition_test.cc
+++ b/third_party/blink/renderer/core/document_transition/document_transition_test.cc
@@ -13,6 +13,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/v8_document_transition_start_options.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_root_transition_type.h"
 #include "third_party/blink/renderer/core/document_transition/document_transition_supplement.h"
+#include "third_party/blink/renderer/core/dom/abort_signal.h"
 #include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
 #include "third_party/blink/renderer/core/html/html_element.h"
 #include "third_party/blink/renderer/core/paint/compositing/compositing_state.h"
@@ -510,11 +511,17 @@
       transition->prepare(script_state, &prepare_options, exception_state));
   EXPECT_EQ(GetState(transition), State::kPreparing);
 
+  // Visual updates are allows during prepare phase.
+  EXPECT_FALSE(LayerTreeHost()->IsDeferringCommits());
+
   UpdateAllLifecyclePhasesAndFinishDirectives();
   prepare_tester.WaitUntilSettled();
   EXPECT_TRUE(prepare_tester.IsFulfilled());
   EXPECT_EQ(GetState(transition), State::kPrepared);
 
+  // Visual updates are stalled between prepared and start.
+  EXPECT_TRUE(LayerTreeHost()->IsDeferringCommits());
+
   DocumentTransitionStartOptions start_options;
   ScriptPromiseTester start_tester(
       script_state,
@@ -523,9 +530,35 @@
   EXPECT_EQ(GetState(transition), State::kStarted);
   UpdateAllLifecyclePhasesAndFinishDirectives();
 
+  // Visual updates are restored on start.
+  EXPECT_FALSE(LayerTreeHost()->IsDeferringCommits());
+
   start_tester.WaitUntilSettled();
   EXPECT_TRUE(start_tester.IsFulfilled());
   EXPECT_EQ(GetState(transition), State::kIdle);
 }
 
+TEST_P(DocumentTransitionTest, AbortSignal) {
+  auto* transition =
+      DocumentTransitionSupplement::documentTransition(GetDocument());
+
+  V8TestingScope v8_scope;
+  ScriptState* script_state = v8_scope.GetScriptState();
+  ExceptionState& exception_state = v8_scope.GetExceptionState();
+
+  auto* abort_signal =
+      MakeGarbageCollected<AbortSignal>(v8_scope.GetExecutionContext());
+  DocumentTransitionPrepareOptions prepare_options;
+  prepare_options.setAbortSignal(abort_signal);
+  ScriptPromiseTester prepare_tester(
+      script_state,
+      transition->prepare(script_state, &prepare_options, exception_state));
+  EXPECT_EQ(GetState(transition), State::kPreparing);
+
+  abort_signal->SignalAbort();
+  prepare_tester.WaitUntilSettled();
+  EXPECT_TRUE(prepare_tester.IsRejected());
+  EXPECT_EQ(GetState(transition), State::kIdle);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index 535ed22e..62564aaa 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -1567,7 +1567,7 @@
 
   // Deferred compositor commits are disallowed by default, and are only allowed
   // for same-origin navigations to an html document fetched with http.
-  bool DeferredCompositorCommitIsAllowed() {
+  bool DeferredCompositorCommitIsAllowed() const {
     return deferred_compositor_commit_is_allowed_;
   }
   void SetDeferredCompositorCommitIsAllowed(bool new_value) {
diff --git a/third_party/blink/renderer/core/events/event_type_names.json5 b/third_party/blink/renderer/core/events/event_type_names.json5
index 25ec973..fcb366c 100644
--- a/third_party/blink/renderer/core/events/event_type_names.json5
+++ b/third_party/blink/renderer/core/events/event_type_names.json5
@@ -74,7 +74,6 @@
     "click",
     "close",
     "closing",
-    "colorselect",
     "complete",
     "compositionend",
     "compositionstart",
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index b4ff8c6..17e4f67 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -4601,7 +4601,6 @@
   if (!GetFrame().IsMainFrame())
     return;
 
-  Document* document = GetFrame().GetDocument();
   ChromeClient& chrome_client = GetFrame().GetPage()->GetChromeClient();
 
   // Determine if we want to defer commits to the compositor once lifecycle
@@ -4612,16 +4611,22 @@
   // over HTTP/HTTPs. And only defer commits once. This method gets called
   // multiple times, and we do not want to defer a second time if we have
   // already done so once and resumed commits already.
-  if (document && document->DeferredCompositorCommitIsAllowed() &&
-      !have_deferred_commits_) {
-    chrome_client.StartDeferringCommits(
-        GetFrame(), base::TimeDelta::FromMilliseconds(kCommitDelayDefaultInMs));
+  if (WillDoPaintHoldingForFCP()) {
     have_deferred_commits_ = true;
+    chrome_client.StartDeferringCommits(
+        GetFrame(), base::TimeDelta::FromMilliseconds(kCommitDelayDefaultInMs),
+        cc::PaintHoldingReason::kFirstContentfulPaint);
   }
 
   chrome_client.BeginLifecycleUpdates(GetFrame());
 }
 
+bool LocalFrameView::WillDoPaintHoldingForFCP() const {
+  Document* document = GetFrame().GetDocument();
+  return document && document->DeferredCompositorCommitIsAllowed() &&
+         !have_deferred_commits_;
+}
+
 void LocalFrameView::SetInitialViewportSize(const IntSize& viewport_size) {
   if (viewport_size == initial_viewport_size_)
     return;
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.h b/third_party/blink/renderer/core/frame/local_frame_view.h
index 978a50d6..cdba46e57 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.h
+++ b/third_party/blink/renderer/core/frame/local_frame_view.h
@@ -185,6 +185,9 @@
   void ScheduleOrthogonalWritingModeRootsForLayout();
   void MarkOrthogonalWritingModeRootsForLayout();
 
+  // Returns true if commits will be deferred for first contentful paint.
+  bool WillDoPaintHoldingForFCP() const;
+
   unsigned LayoutCountForTesting() const { return layout_count_for_testing_; }
   unsigned LifecycleUpdateCountForTesting() const {
     return lifecycle_update_count_for_testing_;
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
index d113d6a0..5367e48 100644
--- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
@@ -1611,10 +1611,11 @@
   return window_segments_;
 }
 
-void WebFrameWidgetImpl::StartDeferringCommits(base::TimeDelta timeout) {
+bool WebFrameWidgetImpl::StartDeferringCommits(base::TimeDelta timeout,
+                                               cc::PaintHoldingReason reason) {
   if (!View()->does_composite())
-    return;
-  widget_base_->LayerTreeHost()->StartDeferringCommits(timeout);
+    return false;
+  return widget_base_->LayerTreeHost()->StartDeferringCommits(timeout, reason);
 }
 
 void WebFrameWidgetImpl::StopDeferringCommits(
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.h b/third_party/blink/renderer/core/frame/web_frame_widget_impl.h
index bfcf3def..f318f6e 100644
--- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.h
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.h
@@ -39,6 +39,7 @@
 #include "cc/input/layer_selection_bound.h"
 #include "cc/input/overscroll_behavior.h"
 #include "cc/trees/layer_tree_host.h"
+#include "cc/trees/paint_holding_reason.h"
 #include "services/viz/public/mojom/hit_test/input_target_client.mojom-blink.h"
 #include "third_party/blink/public/common/input/web_coalesced_input_event.h"
 #include "third_party/blink/public/common/input/web_gesture_device.h"
@@ -446,7 +447,8 @@
   // updates without committing the layer tree. Commits are deferred
   // until at most the given |timeout| has passed. If multiple calls are made
   // when deferral is active then the initial timeout applies.
-  void StartDeferringCommits(base::TimeDelta timeout);
+  bool StartDeferringCommits(base::TimeDelta timeout,
+                             cc::PaintHoldingReason reason);
   // Immediately stop deferring commits.
   void StopDeferringCommits(cc::PaintHoldingCommitTrigger);
 
diff --git a/third_party/blink/renderer/core/layout/layout_counter.cc b/third_party/blink/renderer/core/layout/layout_counter.cc
index 41fb30a..b7ae9b7 100644
--- a/third_party/blink/renderer/core/layout/layout_counter.cc
+++ b/third_party/blink/renderer/core/layout/layout_counter.cc
@@ -484,7 +484,6 @@
 }
 
 String GenerateCounterText(const CounterStyle* counter_style,
-                           EListStyleType deprecated_list_style_type,
                            int value) {
   if (!counter_style)
     return g_empty_string;
@@ -596,7 +595,6 @@
 
   int value = ValueForText(child);
   const CounterStyle* counter_style = nullptr;
-  EListStyleType list_style = EListStyleType::kNone;
   // Note: CSS3 spec doesn't allow 'none' but CSS2.1 allows it. We currently
   // allow it for backward compatibility.
   // See https://github.com/w3c/csswg-drafts/issues/5795 for details.
@@ -605,7 +603,7 @@
         &GetDocument().GetStyleEngine().FindCounterStyleAcrossScopes(
             counter_->ListStyle(), counter_->GetTreeScope());
   }
-  String text = GenerateCounterText(counter_style, list_style, value);
+  String text = GenerateCounterText(counter_style, value);
   // If the separator exists, we need to append all of the parent values as well,
   // including the ones that cross the style containment boundary.
   if (!counter_->Separator().IsNull()) {
@@ -616,7 +614,7 @@
                child->ParentCrossingStyleContainment(counter_->Identifier())) {
       int next_value = next_result_uses_parent_value ? ValueForText(parent)
                                                      : child->CountInParent();
-      text = GenerateCounterText(counter_style, list_style, next_value) +
+      text = GenerateCounterText(counter_style, next_value) +
              counter_->Separator() + text;
       child = parent;
       next_result_uses_parent_value = !child->Parent();
diff --git a/third_party/blink/renderer/core/layout/map_coordinates_test.cc b/third_party/blink/renderer/core/layout/map_coordinates_test.cc
index 3c5991d..01abf4c 100644
--- a/third_party/blink/renderer/core/layout/map_coordinates_test.cc
+++ b/third_party/blink/renderer/core/layout/map_coordinates_test.cc
@@ -1023,6 +1023,52 @@
   EXPECT_EQ(PhysicalOffset(29, 139), mapped_point);
 }
 
+TEST_F(MapCoordinatesTest, MulticolWithAbsPosInInlineRelPos) {
+  SetBodyInnerHTML(R"HTML(
+    <div id='multicol' style='columns:3; column-gap:0; column-fill:auto;
+    width:300px; height:100px; border:8px solid; padding:7px;'>
+        <div style='height:110px;'></div>
+        <div id='container'>
+          <span id='relpos' style='position:relative; left:4px; top:4px;'>
+              <div id='target' style='position:absolute; left:15px; top:15px;
+               margin:10px; border:13px; padding:13px;'></div>
+          </span>
+        </div>
+    </div>
+  )HTML");
+
+  auto* target = GetLayoutBoxByElementId("target");
+  auto* multicol = GetLayoutBoxByElementId("multicol");
+
+  PhysicalOffset mapped_point =
+      MapLocalToAncestor(target, multicol, PhysicalOffset());
+  EXPECT_EQ(PhysicalOffset(144, 54), mapped_point);
+  mapped_point = MapAncestorToLocal(target, multicol, mapped_point);
+  EXPECT_EQ(PhysicalOffset(), mapped_point);
+
+  // Walk each ancestor in the chain separately, to verify each step on the way.
+  auto* container = GetLayoutBoxByElementId("container");
+  LayoutBox* flow_thread = container->ParentBox();
+  ASSERT_TRUE(flow_thread->IsLayoutFlowThread());
+
+  mapped_point = MapLocalToAncestor(target, container, PhysicalOffset());
+  EXPECT_EQ(PhysicalOffset(29, 29), mapped_point);
+  mapped_point = MapAncestorToLocal(target, container, mapped_point);
+  EXPECT_EQ(PhysicalOffset(), mapped_point);
+
+  mapped_point =
+      MapLocalToAncestor(container, flow_thread, PhysicalOffset(25, 25));
+  EXPECT_EQ(PhysicalOffset(25, 135), mapped_point);
+  mapped_point = MapAncestorToLocal(container, flow_thread, mapped_point);
+  EXPECT_EQ(PhysicalOffset(25, 25), mapped_point);
+
+  mapped_point =
+      MapLocalToAncestor(flow_thread, multicol, PhysicalOffset(29, 139));
+  EXPECT_EQ(PhysicalOffset(144, 54), mapped_point);
+  mapped_point = MapAncestorToLocal(flow_thread, multicol, mapped_point);
+  EXPECT_EQ(PhysicalOffset(29, 139), mapped_point);
+}
+
 TEST_F(MapCoordinatesTest, MulticolWithAbsPosNotContained) {
   SetBodyInnerHTML(R"HTML(
     <div id='container' style='position:relative; margin:666px; border:7px
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
index 53523358..7733749 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -401,6 +401,9 @@
     // The relative offset of the inline's containing block to the
     // fragmentation context root.
     LogicalOffset relative_offset;
+    // The offset of the containing block relative to the fragmentation context
+    // root (not including any relative offset).
+    LogicalOffset offset_to_fragmentation_context;
   };
 
   HashMap<const LayoutBox*, InlineContainingBlockInfo> inline_containg_blocks;
@@ -440,8 +443,12 @@
       inline_containers.insert(descendant.inline_container.container,
                                inline_geometry);
       InlineContainingBlockInfo inline_info{
-          inline_containers, offset.block_offset, block_size, start_index,
-          descendant.containing_block.relative_offset};
+          inline_containers,
+          offset.block_offset,
+          block_size,
+          start_index,
+          descendant.containing_block.relative_offset,
+          descendant.containing_block.offset};
       inline_containg_blocks.insert(containing_block, inline_info);
     }
   }
@@ -461,11 +468,10 @@
         container_builder_physical_size, *container_builder_,
         inline_info.fragmentainer_index, &inline_info.map);
 
-    // TODO(almaher): Set |offset_to_border_box| in the final containing block
-    // info that gets created.
     AddInlineContainingBlockInfo(
         inline_info.map, containing_block->StyleRef().GetWritingDirection(),
-        container_builder_physical_size, inline_info.relative_offset);
+        container_builder_physical_size, inline_info.relative_offset,
+        inline_info.offset_to_fragmentation_context);
   }
 }
 
@@ -474,7 +480,8 @@
         inline_container_fragments,
     const WritingDirectionMode container_writing_direction,
     PhysicalSize container_builder_size,
-    LogicalOffset containing_block_relative_offset) {
+    LogicalOffset containing_block_relative_offset,
+    LogicalOffset containing_block_offset) {
   // Transform the start/end fragments into a ContainingBlockInfo.
   for (const auto& block_info : inline_container_fragments) {
     DCHECK(block_info.value.has_value());
@@ -589,18 +596,28 @@
     // applied after fragmentation is performed on the fragmentainer
     // descendants.
     DCHECK((block_info.value->relative_offset == LogicalOffset() &&
-            containing_block_relative_offset == LogicalOffset()) ||
+            containing_block_relative_offset == LogicalOffset() &&
+            containing_block_offset == LogicalOffset()) ||
            container_builder_->IsBlockFragmentationContextRoot());
     LogicalOffset container_offset =
         start_offset - block_info.value->relative_offset;
     LogicalOffset total_relative_offset =
         containing_block_relative_offset + block_info.value->relative_offset;
 
+    // If an OOF has an inline containing block, the OOF offset that is written
+    // back to legacy is relative to the containing block of the inline rather
+    // than the inline itself. |containing_block_offset| will be used when
+    // calculating this OOF offset. However, there may be some relative offset
+    // between the containing block and the inline container that should be
+    // included in the final OOF offset that is written back to legacy. Adjust
+    // for that relative offset here.
     containing_blocks_map_.insert(
         block_info.key,
-        ContainingBlockInfo{inline_writing_direction,
-                            LogicalRect(container_offset, inline_cb_size),
-                            total_relative_offset});
+        ContainingBlockInfo{
+            inline_writing_direction,
+            LogicalRect(container_offset, inline_cb_size),
+            total_relative_offset,
+            containing_block_offset - block_info.value->relative_offset});
   }
 }
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h
index c35ac957..a7f0461 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h
@@ -177,8 +177,6 @@
     // The physical fragment of the containing block used when laying out a
     // fragmentainer descendant. This is the containing block as defined by the
     // spec: https://www.w3.org/TR/css-position-3/#absolute-cb.
-    // TODO(almaher): Ensure that this is correct in the case of an inline
-    // ancestor.
     scoped_refptr<const NGPhysicalFragment> containing_block_fragment = nullptr;
   };
 
@@ -191,11 +189,17 @@
       const Vector<NGLogicalOutOfFlowPositionedNode>&);
   void ComputeInlineContainingBlocksForFragmentainer(
       const Vector<NGLogicalOutOfFlowPositionedNode>&);
+  // |containing_block_relative_offset| is the accumulated relative offset from
+  // the inline's containing block to the fragmentation context root.
+  // |containing_block_offset| is the offset of the inline's containing block
+  // relative to the fragmentation context root (not including any offset from
+  // relative positioning).
   void AddInlineContainingBlockInfo(
       const InlineContainingBlockUtils::InlineContainingBlockMap&,
       const WritingDirectionMode container_writing_direction,
       PhysicalSize container_builder_size,
-      LogicalOffset containing_block_relative_offset = LogicalOffset());
+      LogicalOffset containing_block_relative_offset = LogicalOffset(),
+      LogicalOffset containing_block_offset = LogicalOffset());
 
   void LayoutCandidates(Vector<NGLogicalOutOfFlowPositionedNode>* candidates,
                         const LayoutBox* only_layout,
diff --git a/third_party/blink/renderer/core/loader/empty_clients.cc b/third_party/blink/renderer/core/loader/empty_clients.cc
index 69bcd66..4d371442 100644
--- a/third_party/blink/renderer/core/loader/empty_clients.cc
+++ b/third_party/blink/renderer/core/loader/empty_clients.cc
@@ -89,6 +89,12 @@
   return String();
 }
 
+bool EmptyChromeClient::StartDeferringCommits(LocalFrame& main_frame,
+                                              base::TimeDelta timeout,
+                                              cc::PaintHoldingReason reason) {
+  return false;
+}
+
 void EmptyLocalFrameClient::BeginNavigation(
     const ResourceRequest&,
     mojom::RequestContextFrameType,
diff --git a/third_party/blink/renderer/core/loader/empty_clients.h b/third_party/blink/renderer/core/loader/empty_clients.h
index 3ca7817..e405538c 100644
--- a/third_party/blink/renderer/core/loader/empty_clients.h
+++ b/third_party/blink/renderer/core/loader/empty_clients.h
@@ -32,6 +32,7 @@
 #include <memory>
 
 #include "cc/paint/paint_canvas.h"
+#include "cc/trees/paint_holding_reason.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
@@ -108,8 +109,9 @@
   void SetOverscrollBehavior(LocalFrame& frame,
                              const cc::OverscrollBehavior&) override {}
   void BeginLifecycleUpdates(LocalFrame& main_frame) override {}
-  void StartDeferringCommits(LocalFrame& main_frame,
-                             base::TimeDelta timeout) override {}
+  bool StartDeferringCommits(LocalFrame& main_frame,
+                             base::TimeDelta timeout,
+                             cc::PaintHoldingReason reason) override;
   void StopDeferringCommits(LocalFrame& main_frame,
                             cc::PaintHoldingCommitTrigger) override {}
   void StartDragging(LocalFrame*,
diff --git a/third_party/blink/renderer/core/page/chrome_client.h b/third_party/blink/renderer/core/page/chrome_client.h
index 6effc70c..b452680f 100644
--- a/third_party/blink/renderer/core/page/chrome_client.h
+++ b/third_party/blink/renderer/core/page/chrome_client.h
@@ -31,6 +31,7 @@
 #include "cc/input/overscroll_behavior.h"
 #include "cc/paint/paint_image.h"
 #include "cc/trees/paint_holding_commit_trigger.h"
+#include "cc/trees/paint_holding_reason.h"
 #include "components/viz/common/surfaces/frame_sink_id.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/common/dom_storage/session_storage_namespace_id.h"
@@ -198,8 +199,12 @@
   // reference to make it clear that callers may only call this while a local
   // main frame is present and the state does not persist between instances of
   // local main frames.
-  virtual void StartDeferringCommits(LocalFrame& main_frame,
-                                     base::TimeDelta timeout) = 0;
+  //
+  // Returns false if commits were already deferred, indicating that the call
+  // was a no-op.
+  virtual bool StartDeferringCommits(LocalFrame& main_frame,
+                                     base::TimeDelta timeout,
+                                     cc::PaintHoldingReason reason) = 0;
   virtual void StopDeferringCommits(LocalFrame& main_frame,
                                     cc::PaintHoldingCommitTrigger) = 0;
 
diff --git a/third_party/blink/renderer/core/page/chrome_client_impl.cc b/third_party/blink/renderer/core/page/chrome_client_impl.cc
index b828aa5..7528cfa 100644
--- a/third_party/blink/renderer/core/page/chrome_client_impl.cc
+++ b/third_party/blink/renderer/core/page/chrome_client_impl.cc
@@ -38,6 +38,7 @@
 #include "build/build_config.h"
 #include "cc/animation/animation_host.h"
 #include "cc/layers/picture_layer.h"
+#include "cc/trees/paint_holding_reason.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/common/page/page_zoom.h"
 #include "third_party/blink/public/mojom/input/focus_type.mojom-blink.h"
@@ -983,12 +984,13 @@
   web_view_->StopDeferringMainFrameUpdate();
 }
 
-void ChromeClientImpl::StartDeferringCommits(LocalFrame& main_frame,
-                                             base::TimeDelta timeout) {
+bool ChromeClientImpl::StartDeferringCommits(LocalFrame& main_frame,
+                                             base::TimeDelta timeout,
+                                             cc::PaintHoldingReason reason) {
   DCHECK(main_frame.IsMainFrame());
-  WebLocalFrameImpl::FromFrame(main_frame)
+  return WebLocalFrameImpl::FromFrame(main_frame)
       ->FrameWidgetImpl()
-      ->StartDeferringCommits(timeout);
+      ->StartDeferringCommits(timeout, reason);
 }
 
 void ChromeClientImpl::StopDeferringCommits(
diff --git a/third_party/blink/renderer/core/page/chrome_client_impl.h b/third_party/blink/renderer/core/page/chrome_client_impl.h
index d0fe3dc..d7bf788a 100644
--- a/third_party/blink/renderer/core/page/chrome_client_impl.h
+++ b/third_party/blink/renderer/core/page/chrome_client_impl.h
@@ -72,8 +72,9 @@
   void TakeFocus(mojom::blink::FocusType) override;
   void SetKeyboardFocusURL(Element* new_focus_element) override;
   void BeginLifecycleUpdates(LocalFrame& main_frame) override;
-  void StartDeferringCommits(LocalFrame& main_frame,
-                             base::TimeDelta timeout) override;
+  bool StartDeferringCommits(LocalFrame& main_frame,
+                             base::TimeDelta timeout,
+                             cc::PaintHoldingReason reason) override;
   void StopDeferringCommits(LocalFrame& main_frame,
                             cc::PaintHoldingCommitTrigger) override;
   void StartDragging(LocalFrame*,
diff --git a/third_party/blink/renderer/core/style/computed_style_constants.h b/third_party/blink/renderer/core/style/computed_style_constants.h
index 35098bc9..e2326d5 100644
--- a/third_party/blink/renderer/core/style/computed_style_constants.h
+++ b/third_party/blink/renderer/core/style/computed_style_constants.h
@@ -315,77 +315,6 @@
   return a = a | b;
 }
 
-// https://drafts.csswg.org/css-counter-styles-3/#predefined-counters
-enum class EListStyleType : unsigned {
-  // https://drafts.csswg.org/css-counter-styles-3/#simple-symbolic
-  kDisc,
-  kCircle,
-  kSquare,
-  kDisclosureOpen,
-  kDisclosureClosed,
-
-  // https://drafts.csswg.org/css-counter-styles-3/#simple-numeric
-  kDecimal,
-  kDecimalLeadingZero,
-  kArabicIndic,
-  kBengali,
-  kCambodian,
-  kKhmer,
-  kDevanagari,
-  kGujarati,
-  kGurmukhi,
-  kKannada,
-  kLao,
-  kMalayalam,
-  kMongolian,
-  kMyanmar,
-  kOriya,
-  kPersian,
-  kUrdu,
-  kTelugu,
-  kTibetan,
-  kThai,
-  kLowerRoman,
-  kUpperRoman,
-
-  // https://drafts.csswg.org/css-counter-styles-3/#simple-alphabetic
-  kLowerGreek,
-  kLowerAlpha,
-  kLowerLatin,
-  kUpperAlpha,
-  kUpperLatin,
-
-  // https://drafts.csswg.org/css-counter-styles-3/#simple-fixed
-  kCjkEarthlyBranch,
-  kCjkHeavenlyStem,
-
-  kEthiopicHalehame,
-  kEthiopicHalehameAm,
-  kEthiopicHalehameTiEr,
-  kEthiopicHalehameTiEt,
-  kHangul,
-  kHangulConsonant,
-  kKoreanHangulFormal,
-  kKoreanHanjaFormal,
-  kKoreanHanjaInformal,
-  kHebrew,
-  kArmenian,
-  kLowerArmenian,
-  kUpperArmenian,
-  kGeorgian,
-  kCjkIdeographic,
-  kSimpChineseFormal,
-  kSimpChineseInformal,
-  kTradChineseFormal,
-  kTradChineseInformal,
-  kHiragana,
-  kKatakana,
-  kHiraganaIroha,
-  kKatakanaIroha,
-  kNone,
-  kString,
-};
-
 enum class EBaselineShiftType : unsigned { kLength, kSub, kSuper };
 
 enum EPaintOrderType {
diff --git a/third_party/blink/renderer/modules/eyedropper/BUILD.gn b/third_party/blink/renderer/modules/eyedropper/BUILD.gn
index 9d70bb3..eb5b2c6 100644
--- a/third_party/blink/renderer/modules/eyedropper/BUILD.gn
+++ b/third_party/blink/renderer/modules/eyedropper/BUILD.gn
@@ -6,8 +6,6 @@
 
 blink_modules_sources("eyedropper") {
   sources = [
-    "color_select_event.cc",
-    "color_select_event.h",
     "eye_dropper.cc",
     "eye_dropper.h",
   ]
diff --git a/third_party/blink/renderer/modules/eyedropper/color_select_event.cc b/third_party/blink/renderer/modules/eyedropper/color_select_event.cc
deleted file mode 100644
index 1e70481..0000000
--- a/third_party/blink/renderer/modules/eyedropper/color_select_event.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/eyedropper/color_select_event.h"
-
-#include "third_party/blink/renderer/bindings/modules/v8/v8_color_select_event_init.h"
-
-namespace blink {
-
-ColorSelectEvent::ColorSelectEvent(const AtomicString& type,
-                                   const ColorSelectEventInit* initializer,
-                                   base::TimeTicks platform_time_stamp,
-                                   SyntheticEventType synthetic_event_type,
-                                   WebMenuSourceType menu_source_type)
-    : PointerEvent(type,
-                   initializer,
-                   platform_time_stamp,
-                   synthetic_event_type,
-                   menu_source_type),
-      value_(initializer->value()) {}
-
-ColorSelectEvent* ColorSelectEvent::Create(
-    const AtomicString& type,
-    const ColorSelectEventInit* initializer,
-    base::TimeTicks platform_time_stamp,
-    SyntheticEventType synthetic_event_type,
-    WebMenuSourceType menu_source_type) {
-  return MakeGarbageCollected<ColorSelectEvent>(
-      type, initializer, platform_time_stamp, synthetic_event_type,
-      menu_source_type);
-}
-
-String ColorSelectEvent::value() const {
-  return value_;
-}
-
-void ColorSelectEvent::Trace(Visitor* visitor) const {
-  PointerEvent::Trace(visitor);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/eyedropper/color_select_event.h b/third_party/blink/renderer/modules/eyedropper/color_select_event.h
deleted file mode 100644
index 3b09874..0000000
--- a/third_party/blink/renderer/modules/eyedropper/color_select_event.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_EYEDROPPER_COLOR_SELECT_EVENT_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_EYEDROPPER_COLOR_SELECT_EVENT_H_
-
-#include "third_party/blink/renderer/bindings/modules/v8/v8_color_select_event_init.h"
-#include "third_party/blink/renderer/core/events/pointer_event.h"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-
-namespace blink {
-
-class ColorSelectEvent final : public PointerEvent {
-  DEFINE_WRAPPERTYPEINFO();
-
- public:
-  explicit ColorSelectEvent(const AtomicString& type,
-                            const ColorSelectEventInit* initializer,
-                            base::TimeTicks platform_time_stamp,
-                            SyntheticEventType synthetic_event_type,
-                            WebMenuSourceType menu_source_type);
-
-  static ColorSelectEvent* Create(
-      const AtomicString& type,
-      const ColorSelectEventInit* initializer,
-      base::TimeTicks platform_time_stamp = base::TimeTicks::Now(),
-      SyntheticEventType synthetic_event_type = kRealOrIndistinguishable,
-      WebMenuSourceType menu_source_type = kMenuSourceNone);
-
-  String value() const;
-
-  void Trace(Visitor*) const override;
-
- private:
-  String value_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_EYEDROPPER_COLOR_SELECT_EVENT_H_
diff --git a/third_party/blink/renderer/modules/eyedropper/color_select_event.idl b/third_party/blink/renderer/modules/eyedropper/color_select_event.idl
deleted file mode 100644
index 97b2bfb..0000000
--- a/third_party/blink/renderer/modules/eyedropper/color_select_event.idl
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/EyeDropper/explainer.md
-
-[Exposed=Window, RuntimeEnabled=EyeDropperAPI]
-interface ColorSelectEvent : PointerEvent {
-  constructor(DOMString type, optional ColorSelectEventInit eventInitDict = {});
-
-  readonly attribute DOMString value;
-};
diff --git a/third_party/blink/renderer/modules/eyedropper/color_select_event_init.idl b/third_party/blink/renderer/modules/eyedropper/color_selection_result.idl
similarity index 76%
rename from third_party/blink/renderer/modules/eyedropper/color_select_event_init.idl
rename to third_party/blink/renderer/modules/eyedropper/color_selection_result.idl
index 0285a737..57061060d 100644
--- a/third_party/blink/renderer/modules/eyedropper/color_select_event_init.idl
+++ b/third_party/blink/renderer/modules/eyedropper/color_selection_result.idl
@@ -4,6 +4,6 @@
 
 // https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/EyeDropper/explainer.md
 
-dictionary ColorSelectEventInit : PointerEventInit {
-    DOMString value = "";
+dictionary ColorSelectionResult {
+    DOMString sRGBHex;
 };
diff --git a/third_party/blink/renderer/modules/eyedropper/eye_dropper.cc b/third_party/blink/renderer/modules/eyedropper/eye_dropper.cc
index 615ae23..975cef97 100644
--- a/third_party/blink/renderer/modules/eyedropper/eye_dropper.cc
+++ b/third_party/blink/renderer/modules/eyedropper/eye_dropper.cc
@@ -4,45 +4,101 @@
 
 #include "third_party/blink/renderer/modules/eyedropper/eye_dropper.h"
 
-#include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/modules/event_target_modules.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_color_selection_result.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/graphics/color.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 
 namespace blink {
 
-EyeDropper::EyeDropper(ScriptState* script_state)
-    : ExecutionContextClient(ExecutionContext::From(script_state)),
-      opened_(false) {}
+EyeDropper::EyeDropper(ExecutionContext* context)
+    : eye_dropper_chooser_(context) {}
 
-EyeDropper* EyeDropper::Create(ScriptState* script_state) {
-  return MakeGarbageCollected<EyeDropper>(script_state);
+EyeDropper* EyeDropper::Create(ExecutionContext* context) {
+  return MakeGarbageCollected<EyeDropper>(context);
 }
 
-ExecutionContext* EyeDropper::GetExecutionContext() const {
-  return ExecutionContextClient::GetExecutionContext();
+ScriptPromise EyeDropper::open(ScriptState* script_state,
+                               ExceptionState& exception_state) {
+  DCHECK(RuntimeEnabledFeatures::EyeDropperAPIEnabled());
+
+  if (!script_state->ContextIsValid()) {
+    exception_state.ThrowDOMException(
+        DOMExceptionCode::kInvalidStateError,
+        "The object is no longer associated with a window.");
+    return ScriptPromise();
+  }
+
+  LocalDOMWindow* window = LocalDOMWindow::From(script_state);
+  if (!LocalFrame::HasTransientUserActivation(window->GetFrame())) {
+    exception_state.ThrowDOMException(
+        DOMExceptionCode::kInvalidAccessError,
+        "EyeDropper::open() requires user gesture.");
+    return ScriptPromise();
+  }
+
+  if (eye_dropper_chooser_.is_bound()) {
+    exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+                                      "EyeDropper is already open.");
+    return ScriptPromise();
+  }
+
+  auto* resolver_ = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+  ScriptPromise promise = resolver_->Promise();
+
+  auto* frame = window->GetFrame();
+  frame->GetBrowserInterfaceBroker().GetInterface(
+      eye_dropper_chooser_.BindNewPipeAndPassReceiver(
+          frame->GetTaskRunner(TaskType::kUserInteraction)));
+  eye_dropper_chooser_.set_disconnect_handler(
+      WTF::Bind(&EyeDropper::EndChooser, WrapWeakPersistent(this)));
+  eye_dropper_chooser_->Choose(WTF::Bind(&EyeDropper::EyeDropperResponseHandler,
+                                         WrapPersistent(this),
+                                         WrapPersistent(resolver_)));
+
+  return promise;
 }
 
-const AtomicString& EyeDropper::InterfaceName() const {
-  return event_target_names::kEyeDropper;
+void EyeDropper::EyeDropperResponseHandler(ScriptPromiseResolver* resolver,
+                                           bool success,
+                                           uint32_t color) {
+  eye_dropper_chooser_.reset();
+
+  if (!resolver->GetExecutionContext() ||
+      resolver->GetExecutionContext()->IsContextDestroyed()) {
+    return;
+  }
+
+  if (success) {
+    ColorSelectionResult* result = ColorSelectionResult::Create();
+    result->setSRGBHex(Color(color).Serialized());
+    resolver->Resolve(result);
+  } else {
+    resolver->Reject(MakeGarbageCollected<DOMException>(
+        DOMExceptionCode::kOperationError, "Unable to select a color."));
+  }
 }
 
-EyeDropper::~EyeDropper() = default;
-
-bool EyeDropper::opened() const {
-  return opened_;
-}
-
-ScriptPromise EyeDropper::open() {
-  // TODO(iopopesc): Add support for open.
-  return ScriptPromise();
-}
-
-void EyeDropper::close() {
-  // TODO(iopopesc): Add support for close.
+void EyeDropper::EndChooser() {
+  eye_dropper_chooser_.reset();
+  if (resolver_) {
+    resolver_->Reject(
+        MakeGarbageCollected<DOMException>(DOMExceptionCode::kNotSupportedError,
+                                           "EyeDropper API is not available."));
+    resolver_ = nullptr;
+  }
 }
 
 void EyeDropper::Trace(Visitor* visitor) const {
-  EventTargetWithInlineData::Trace(visitor);
-  ExecutionContextClient::Trace(visitor);
+  visitor->Trace(eye_dropper_chooser_);
+  visitor->Trace(resolver_);
+  ScriptWrappable::Trace(visitor);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/eyedropper/eye_dropper.h b/third_party/blink/renderer/modules/eyedropper/eye_dropper.h
index e131a0b2..3c44cb3 100644
--- a/third_party/blink/renderer/modules/eyedropper/eye_dropper.h
+++ b/third_party/blink/renderer/modules/eyedropper/eye_dropper.h
@@ -6,52 +6,45 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_EYEDROPPER_EYE_DROPPER_H_
 
 #include "base/macros.h"
+#include "third_party/blink/public/mojom/choosers/color_chooser.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
-#include "third_party/blink/renderer/core/dom/events/event_target.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
 
 namespace blink {
 
+class ExceptionState;
+class ScriptPromise;
+class ScriptPromiseResolver;
+
 // The EyeDropper API enables developers to use a browser-supplied eyedropper
 // in their web applications. This feature is still
 // under development, and is not part of the standard. It can be enabled
 // by passing --enable-blink-features=EyeDropperAPI. See
 // https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/EyeDropper/explainer.md
 // for more details.
-class EyeDropper final : public EventTargetWithInlineData,
-                         public ExecutionContextClient {
+class EyeDropper final : public ScriptWrappable {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  explicit EyeDropper(ScriptState*);
-  static EyeDropper* Create(ScriptState*);
+  explicit EyeDropper(ExecutionContext*);
+  static EyeDropper* Create(ExecutionContext*);
   EyeDropper(const EyeDropper&) = delete;
   EyeDropper& operator=(const EyeDropper&) = delete;
-  ~EyeDropper() override;
+  ~EyeDropper() override = default;
 
-  // EventTarget:
-  ExecutionContext* GetExecutionContext() const override;
-  const AtomicString& InterfaceName() const override;
-
-  // Opens the eyedropper and replaces the cursor with a browser-defined preview
-  // and sets opened boolean to true.
-  ScriptPromise open();
-
-  // Exits the eyedropper mode and the cursor returns to its regular
-  // functionality. Sets opened boolean to false.
-  void close();
-
-  // States if the eyedropper is opened and in use.
-  bool opened() const;
-
-  DEFINE_ATTRIBUTE_EVENT_LISTENER(colorselect, kColorselect)
-  DEFINE_ATTRIBUTE_EVENT_LISTENER(close, kClose)
+  // Opens the eyedropper and replaces the cursor with a browser-defined
+  // preview.
+  ScriptPromise open(ScriptState*, ExceptionState&);
 
   void Trace(Visitor*) const override;
 
  private:
-  bool opened_;
+  void EyeDropperResponseHandler(ScriptPromiseResolver*, bool, uint32_t);
+  void EndChooser();
+
+  HeapMojoRemote<mojom::blink::EyeDropperChooser> eye_dropper_chooser_;
+  Member<ScriptPromiseResolver> resolver_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/eyedropper/eye_dropper.idl b/third_party/blink/renderer/modules/eyedropper/eye_dropper.idl
index 75278162..c6ce2db 100644
--- a/third_party/blink/renderer/modules/eyedropper/eye_dropper.idl
+++ b/third_party/blink/renderer/modules/eyedropper/eye_dropper.idl
@@ -5,15 +5,8 @@
 // https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/EyeDropper/explainer.md
 
 [Exposed=Window, RuntimeEnabled=EyeDropperAPI]
-interface EyeDropper : EventTarget {
-  [CallWith=ScriptState] constructor();
+interface EyeDropper {
+  [CallWith=ExecutionContext] constructor();
 
-  Promise<void> open();
-  void close();
-
-  readonly attribute boolean opened;
-
-  // Event handler attributes
-  attribute EventHandler oncolorselect;
-  attribute EventHandler onclose;
+  [CallWith=ScriptState, RaisesException] Promise<ColorSelectionResult> open();
 };
diff --git a/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.cc b/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.cc
index 978c8ff7..fb67543 100644
--- a/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.cc
@@ -46,6 +46,14 @@
                         const IntPoint& offset,
                         const PropertyTreeStateOrAlias* properties) {
   PaintController& paint_controller = context.GetPaintController();
+  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+    // Only record the first fragment's cc::Layer to prevent duplicate layers.
+    // This is not needed for link highlights which do support fragmentation.
+    if (type != DisplayItem::kForeignLayerLinkHighlight &&
+        paint_controller.CurrentFragment() != 0) {
+      return;
+    }
+  }
   // This is like ScopedPaintChunkProperties but uses null id because foreign
   // layer chunk doesn't need an id nor a client.
   absl::optional<PropertyTreeStateOrAlias> previous_properties;
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index d3fcf52..cea8b8b 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -951,7 +951,7 @@
     },
     {
       name: "EyeDropperAPI",
-      status: "test",
+      status: "experimental",
     },
     {
       name: "FaceDetector",
diff --git a/third_party/blink/renderer/platform/webrtc/convert_to_webrtc_video_frame_buffer.cc b/third_party/blink/renderer/platform/webrtc/convert_to_webrtc_video_frame_buffer.cc
index 28df9b1..85c8c80 100644
--- a/third_party/blink/renderer/platform/webrtc/convert_to_webrtc_video_frame_buffer.cc
+++ b/third_party/blink/renderer/platform/webrtc/convert_to_webrtc_video_frame_buffer.cc
@@ -195,7 +195,10 @@
   // ARGB pixel format may be produced by readback of texture backed frames.
   DCHECK(source_frame->format() == media::PIXEL_FORMAT_I420 ||
          source_frame->format() == media::PIXEL_FORMAT_I420A ||
-         source_frame->format() == media::PIXEL_FORMAT_ARGB);
+         source_frame->format() == media::PIXEL_FORMAT_ARGB ||
+         source_frame->format() == media::PIXEL_FORMAT_XRGB ||
+         source_frame->format() == media::PIXEL_FORMAT_ABGR ||
+         source_frame->format() == media::PIXEL_FORMAT_XBGR);
   const bool has_alpha = source_frame->format() == media::PIXEL_FORMAT_I420A;
   // Convert to I420 and scale to the natural size specified in
   // |source_frame|.
@@ -239,35 +242,41 @@
                         dst_frame->coded_size().width(),
                         dst_frame->coded_size().height(), libyuv::kFilterBox);
       break;
-    case media::PIXEL_FORMAT_ARGB: {
+    case media::PIXEL_FORMAT_XRGB:
+    case media::PIXEL_FORMAT_ARGB:
+    case media::PIXEL_FORMAT_XBGR:
+    case media::PIXEL_FORMAT_ABGR: {
+      auto convert_func = (source_frame->format() == media::PIXEL_FORMAT_XRGB ||
+                           source_frame->format() == media::PIXEL_FORMAT_ARGB)
+                              ? libyuv::ARGBToI420
+                              : libyuv::ABGRToI420;
+
       auto visible_size = source_frame->visible_rect().size();
       if (visible_size == dst_frame->coded_size()) {
         // Direct conversion to dst_frame with no scaling.
-        libyuv::ARGBToI420(
-            source_frame->visible_data(media::VideoFrame::kARGBPlane),
-            source_frame->stride(media::VideoFrame::kARGBPlane),
-            dst_frame->data(media::VideoFrame::kYPlane),
-            dst_frame->stride(media::VideoFrame::kYPlane),
-            dst_frame->data(media::VideoFrame::kUPlane),
-            dst_frame->stride(media::VideoFrame::kUPlane),
-            dst_frame->data(media::VideoFrame::kVPlane),
-            dst_frame->stride(media::VideoFrame::kVPlane), visible_size.width(),
-            visible_size.height());
+        convert_func(source_frame->visible_data(media::VideoFrame::kARGBPlane),
+                     source_frame->stride(media::VideoFrame::kARGBPlane),
+                     dst_frame->data(media::VideoFrame::kYPlane),
+                     dst_frame->stride(media::VideoFrame::kYPlane),
+                     dst_frame->data(media::VideoFrame::kUPlane),
+                     dst_frame->stride(media::VideoFrame::kUPlane),
+                     dst_frame->data(media::VideoFrame::kVPlane),
+                     dst_frame->stride(media::VideoFrame::kVPlane),
+                     visible_size.width(), visible_size.height());
       } else {
         // Convert to I420 tmp image and then scale to the dst_frame.
         auto tmp_frame = shared_resources->CreateTemporaryFrame(
             media::PIXEL_FORMAT_I420, visible_size, gfx::Rect(visible_size),
             visible_size, source_frame->timestamp());
-        libyuv::ARGBToI420(
-            source_frame->visible_data(media::VideoFrame::kARGBPlane),
-            source_frame->stride(media::VideoFrame::kARGBPlane),
-            tmp_frame->data(media::VideoFrame::kYPlane),
-            tmp_frame->stride(media::VideoFrame::kYPlane),
-            tmp_frame->data(media::VideoFrame::kUPlane),
-            tmp_frame->stride(media::VideoFrame::kUPlane),
-            tmp_frame->data(media::VideoFrame::kVPlane),
-            tmp_frame->stride(media::VideoFrame::kVPlane), visible_size.width(),
-            visible_size.height());
+        convert_func(source_frame->visible_data(media::VideoFrame::kARGBPlane),
+                     source_frame->stride(media::VideoFrame::kARGBPlane),
+                     tmp_frame->data(media::VideoFrame::kYPlane),
+                     tmp_frame->stride(media::VideoFrame::kYPlane),
+                     tmp_frame->data(media::VideoFrame::kUPlane),
+                     tmp_frame->stride(media::VideoFrame::kUPlane),
+                     tmp_frame->data(media::VideoFrame::kVPlane),
+                     tmp_frame->stride(media::VideoFrame::kVPlane),
+                     visible_size.width(), visible_size.height());
         libyuv::I420Scale(tmp_frame->data(media::VideoFrame::kYPlane),
                           tmp_frame->stride(media::VideoFrame::kYPlane),
                           tmp_frame->data(media::VideoFrame::kUPlane),
@@ -327,7 +336,10 @@
   RTC_DCHECK(source_frame->format() == media::PIXEL_FORMAT_I420 ||
              source_frame->format() == media::PIXEL_FORMAT_I420A ||
              source_frame->format() == media::PIXEL_FORMAT_NV12 ||
-             source_frame->format() == media::PIXEL_FORMAT_ARGB);
+             source_frame->format() == media::PIXEL_FORMAT_ARGB ||
+             source_frame->format() == media::PIXEL_FORMAT_XRGB ||
+             source_frame->format() == media::PIXEL_FORMAT_ABGR ||
+             source_frame->format() == media::PIXEL_FORMAT_XBGR);
   RTC_DCHECK(shared_resources);
 
   const bool source_is_i420 =
@@ -372,7 +384,9 @@
   static constexpr const media::VideoPixelFormat
       kGetPixelFormatsMappableToWebRtcVideoFrameBuffer[] = {
           media::PIXEL_FORMAT_I420, media::PIXEL_FORMAT_I420A,
-          media::PIXEL_FORMAT_NV12};
+          media::PIXEL_FORMAT_NV12, media::PIXEL_FORMAT_ARGB,
+          media::PIXEL_FORMAT_XRGB, media::PIXEL_FORMAT_ABGR,
+          media::PIXEL_FORMAT_XBGR};
   return base::make_span(kGetPixelFormatsMappableToWebRtcVideoFrameBuffer);
 }
 
diff --git a/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc b/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc
index 2db718e3..73e70b80 100644
--- a/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc
+++ b/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc
@@ -32,6 +32,7 @@
 #include "cc/metrics/web_vital_metrics.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_mutator.h"
+#include "cc/trees/paint_holding_reason.h"
 #include "cc/trees/render_frame_metadata_observer.h"
 #include "cc/trees/swap_promise.h"
 #include "cc/trees/ukm_manager.h"
@@ -202,10 +203,11 @@
   delegate_->OnDeferMainFrameUpdatesChanged(status);
 }
 
-void LayerTreeView::OnDeferCommitsChanged(bool status) {
+void LayerTreeView::OnDeferCommitsChanged(bool status,
+                                          cc::PaintHoldingReason reason) {
   if (!delegate_)
     return;
-  delegate_->OnDeferCommitsChanged(status);
+  delegate_->OnDeferCommitsChanged(status, reason);
 }
 
 void LayerTreeView::BeginMainFrameNotExpectedSoon() {
diff --git a/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.h b/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.h
index 7c6b808..bf7bed78 100644
--- a/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.h
+++ b/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.h
@@ -15,6 +15,7 @@
 #include "cc/input/browser_controls_state.h"
 #include "cc/trees/layer_tree_host_client.h"
 #include "cc/trees/layer_tree_host_single_thread_client.h"
+#include "cc/trees/paint_holding_reason.h"
 #include "cc/trees/swap_promise.h"
 #include "cc/trees/swap_promise_monitor.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
@@ -80,7 +81,8 @@
   void DidUpdateLayers() override;
   void BeginMainFrame(const viz::BeginFrameArgs& args) override;
   void OnDeferMainFrameUpdatesChanged(bool) override;
-  void OnDeferCommitsChanged(bool) override;
+  void OnDeferCommitsChanged(bool defer_status,
+                             cc::PaintHoldingReason reason) override;
   void BeginMainFrameNotExpectedSoon() override;
   void BeginMainFrameNotExpectedUntil(base::TimeTicks time) override;
   void UpdateLayerTreeHost() override;
diff --git a/third_party/blink/renderer/platform/widget/compositing/layer_tree_view_delegate.h b/third_party/blink/renderer/platform/widget/compositing/layer_tree_view_delegate.h
index 01877e8..1a9d882 100644
--- a/third_party/blink/renderer/platform/widget/compositing/layer_tree_view_delegate.h
+++ b/third_party/blink/renderer/platform/widget/compositing/layer_tree_view_delegate.h
@@ -10,6 +10,7 @@
 #include "base/callback.h"
 #include "base/time/time.h"
 #include "cc/trees/layer_tree_host_client.h"
+#include "cc/trees/paint_holding_reason.h"
 
 namespace cc {
 class LayerTreeFrameSink;
@@ -40,7 +41,8 @@
   virtual void BeginMainFrame(base::TimeTicks frame_time) = 0;
 
   virtual void OnDeferMainFrameUpdatesChanged(bool) = 0;
-  virtual void OnDeferCommitsChanged(bool) = 0;
+  virtual void OnDeferCommitsChanged(bool defer_status,
+                                     cc::PaintHoldingReason reason) = 0;
 
   // Notifies that the layer tree host has completed a call to
   // RequestMainFrameUpdate in response to a BeginMainFrame.
diff --git a/third_party/blink/renderer/platform/widget/compositing/test/stub_layer_tree_view_delegate.h b/third_party/blink/renderer/platform/widget/compositing/test/stub_layer_tree_view_delegate.h
index cca220a..780434b4 100644
--- a/third_party/blink/renderer/platform/widget/compositing/test/stub_layer_tree_view_delegate.h
+++ b/third_party/blink/renderer/platform/widget/compositing/test/stub_layer_tree_view_delegate.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WIDGET_COMPOSITING_TEST_STUB_LAYER_TREE_VIEW_DELEGATE_H_
 
 #include "cc/paint/element_id.h"
+#include "cc/trees/paint_holding_reason.h"
 #include "third_party/blink/renderer/platform/widget/compositing/layer_tree_view_delegate.h"
 
 namespace cc {
@@ -27,7 +28,8 @@
       const cc::CompositorCommitData& commit_data) override {}
   void BeginMainFrame(base::TimeTicks frame_time) override {}
   void OnDeferMainFrameUpdatesChanged(bool) override {}
-  void OnDeferCommitsChanged(bool) override {}
+  void OnDeferCommitsChanged(bool defer_status,
+                             cc::PaintHoldingReason reason) override {}
   void DidBeginMainFrame() override {}
   void DidCommitAndDrawCompositorFrame() override {}
   void WillCommitCompositorFrame() override {}
diff --git a/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc b/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc
index c206b64..129136e 100644
--- a/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc
+++ b/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc
@@ -15,6 +15,7 @@
 #include "cc/base/features.h"
 #include "cc/metrics/event_metrics.h"
 #include "cc/trees/layer_tree_host.h"
+#include "cc/trees/paint_holding_reason.h"
 #include "components/power_scheduler/power_mode.h"
 #include "components/power_scheduler/power_mode_arbiter.h"
 #include "components/power_scheduler/power_mode_voter.h"
@@ -634,8 +635,10 @@
   }
 }
 
-void WidgetInputHandlerManager::OnDeferCommitsChanged(bool status) {
-  if (status) {
+void WidgetInputHandlerManager::OnDeferCommitsChanged(
+    bool status,
+    cc::PaintHoldingReason reason) {
+  if (status && reason == cc::PaintHoldingReason::kFirstContentfulPaint) {
     renderer_deferral_state_ |=
         static_cast<uint16_t>(RenderingDeferralBits::kDeferCommits);
   } else {
diff --git a/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h b/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h
index 2d3a862d..7b748fb 100644
--- a/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h
+++ b/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h
@@ -10,6 +10,7 @@
 
 #include "base/single_thread_task_runner.h"
 #include "build/build_config.h"
+#include "cc/trees/paint_holding_reason.h"
 #include "components/power_scheduler/power_mode_voter.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
@@ -151,7 +152,7 @@
   void OnDeferMainFrameUpdatesChanged(bool);
 
   // Called to inform us when the system starts or stops deferring commits.
-  void OnDeferCommitsChanged(bool);
+  void OnDeferCommitsChanged(bool defer_status, cc::PaintHoldingReason reason);
 
   // Allow tests, headless etc. to have input events processed before the
   // compositor is ready to commit frames.
diff --git a/third_party/blink/renderer/platform/widget/widget_base.cc b/third_party/blink/renderer/platform/widget/widget_base.cc
index 4d65cad..08eb52e 100644
--- a/third_party/blink/renderer/platform/widget/widget_base.cc
+++ b/third_party/blink/renderer/platform/widget/widget_base.cc
@@ -13,6 +13,7 @@
 #include "cc/mojo_embedder/async_layer_tree_frame_sink.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_settings.h"
+#include "cc/trees/paint_holding_reason.h"
 #include "cc/trees/ukm_manager.h"
 #include "components/viz/common/features.h"
 #include "components/viz/common/switches.h"
@@ -490,10 +491,11 @@
   widget_input_handler_manager_->OnDeferMainFrameUpdatesChanged(defer);
 }
 
-void WidgetBase::OnDeferCommitsChanged(bool defer) {
+void WidgetBase::OnDeferCommitsChanged(bool defer,
+                                       cc::PaintHoldingReason reason) {
   // The input handler wants to know about the commit status for metric purposes
   // and to enable/disable input.
-  widget_input_handler_manager_->OnDeferCommitsChanged(defer);
+  widget_input_handler_manager_->OnDeferCommitsChanged(defer, reason);
 }
 
 void WidgetBase::DidBeginMainFrame() {
diff --git a/third_party/blink/renderer/platform/widget/widget_base.h b/third_party/blink/renderer/platform/widget/widget_base.h
index 58d48575..1336009 100644
--- a/third_party/blink/renderer/platform/widget/widget_base.h
+++ b/third_party/blink/renderer/platform/widget/widget_base.h
@@ -8,6 +8,7 @@
 #include "base/time/time.h"
 #include "cc/paint/element_id.h"
 #include "cc/trees/browser_controls_params.h"
+#include "cc/trees/paint_holding_reason.h"
 #include "components/viz/common/surfaces/local_surface_id.h"
 #include "mojo/public/cpp/bindings/associated_receiver.h"
 #include "mojo/public/cpp/bindings/associated_remote.h"
@@ -133,7 +134,8 @@
       const cc::CompositorCommitData& commit_data) override;
   void BeginMainFrame(base::TimeTicks frame_time) override;
   void OnDeferMainFrameUpdatesChanged(bool) override;
-  void OnDeferCommitsChanged(bool) override;
+  void OnDeferCommitsChanged(bool defer_status,
+                             cc::PaintHoldingReason reason) override;
   void DidBeginMainFrame() override;
   void RequestNewLayerTreeFrameSink(
       LayerTreeFrameSinkCallback callback) override;
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
index 13dfbce..4cb4837 100755
--- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
+++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -352,6 +352,7 @@
 
             # UMA Enums
             'cc::PaintHoldingCommitTrigger',
+            'cc::PaintHoldingReason',
 
             # Scrolling
             'cc::kManipulationInfoPinchZoom',
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=ForceSynchronousHTMLParsing b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=ForceSynchronousHTMLParsing
index d8eedcd..77477ebb 100644
--- a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=ForceSynchronousHTMLParsing
+++ b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=ForceSynchronousHTMLParsing
@@ -39,8 +39,6 @@
 #
 # Text failures
 #
-### fast/block/float
-crbug.com/901056 fast/block/float/4145535Crash.html [ Failure Pass ]
 
 ### http/tests/devtools/console
 # An extra "VM" is printed in front of the page name.
diff --git a/third_party/blink/web_tests/MSANExpectations b/third_party/blink/web_tests/MSANExpectations
index ce21327c..7ac1312e 100644
--- a/third_party/blink/web_tests/MSANExpectations
+++ b/third_party/blink/web_tests/MSANExpectations
@@ -190,3 +190,6 @@
 crbug.com/1215390 [ Linux ] external/wpt/pointerevents/pointerevent_pointerId_scope.html [ Pass Failure ]
 crbug.com/1215632 [ Linux ] external/wpt/html/webappapis/scripting/events/event-handler-attributes-frameset-window.html [ Pass Timeout ]
 crbug.com/1215632 [ Linux ] external/wpt/html/webappapis/scripting/events/event-handler-attributes-windowless-body.html [ Pass Timeout ]
+
+# Sheriff 2021-07-15
+crbug.com/1229588 [ Linux ] external/wpt/secure-payment-confirmation/secure-payment-confirmation.tentative.https.html [ Pass Timeout ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index f5b2d95..e375968 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1870,7 +1870,6 @@
 
 # These tests are skipped as there is no touch support on Mac.
 crbug.com/613672 [ Mac ] fast/events/pointerevents/multi-pointer-event-in-slop-region.html [ Skip ]
-crbug.com/613672 [ Mac ] fast/events/pointerevents/pointer-event-in-slop-region.html [ Skip ]
 
 # In addition to having no support on Mac, the following test times out
 # regularly on Windows.
@@ -4872,7 +4871,6 @@
 crbug.com/1207342 http/tests/devtools/sources/debugger-pause/debugger-mute-exception.js [ Failure Pass ]
 crbug.com/1207342 http/tests/devtools/sources/debugger-pause/debugger-change-variable.js [ Failure Pass ]
 crbug.com/1207342 http/tests/devtools/sources/debugger-pause/debugger-resume-button-in-overlay.js [ Failure Pass ]
-crbug.com/1207342 http/tests/devtools/sources/debugger-pause/pause-on-elements-panel.js [ Failure Pass ]
 crbug.com/1207342 http/tests/devtools/sources/debugger-pause/set-return-value.js [ Failure Pass ]
 crbug.com/1207342 http/tests/devtools/sources/debugger-pause/skip-pauses-until-reload.js [ Failure Pass ]
 crbug.com/1207342 http/tests/devtools/sources/debugger-pause/function-name-in-callstack.js [ Failure Pass ]
@@ -7091,7 +7089,6 @@
 crbug.com/1201406 [ Mac11.0 ] fast/events/touch/gesture/touch-gesture-scroll-listbox.html [ Failure ]
 crbug.com/1201406 [ Mac11.0 ] http/tests/credentialmanager/credentialscontainer-create-from-nested-frame.html [ Crash Timeout ]
 crbug.com/1201406 [ Mac11.0 ] http/tests/credentialmanager/credentialscontainer-create-origins.html [ Crash Timeout ]
-crbug.com/1201406 [ Mac11.0 ] http/tests/credentialmanager/credentialscontainer-create-with-virtual-authenticator.html [ Crash Timeout ]
 crbug.com/1201406 [ Mac11.0 ] http/tests/credentialmanager/publickeycredential-same-origin-with-ancestors.html [ Crash Timeout ]
 crbug.com/1201406 [ Mac11.0 ] http/tests/credentialmanager/register-then-sign.html [ Crash Timeout ]
 crbug.com/1201406 [ Mac11.0 ] http/tests/inspector-protocol/webauthn/webauthn-add-virtual-authenticator.js [ Crash Timeout ]
@@ -7358,3 +7355,9 @@
 crbug.com/1229439 [ Mac10.14 ] media/audio-repaint.html [ Failure Pass ]
 crbug.com/1229666 external/wpt/html/semantics/forms/form-submission-0/urlencoded2.window.html [ Pass Timeout ]
 crbug.com/1229666 virtual/synchronous_html_parser/external/wpt/html/semantics/forms/form-submission-0/urlencoded2.window.html [ Pass Timeout ]
+crbug.com/1093027 http/tests/credentialmanager/credentialscontainer-create-with-virtual-authenticator.html [ Pass Failure Crash Timeout ]
+crbug.com/1229701 virtual/synchronous_html_parser/http/tests/inspector-protocol/network/disable-cache-media-resource.js [ Pass Timeout ]
+# The next test was originally skipped on mac for lack of support (crbug.com/613672). It is now skipped everywhere due to flakiness.
+crbug.com/1229708 fast/events/pointerevents/pointer-event-in-slop-region.html [ Skip ]
+crbug.com/1229711 [ Linux ] http/tests/devtools/console-resource-errors.js [ Pass Failure ]
+crbug.com/1229725 http/tests/devtools/sources/debugger-pause/pause-on-elements-panel.js [ Pass Failure Crash ]
diff --git a/third_party/blink/web_tests/external/wpt/eyedropper/manual/eye-dropper.tentative.html b/third_party/blink/web_tests/external/wpt/eyedropper/manual/eye-dropper.tentative.html
new file mode 100644
index 0000000..9cf7a68
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/eyedropper/manual/eye-dropper.tentative.html
@@ -0,0 +1,120 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>EyeDropper API test</title>
+<style>
+#canvas {
+  background-color: #ff0000;
+  position: absolute;
+  left: 250px;
+  height: 300px;
+  width: 300px;
+}
+#color {
+  background: url("resources/eye_dropper_icon.svg") no-repeat;
+  width: 20px;
+  height: 20px;
+  border: 0;
+  padding: 10px;
+}
+#color:disabled {
+  visibility: hidden;
+}
+#result {
+  visibility: hidden;
+  width: 50px;
+  height: 50px;
+}
+#result.visible {
+  visibility: visible;
+}
+#action {
+  font-weight: bold;
+}
+#action.hidden {
+  visibility: hidden;
+}
+#logger {
+  position: absolute;
+  top: 400px;
+}
+#reset {
+  position: absolute;
+  top: 40px;
+  visibility: hidden;
+}
+#reset.visible {
+  visibility: visible;
+}
+.passed {
+  color: green;
+  font-size: x-large;
+}
+.failed {
+  color: red;
+  font-size: x-large;
+}
+</style>
+</head>
+<body>
+  This tests the EyeDropper API.<br><br><br>
+  <div id="action">TODO: Click on the eye dropper icon.</div>
+  <div id="canvas"></div>
+  <button id="color"></button>
+  <div id="result"></div>
+  <ol id="logger"></ol>
+  <button id="reset">Reset test!</button>
+
+  <script>
+    function log(str) {
+      let entry = document.createElement("li");
+      entry.innerText = str;
+      logger.appendChild(entry);
+      return entry;
+    }
+
+    document.getElementById("color").addEventListener("click", function() {
+      action.innerHTML = "TODO: Click on the red canvas";
+      log("eye dropper opened");
+      let eyeDropper = new EyeDropper();
+      eyeDropper.open()
+      .then(colorSelectionResult => {
+        let entry = log("color selected is " + colorSelectionResult.sRGBHex + " expected: #ff0000");
+
+        result.style.backgroundColor = colorSelectionResult.sRGBHex;
+        result.classList.add("visible");
+
+        let span = document.createElement("span");
+        let red = parseInt(colorSelectionResult.sRGBHex.substring(1, 3), 16);
+        let green = parseInt(colorSelectionResult.sRGBHex.substring(3, 5), 16);
+        let blue = parseInt(colorSelectionResult.sRGBHex.substring(5, 7), 16);
+        // Make sure the selected color is close to pure red (#FF0000), but allow
+        // some deviation due to monitor color calibration.
+        if (red >= 0xC0 && green <= 0x3F && blue <= 0x3F) {
+          span.innerText = "PASS ";
+          span.classList.add("passed");
+        } else {
+          span.innerText = "FAIL ";
+          span.classList.add("failed");
+        }
+        entry.prepend(span);
+        reset.classList.add("visible");
+        action.classList.add("hidden");
+        color.disabled = true;
+      })
+      .catch(error => {
+        log("no color was selected");
+      });
+    });
+
+    document.getElementById("reset").addEventListener("click", function() {
+      action.innerHTML = "TODO: Click on the eye dropper icon.";
+      action.classList.remove("hidden");
+      result.classList.remove("visible");
+      reset.classList.remove("visible");
+      color.disabled = false;
+      logger.innerHTML = "";
+    })
+  </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/eyedropper/manual/resources/eye_dropper_icon.svg b/third_party/blink/web_tests/external/wpt/eyedropper/manual/resources/eye_dropper_icon.svg
new file mode 100644
index 0000000..20d39973
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/eyedropper/manual/resources/eye_dropper_icon.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 0 24 24" width="20"><path d="M0 0h24v24H0z" fill="none"/><path fill="WindowText" d="M20.71 5.63l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-3.12 3.12-1.93-1.91-1.41 1.41 1.42 1.42L3 16.25V21h4.75l8.92-8.92 1.42 1.42 1.41-1.41-1.92-1.92 3.12-3.12c.4-.4.4-1.03.01-1.42zM6.92 19L5 17.08l8.06-8.06 1.92 1.92L6.92 19z"/></svg>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/cancel-animation.html b/third_party/blink/web_tests/external/wpt/scroll-animations/cancel-animation.html
index 16858f4f..40bd546 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/cancel-animation.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/cancel-animation.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
 <meta charset=utf-8>
-<<title>Canceling an animation</title>
+<title>Canceling an animation</title>
 <link rel="help"
     href="https://drafts.csswg.org/web-animations/#canceling-an-animation-section">
 <script src="/resources/testharness.js"></script>
@@ -24,8 +24,14 @@
 <script>
 'use strict';
 
+// TODO(crbug.com/1216655): Remove time range. Once time range is removed, all
+// functions that include ...WithTimeRange() should be replaced with the same
+// function but without that ending. For example:
+//
+// createScrollLinkedAnimationWithTimeRange() => createScrollLinkedAnimation()
+
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -40,7 +46,7 @@
    + ' unresolved');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -59,7 +65,7 @@
    + ' canceled');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -80,7 +86,7 @@
    + ' canceled');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -91,7 +97,7 @@
 }, 'When an animation is canceled, it should create a resolved Promise');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -103,7 +109,7 @@
 }, 'The ready promise should be replaced when the animation is canceled');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -123,7 +129,7 @@
    + ' idle');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -141,7 +147,7 @@
    + ' idle');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -160,7 +166,7 @@
 }, 'Canceling an animation should fire cancel event on orphaned element');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = animation.timeline.scrollSource;
 
   // Wait for new animation frame which allows the timeline to compute new
@@ -184,7 +190,7 @@
    + ' and hold time to be unresolved');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = animation.timeline.scrollSource;
 
   // Wait for new animation frame which allows the timeline to compute new
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/current-time.html b/third_party/blink/web_tests/external/wpt/scroll-animations/current-time.html
index 6682939..b4939f8 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/current-time.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/current-time.html
@@ -6,6 +6,7 @@
 <script src="/resources/testharnessreport.js"></script>
 <script src="/web-animations/testcommon.js"></script>
 <script src="./resources/scrolltimeline-utils.js"></script>
+<script src="./testcommon.js"></script>
 
 <body></body>
 
@@ -14,36 +15,44 @@
 
 promise_test(async t => {
   const scroller = setupScrollTimelineTest();
-  // Set the timeRange such that currentTime maps directly to the value
-  // scrolled. The contents and scroller are square, so it suffices to compute
-  // one edge and use it for all the timelines.
+  const scrollTimeline = new ScrollTimeline({ scrollSource: scroller });
+
+  assert_equals(scrollTimeline.duration.unit, "percent",
+      "duration returns as a percent for scroll timelines");
+  assert_equals(scrollTimeline.duration.value, 100, "duration is 100%");
+}, "Scroll timeline correctly returns duration as 100%");
+
+promise_test(async t => {
+  const scroller = setupScrollTimelineTest();
   const scrollerSize = scroller.scrollHeight - scroller.clientHeight;
 
-  const blockScrollTimeline = new ScrollTimeline(
-      {scrollSource: scroller, timeRange: scrollerSize, orientation: 'block'});
-  const inlineScrollTimeline = new ScrollTimeline(
-      {scrollSource: scroller, timeRange: scrollerSize, orientation: 'inline'});
+  const blockScrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    orientation: 'block'
+  });
+  const inlineScrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    orientation: 'inline'
+  });
   const horizontalScrollTimeline = new ScrollTimeline({
     scrollSource: scroller,
-    timeRange: scrollerSize,
     orientation: 'horizontal'
   });
   const verticalScrollTimeline = new ScrollTimeline({
     scrollSource: scroller,
-    timeRange: scrollerSize,
     orientation: 'vertical'
   });
 
   // Unscrolled, all timelines should read a currentTime of 0.
-  assert_equals(
-      blockScrollTimeline.currentTime, 0, 'Unscrolled block timeline');
-  assert_equals(
-      inlineScrollTimeline.currentTime, 0, 'Unscrolled inline timeline');
-  assert_equals(
-      horizontalScrollTimeline.currentTime, 0,
+  assert_percent_css_unit_value_approx_equals(
+      blockScrollTimeline.currentTime, 0, 0, 'Unscrolled block timeline');
+  assert_percent_css_unit_value_approx_equals(
+      inlineScrollTimeline.currentTime, 0, 0, 'Unscrolled inline timeline');
+  assert_percent_css_unit_value_approx_equals(
+      horizontalScrollTimeline.currentTime, 0, 0,
       'Unscrolled horizontal timeline');
-  assert_equals(
-      verticalScrollTimeline.currentTime, 0, 'Unscrolled vertical timeline');
+  assert_percent_css_unit_value_approx_equals(
+      verticalScrollTimeline.currentTime, 0, 0, 'Unscrolled vertical timeline');
 
   // Do some scrolling and make sure that the ScrollTimelines update.
   scroller.scrollTop = 50;
@@ -52,82 +61,53 @@
   // current time.
   await waitForNextFrame();
 
-  // As noted above timeRange is mapped such that currentTime should be the
-  // scroll offset.
-  assert_equals(blockScrollTimeline.currentTime, 50, 'Scrolled block timeline');
-  assert_equals(
-      inlineScrollTimeline.currentTime, 75, 'Scrolled inline timeline');
-  assert_equals(
-      horizontalScrollTimeline.currentTime, 75, 'Scrolled horizontal timeline');
-  assert_equals(
-      verticalScrollTimeline.currentTime, 50, 'Scrolled vertical timeline');
-}, 'currentTime calculates the correct time based on scrolled amount');
+  assert_percent_css_unit_value_approx_equals(
+      blockScrollTimeline.currentTime, 12.048, 0.01, 'Scrolled block timeline');
+  assert_percent_css_unit_value_approx_equals(
+      inlineScrollTimeline.currentTime, 18.072, 0.01, 'Scrolled inline timeline');
+  assert_percent_css_unit_value_approx_equals(
+      horizontalScrollTimeline.currentTime, 18.072, 0.01, 'Scrolled horizontal timeline');
+  assert_percent_css_unit_value_approx_equals(
+      verticalScrollTimeline.currentTime, 12.048, 0.01, 'Scrolled vertical timeline');
+}, 'currentTime calculates the correct time based on scroll progress');
 
-promise_test(async t => {
-  // It is difficult to calculate the scroll offset which results in an exact
-  // currentTime. Scrolling is calculated in integers which allows for the
-  // possibility of rounding, and scrollbar widths differ between platforms
-  // which means it is not possible to ensure a divisible scroller size. Instead
-  // the scroller content is made large enough that rounding differences result
-  // in negligible deltas in the output value.
-  const contentOverrides = new Map([['width', '1000px'], ['height', '1000px']]);
-  const scroller = setupScrollTimelineTest(new Map(), contentOverrides);
-  const scrollTimeline = new ScrollTimeline(
-      {scrollSource: scroller, timeRange: 100, orientation: 'block'});
-
-  // Mapping timeRange to 100 means the output is 'percentage scrolled', so
-  // calculate where the 50% scroll mark would be.
-  const halfwayY = (scroller.scrollHeight - scroller.clientHeight) / 2;
-  scroller.scrollTop = halfwayY;
-  // Wait for new animation frame  which allows the timeline to compute new
-  // current time.
-  await waitForNextFrame();
-
-  assert_approx_equals(scrollTimeline.currentTime, 50, 0.5);
-}, 'currentTime adjusts correctly for the timeRange');
 
 promise_test(async t => {
   const scroller = setupScrollTimelineTest();
-  // Set the timeRange such that currentTime maps directly to the value
-  // scrolled. The contents and scroller are square, so it suffices to compute
-  // one edge and use it for all the timelines.
   const scrollerSize = scroller.scrollHeight - scroller.clientHeight;
 
   const lengthScrollTimeline = new ScrollTimeline({
     scrollSource: scroller,
-    timeRange: scrollerSize,
     orientation: 'block',
     scrollOffsets: [CSS.px(20), 'auto']
   });
   const percentageScrollTimeline = new ScrollTimeline({
     scrollSource: scroller,
-    timeRange: scrollerSize,
     orientation: 'block',
     scrollOffsets: [CSS.percent(20), 'auto']
   });
   const calcScrollTimeline = new ScrollTimeline({
     scrollSource: scroller,
-    timeRange: scrollerSize,
     orientation: 'block',
     scrollOffsets: [CSS.percent(20).sub(CSS.px(5)), 'auto']
   });
 
   // Unscrolled all timelines should read a current time of 0, as the
   // current offset (0) will be less than the startScrollOffset.
-  assert_equals(
-      lengthScrollTimeline.currentTime, 0,
+  assert_percent_css_unit_value_approx_equals(
+      lengthScrollTimeline.currentTime, 0, 0,
       'Unscrolled length-based timeline current time');
   assert_equals(
       lengthScrollTimeline.phase, "before",
       'Unscrolled length-based timeline phase');
-  assert_equals(
-      percentageScrollTimeline.currentTime, 0,
+  assert_percent_css_unit_value_approx_equals(
+      percentageScrollTimeline.currentTime, 0, 0,
       'Unscrolled percentage-based timeline current time');
   assert_equals(
     percentageScrollTimeline.phase, "before",
       'Unscrolled percentage-based timeline phase');
-  assert_equals(
-      calcScrollTimeline.currentTime, 0,
+  assert_percent_css_unit_value_approx_equals(
+      calcScrollTimeline.currentTime, 0, 0,
       'Unscrolled calc-based timeline current time');
   assert_equals(
       calcScrollTimeline.phase, "before",
@@ -138,8 +118,8 @@
   // Wait for new animation frame  which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
-  assert_equals(
-      lengthScrollTimeline.currentTime, 0,
+  assert_percent_css_unit_value_approx_equals(
+      lengthScrollTimeline.currentTime, 0, 0,
       'Length-based timeline current time before the startScrollOffset'
       + ' point');
   assert_equals(
@@ -147,17 +127,17 @@
       'Length-based timeline phase before the startScrollOffset point');
   scroller.scrollTop = 20;
   await waitForNextFrame();
-  assert_equals(
-      lengthScrollTimeline.currentTime, 0,
+  assert_percent_css_unit_value_approx_equals(
+      lengthScrollTimeline.currentTime, 0, 0,
       'Length-based timeline current time at the startScrollOffset point');
   assert_equals(
       lengthScrollTimeline.phase, "active",
       'Length-based timeline phase at the startScrollOffset point');
   scroller.scrollTop = 50;
   await waitForNextFrame();
-  assert_times_equal(
+  assert_percent_css_unit_value_approx_equals(
       lengthScrollTimeline.currentTime,
-      calculateCurrentTime(50, 20, scrollerSize, scrollerSize),
+      calculateCurrentTime(50, 20, scrollerSize, 100), 0.01,
       'Length-based timeline current time after the startScrollOffset point');
   assert_equals(
       lengthScrollTimeline.phase, "active",
@@ -166,8 +146,8 @@
   // Check the percentage-based ScrollTimeline.
   scroller.scrollTop = 0.19 * scrollerSize;
   await waitForNextFrame();
-  assert_equals(
-      percentageScrollTimeline.currentTime, 0,
+  assert_percent_css_unit_value_approx_equals(
+      percentageScrollTimeline.currentTime, 0, 0,
       'Percentage-based timeline current time before the startScrollOffset'
       + ' point');
   assert_equals(
@@ -175,18 +155,18 @@
       'Percentage-based timeline phase before the startScrollOffset point');
   scroller.scrollTop = 0.20 * scrollerSize;
   await waitForNextFrame();
-  assert_equals(
-      percentageScrollTimeline.currentTime, 0,
+  assert_percent_css_unit_value_approx_equals(
+      percentageScrollTimeline.currentTime, 0, 0,
       'Percentage-based timeline current time at the startScrollOffset point');
   assert_equals(
       percentageScrollTimeline.phase, "active",
       'Percentage-based timeline phase at the startScrollOffset point');
   scroller.scrollTop = 0.50 * scrollerSize;
   await waitForNextFrame();
-  assert_times_equal(
+  assert_percent_css_unit_value_approx_equals(
       percentageScrollTimeline.currentTime,
       calculateCurrentTime(
-          scroller.scrollTop, 0.2 * scrollerSize, scrollerSize, scrollerSize),
+          scroller.scrollTop, 0.2 * scrollerSize, scrollerSize, 100), 0.01,
       'Percentage-based timeline current time after the startScrollOffset'
       + ' point');
   assert_equals(
@@ -196,27 +176,27 @@
   // Check the calc-based ScrollTimeline.
   scroller.scrollTop = 0.2 * scrollerSize - 10;
   await waitForNextFrame();
-  assert_equals(
-      calcScrollTimeline.currentTime, 0,
+  assert_percent_css_unit_value_approx_equals(
+      calcScrollTimeline.currentTime, 0, 0,
       'Calc-based timeline current time before the startScrollOffset point');
   assert_equals(
       calcScrollTimeline.phase, "before",
       'Calc-based timeline phase at the startScrollOffset point');
   scroller.scrollTop = 0.2 * scrollerSize - 5;
   await waitForNextFrame();
-  assert_equals(
-      calcScrollTimeline.currentTime, 0,
+  assert_percent_css_unit_value_approx_equals(
+      calcScrollTimeline.currentTime, 0, 0,
       'Calc-based timeline current time at the startScrollOffset point');
   assert_equals(
       calcScrollTimeline.phase, "active",
       'Calc-based timeline phase at the startScrollOffset point');
   scroller.scrollTop = 0.2 * scrollerSize;
   await waitForNextFrame();
-  assert_times_equal(
+  assert_percent_css_unit_value_approx_equals(
       calcScrollTimeline.currentTime,
       calculateCurrentTime(
           scroller.scrollTop, 0.2 * scrollerSize - 5, scrollerSize,
-          scrollerSize),
+          100), 0.01,
       'Calc-based timeline current time after the startScrollOffset point');
   assert_equals(
       calcScrollTimeline.phase, "active",
@@ -225,81 +205,68 @@
 
 promise_test(async t => {
   const scroller = setupScrollTimelineTest();
-  // Set the timeRange such that currentTime maps directly to the value
-  // scrolled. The contents and scroller are square, so it suffices to compute
-  // one edge and use it for all the timelines.
   const scrollerSize = scroller.scrollHeight - scroller.clientHeight;
 
   // When the endScrollOffset is equal to the maximum scroll offset (and there
   // are no fill modes), the endScrollOffset is treated as inclusive.
   const inclusiveAutoScrollTimeline = new ScrollTimeline({
     scrollSource: scroller,
-    timeRange: scrollerSize,
     orientation: 'block',
   });
   const inclusiveLengthScrollTimeline = new ScrollTimeline({
     scrollSource: scroller,
-    timeRange: scrollerSize,
     orientation: 'block',
     scrollOffsets: [CSS.px(scrollerSize)]
   });
   const inclusivePercentageScrollTimeline = new ScrollTimeline({
     scrollSource: scroller,
-    timeRange: scrollerSize,
     orientation: 'block',
     scrollOffsets: [CSS.percent(100)]
   });
   const inclusiveCalcScrollTimeline = new ScrollTimeline({
     scrollSource: scroller,
-    timeRange: scrollerSize,
     orientation: 'block',
     scrollOffsets: [CSS.percent(80).add(CSS.px(0.2 * scrollerSize))]
   });
 
   scroller.scrollTop = scrollerSize;
   let expectedCurrentTime = calculateCurrentTime(
-      scroller.scrollTop, 0, scrollerSize, scrollerSize);
+      scroller.scrollTop, 0, scrollerSize, 100);
 
   // Wait for new animation frame  which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
 
-  assert_times_equal(
-    inclusiveAutoScrollTimeline.currentTime, expectedCurrentTime,
+  assert_percent_css_unit_value_approx_equals(
+    inclusiveAutoScrollTimeline.currentTime, expectedCurrentTime, 0.01,
     'Inclusive auto timeline at the endScrollOffset point');
-  assert_times_equal(
-    inclusiveLengthScrollTimeline.currentTime, expectedCurrentTime,
+  assert_percent_css_unit_value_approx_equals(
+    inclusiveLengthScrollTimeline.currentTime, expectedCurrentTime, 0.01, 0.01,
     'Inclusive length-based timeline at the endScrollOffset point');
-  assert_times_equal(
-    inclusivePercentageScrollTimeline.currentTime, expectedCurrentTime,
+  assert_percent_css_unit_value_approx_equals(
+    inclusivePercentageScrollTimeline.currentTime, expectedCurrentTime, 0.01,
     'Inclusive percentage-based timeline at the endScrollOffset point');
-  assert_times_equal(
-    inclusiveCalcScrollTimeline.currentTime, expectedCurrentTime,
+  assert_percent_css_unit_value_approx_equals(
+    inclusiveCalcScrollTimeline.currentTime, expectedCurrentTime, 0.01,
     'Inclusive calc-based timeline at the endScrollOffset point');
 }, 'currentTime handles endScrollOffset correctly (inclusive cases)');
 
 promise_test(async t => {
   const scroller = setupScrollTimelineTest();
-  // Set the timeRange such that currentTime maps directly to the value
-  // scrolled. The contents and scroller are square, so it suffices to compute
-  // one edge and use it for all the timelines.
   const scrollerSize = scroller.scrollHeight - scroller.clientHeight;
 
   const lengthScrollTimeline = new ScrollTimeline({
     scrollSource: scroller,
-    timeRange: scrollerSize,
     orientation: 'block',
     scrollOffsets: [CSS.px(scrollerSize - 20)]
   });
   const percentageScrollTimeline = new ScrollTimeline({
     scrollSource: scroller,
-    timeRange: scrollerSize,
     orientation: 'block',
     scrollOffsets: [CSS.percent(80)]
   });
   const calcScrollTimeline = new ScrollTimeline({
     scrollSource: scroller,
-    timeRange: scrollerSize,
     orientation: 'block',
     scrollOffsets: [CSS.percent(80).add(CSS.px(5))]
   });
@@ -309,26 +276,26 @@
   // Wait for new animation frame  which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
-  assert_equals(
-      lengthScrollTimeline.currentTime, lengthScrollTimeline.timeRange,
+  assert_percent_css_unit_value_approx_equals(
+      lengthScrollTimeline.currentTime, 100, 0.01,
       'Length-based timeline current time after the endScrollOffset point');
   assert_equals(
       lengthScrollTimeline.phase, "after",
       'Length-based timeline phase after the endScrollOffset point');
   scroller.scrollTop = scrollerSize - 20;
   await waitForNextFrame();
-  assert_equals(
-      lengthScrollTimeline.currentTime, lengthScrollTimeline.timeRange,
+  assert_percent_css_unit_value_approx_equals(
+      lengthScrollTimeline.currentTime, 100, 0.01,
       'Length-based timeline current time at the endScrollOffset point');
   assert_equals(
       lengthScrollTimeline.phase, "after",
       'Length-based timeline phase at the endScrollOffset point');
   scroller.scrollTop = scrollerSize - 50;
   await waitForNextFrame();
-  assert_times_equal(
+  assert_percent_css_unit_value_approx_equals(
       lengthScrollTimeline.currentTime,
       calculateCurrentTime(
-          scrollerSize - 50, 0, scrollerSize - 20, scrollerSize),
+          scrollerSize - 50, 0, scrollerSize - 20, 100), 0.01,
       'Length-based timeline current time before the endScrollOffset point');
   assert_equals(
       lengthScrollTimeline.phase, "active",
@@ -337,26 +304,26 @@
   // Check the percentage-based ScrollTimeline.
   scroller.scrollTop = 0.81 * scrollerSize;
   await waitForNextFrame();
-  assert_equals(
-      percentageScrollTimeline.currentTime, percentageScrollTimeline.timeRange,
+  assert_percent_css_unit_value_approx_equals(
+      percentageScrollTimeline.currentTime, 100, 0.01,
       'Percentage-based timeline current time after the endScrollOffset point');
   assert_equals(
       percentageScrollTimeline.phase, "after",
       'Percentage-based timeline phase after the endScrollOffset point');
   scroller.scrollTop = 0.80 * scrollerSize;
   await waitForNextFrame();
-  assert_equals(
-      percentageScrollTimeline.currentTime, percentageScrollTimeline.timeRange,
+  assert_percent_css_unit_value_approx_equals(
+      percentageScrollTimeline.currentTime, 100, 0.01,
       'Percentage-based timeline current time at the endScrollOffset point');
   assert_equals(
       percentageScrollTimeline.phase, "after",
       'Percentage-based timeline phase at the endScrollOffset point');
   scroller.scrollTop = 0.50 * scrollerSize;
   await waitForNextFrame();
-  assert_times_equal(
+  assert_percent_css_unit_value_approx_equals(
       percentageScrollTimeline.currentTime,
       calculateCurrentTime(
-          scroller.scrollTop, 0, 0.8 * scrollerSize, scrollerSize),
+          scroller.scrollTop, 0, 0.8 * scrollerSize, 100), 0.01,
       'Percentage-based timeline current time before the endScrollOffset point');
   assert_equals(
       percentageScrollTimeline.phase, "active",
@@ -365,26 +332,26 @@
   // Check the calc-based ScrollTimeline.
   scroller.scrollTop = 0.8 * scrollerSize + 6;
   await waitForNextFrame();
-  assert_equals(
-      calcScrollTimeline.currentTime, calcScrollTimeline.timeRange,
+  assert_percent_css_unit_value_approx_equals(
+      calcScrollTimeline.currentTime, 100, 0.01,
       'Calc-based timeline current time after the endScrollOffset point');
   assert_equals(
       calcScrollTimeline.phase, "after",
       'Calc-based timeline phase after the endScrollOffset point');
   scroller.scrollTop = 0.8 * scrollerSize + 5;
   await waitForNextFrame();
-  assert_equals(
-      calcScrollTimeline.currentTime, calcScrollTimeline.timeRange,
+  assert_percent_css_unit_value_approx_equals(
+      calcScrollTimeline.currentTime, 100, 0.01,
       'Calc-based timeline current time at the endScrollOffset point');
   assert_equals(
       calcScrollTimeline.phase, "after",
       'Calc-based timeline phase at the endScrollOffset point');
   scroller.scrollTop = 0.5 * scrollerSize;
   await waitForNextFrame();
-  assert_times_equal(
+  assert_percent_css_unit_value_approx_equals(
       calcScrollTimeline.currentTime,
       calculateCurrentTime(
-          scroller.scrollTop, 0, 0.8 * scrollerSize + 5, scrollerSize),
+          scroller.scrollTop, 0, 0.8 * scrollerSize + 5, 100), 0.01,
       'Calc-based timeline current time before the endScrollOffset point');
   assert_equals(
       calcScrollTimeline.phase, "active",
@@ -393,14 +360,10 @@
 
 promise_test(async t => {
   const scroller = setupScrollTimelineTest();
-  // Set the timeRange such that currentTime maps directly to the value
-  // scrolled. The contents and scroller are square, so it suffices to compute
-  // one edge and use it for all the timelines.
   const scrollerSize = scroller.scrollHeight - scroller.clientHeight;
 
   const scrollTimeline = new ScrollTimeline({
     scrollSource: scroller,
-    timeRange: scrollerSize,
     orientation: 'block',
     scrollOffsets: [CSS.px(20), CSS.px(scrollerSize - 50)]
   });
@@ -409,21 +372,15 @@
   // Wait for new animation frame  which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
-  assert_times_equal(
+  assert_percent_css_unit_value_approx_equals(
       scrollTimeline.currentTime,
-      calculateCurrentTime(150, 20, scrollerSize - 50, scrollerSize));
+      calculateCurrentTime(150, 20, scrollerSize - 50, 100), 0.01);
 }, 'currentTime handles startScrollOffset and endScrollOffset together correctly');
 
 promise_test(async t => {
   const scroller = setupScrollTimelineTest();
-  // Set the timeRange such that currentTime maps directly to the value
-  // scrolled. The contents and scroller are square, so it suffices to compute
-  // one edge and use it for all the timelines.
-  const scrollerSize = scroller.scrollHeight - scroller.clientHeight;
-
   const scrollTimeline = new ScrollTimeline({
     scrollSource: scroller,
-    timeRange: scrollerSize,
     orientation: 'block',
     scrollOffsets: [CSS.px(20), CSS.px(20)]
   });
@@ -432,19 +389,14 @@
   // Wait for new animation frame  which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
-  assert_equals(scrollTimeline.currentTime, scrollTimeline.timeRange);
+  assert_percent_css_unit_value_approx_equals(scrollTimeline.currentTime,
+      100, 0.01);
 }, 'currentTime handles startScrollOffset == endScrollOffset correctly');
 
 promise_test(async t => {
   const scroller = setupScrollTimelineTest();
-  // Set the timeRange such that currentTime maps directly to the value
-  // scrolled. The contents and scroller are square, so it suffices to compute
-  // one edge and use it for all the timelines.
-  const scrollerSize = scroller.scrollHeight - scroller.clientHeight;
-
   const scrollTimeline = new ScrollTimeline({
     scrollSource: scroller,
-    timeRange: scrollerSize,
     orientation: 'block',
     scrollOffsets: [CSS.px(50), CSS.px(10)]
   });
@@ -453,10 +405,90 @@
   // Wait for new animation frame  which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
-  assert_equals(scrollTimeline.currentTime, 0);
+  assert_percent_css_unit_value_approx_equals(scrollTimeline.currentTime, 0, 0.01);
   scroller.scrollTop = 60;
   await waitForNextFrame();
-  assert_equals(scrollTimeline.currentTime, scrollTimeline.timeRange);
+  assert_percent_css_unit_value_approx_equals(scrollTimeline.currentTime, 100, 0.01);
 }, 'currentTime handles startScrollOffset > endScrollOffset correctly');
 
+promise_test(async t => {
+  const scroller = setupScrollTimelineTest();
+  const scrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    orientation: 'block',
+    scrollOffsets: [CSS.px(10), CSS.px(20), CSS.px(40), CSS.px(70), CSS.px(90)],
+  });
+
+  var offset = 0;
+  var w = 1 / 4;  // offset weight
+  var p = 0;  // progress within the offset
+
+  scroller.scrollTop = 10;
+  // Wait for new animation frame  which allows the timeline to compute new
+  // current time.
+  await waitForNextFrame();
+
+  assert_percent_css_unit_value_approx_equals(
+    scrollTimeline.currentTime, (offset + p) * w * 100, 0.01,
+    "current time calculation when scroll = " + scroller.scrollTop);
+
+  p = (12 - 10) / (20 - 10);
+  scroller.scrollTop = 12;
+  await waitForNextFrame();
+  assert_percent_css_unit_value_approx_equals(
+    scrollTimeline.currentTime, (offset + p) * w * 100, 0.01,
+    "current time calculation when scroll = " + scroller.scrollTop);
+
+  offset = 1;
+  p = 0;
+  scroller.scrollTop = 20;
+  await waitForNextFrame();
+  assert_percent_css_unit_value_approx_equals(
+    scrollTimeline.currentTime, (offset + p) * w * 100, 0.01,
+    "current time calculation when scroll = " + scroller.scrollTop);
+
+  p = (35 - 20) / (40 - 20);
+  scroller.scrollTop = 35;
+  await waitForNextFrame();
+  assert_percent_css_unit_value_approx_equals(
+    scrollTimeline.currentTime, (offset + p) * w * 100, 0.01,
+    "current time calculation when scroll = " + scroller.scrollTop);
+
+  offset = 2;
+  p = 0;
+  scroller.scrollTop = 40;
+  await waitForNextFrame();
+  assert_percent_css_unit_value_approx_equals(
+    scrollTimeline.currentTime, (offset + p) * w * 100, 0.01,
+    "current time calculation when scroll = " + scroller.scrollTop);
+
+  p = (60 - 40) / (70 - 40);
+  scroller.scrollTop = 60;
+  await waitForNextFrame();
+  assert_percent_css_unit_value_approx_equals(
+    scrollTimeline.currentTime, (offset + p) * w * 100, 0.01,
+    "current time calculation when scroll = " + scroller.scrollTop);
+
+  offset = 3;
+  p = 0;
+  scroller.scrollTop = 70;
+  await waitForNextFrame();
+  assert_percent_css_unit_value_approx_equals(
+    scrollTimeline.currentTime, (offset + p) * w * 100, 0.01,
+    "current time calculation when scroll = " + scroller.scrollTop);
+
+  p = (80 - 70) / (90 - 70);
+  scroller.scrollTop = 80;
+  await waitForNextFrame();
+  assert_percent_css_unit_value_approx_equals(
+    scrollTimeline.currentTime, (offset + p) * w * 100, 0.01,
+    "current time calculation when scroll = " + scroller.scrollTop);
+
+  scroller.scrollTop = 90;
+  await waitForNextFrame();
+  assert_percent_css_unit_value_approx_equals(
+    scrollTimeline.currentTime, 100, 0.01,
+    "current time calculation when scroll = " + scroller.scrollTop);
+}, 'currentTime calculations when multiple scroll offsets are specified');
+
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/effect-updateTiming.html b/third_party/blink/web_tests/external/wpt/scroll-animations/effect-updateTiming.html
index 6e72ad1..ae7961c 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/effect-updateTiming.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/effect-updateTiming.html
@@ -31,7 +31,7 @@
 // ------------------------------
 
 promise_test(async t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t, {duration: 1000, delay: 200})
+  const anim = createScrollLinkedAnimationWithTiming(t, {duration: 1000, delay: 200})
   anim.play();
 
   assert_equals(anim.effect.getTiming().delay, 200, 'initial delay 200');
@@ -45,7 +45,7 @@
 }, 'Allows setting the delay to a positive number');
 
 test(t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t, {duration: 100, delay: -100})
+  const anim = createScrollLinkedAnimationWithTiming(t, {duration: 100, delay: -100})
   anim.play();
   anim.effect.updateTiming({ delay: -100 });
   assert_equals(anim.effect.getTiming().delay, -100, 'set delay -100');
@@ -55,7 +55,7 @@
 }, 'Allows setting the delay to a negative number');
 
 test(t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t, {duration: 100})
+  const anim = createScrollLinkedAnimationWithTiming(t, {duration: 100})
   anim.play();
   anim.effect.updateTiming({ delay: 100 });
   assert_equals(anim.effect.getComputedTiming().progress, null);
@@ -64,7 +64,7 @@
    + ' causes the animation to be no longer in-effect');
 
 test(t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t, { fill: 'both', duration: 100 })
+  const anim = createScrollLinkedAnimationWithTiming(t, { fill: 'both', duration: 100 })
   anim.play();
   anim.effect.updateTiming({ delay: -50 });
   assert_equals(anim.effect.getComputedTiming().progress, 0.5);
@@ -72,7 +72,7 @@
    + ' seeks into the active interval');
 
 test(t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t, { fill: 'both', duration: 100 })
+  const anim = createScrollLinkedAnimationWithTiming(t, { fill: 'both', duration: 100 })
   anim.play();
   anim.effect.updateTiming({ delay: -100 });
   assert_equals(anim.effect.getComputedTiming().progress, 1);
@@ -82,7 +82,7 @@
 
 for (const invalid of gBadDelayValues) {
   test(t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t)
+  const anim = createScrollLinkedAnimationWithTiming(t)
   anim.play();
     assert_throws_js(TypeError, () => {
       anim.effect.updateTiming({ delay: invalid });
@@ -96,7 +96,7 @@
 // ------------------------------
 
 test(t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t, { duration: 2000 })
+  const anim = createScrollLinkedAnimationWithTiming(t, { duration: 2000 })
   anim.play();
   anim.effect.updateTiming({ endDelay: 123.45 });
   assert_time_equals_literal(anim.effect.getTiming().endDelay, 123.45,
@@ -106,7 +106,7 @@
 }, 'Allows setting the endDelay to a positive number');
 
 test(t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t, { duration: 2000 })
+  const anim = createScrollLinkedAnimationWithTiming(t, { duration: 2000 })
   anim.play();
   anim.effect.updateTiming({ endDelay: -1000 });
   assert_equals(anim.effect.getTiming().endDelay, -1000, 'set endDelay -1000');
@@ -115,7 +115,7 @@
 }, 'Allows setting the endDelay to a negative number');
 
 test(t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t, { duration: 2000 })
+  const anim = createScrollLinkedAnimationWithTiming(t, { duration: 2000 })
   anim.play();
   assert_throws_js(TypeError, () => {
     anim.effect.updateTiming({ endDelay: Infinity });
@@ -123,7 +123,7 @@
 }, 'Throws when setting the endDelay to infinity');
 
 test(t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t, { duration: 2000 })
+  const anim = createScrollLinkedAnimationWithTiming(t, { duration: 2000 })
   anim.play();
   assert_throws_js(TypeError, () => {
     anim.effect.updateTiming({ endDelay: -Infinity });
@@ -137,7 +137,7 @@
 
 for (const fill of ['none', 'forwards', 'backwards', 'both']) {
   test(t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t, { duration: 100 })
+  const anim = createScrollLinkedAnimationWithTiming(t, { duration: 100 })
   anim.play();
     anim.effect.updateTiming({ fill });
     assert_equals(anim.effect.getTiming().fill, fill, 'set fill ' + fill);
@@ -152,7 +152,7 @@
 // ------------------------------
 
 test(t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t, { iterationStart: 0.2,
+  const anim = createScrollLinkedAnimationWithTiming(t, { iterationStart: 0.2,
                                       iterations: 1,
                                       fill: 'both',
                                       duration: 100,
@@ -165,7 +165,7 @@
    + ' backwards-filling');
 
 test(t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t, { iterationStart: 0.2,
+  const anim = createScrollLinkedAnimationWithTiming(t, { iterationStart: 0.2,
                                       iterations: 1,
                                       fill: 'both',
                                       duration: 100,
@@ -178,7 +178,7 @@
    + ' active phase');
 
 test(t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t, { iterationStart: 0.3,
+  const anim = createScrollLinkedAnimationWithTiming(t, { iterationStart: 0.3,
                                       iterations: 1,
                                       fill: 'both',
                                       duration: 200,
@@ -205,7 +205,7 @@
 
 for (const invalid of gBadIterationStartValues) {
   test(t => {
-    const anim = createProgressBasedScrollLinkedAnimationWithTiming(t)
+    const anim = createScrollLinkedAnimationWithTiming(t)
     anim.play();
     assert_throws_js(TypeError, () => {
       anim.effect.updateTiming({ iterationStart: invalid });
@@ -218,7 +218,7 @@
 // ------------------------------
 
 test(t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t, { duration: 2000 })
+  const anim = createScrollLinkedAnimationWithTiming(t, { duration: 2000 })
   anim.play();
   anim.effect.updateTiming({ iterations: 2 });
   assert_equals(anim.effect.getTiming().iterations, 2, 'set duration 2');
@@ -227,7 +227,7 @@
 }, 'Allows setting iterations to a double value');
 
 test(t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t, { duration: 2000 })
+  const anim = createScrollLinkedAnimationWithTiming(t, { duration: 2000 })
   anim.play();
   assert_throws_js(TypeError, () => {
     anim.effect.updateTiming({ iterations: Infinity });
@@ -238,7 +238,7 @@
 // progress based animations behave a bit differently than time based animations
 // when changing iterations.
 test(t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t,  { duration: 100000, fill: 'both' })
+  const anim = createScrollLinkedAnimationWithTiming(t,  { duration: 100000, fill: 'both' })
   anim.play();
   anim.finish();
 
@@ -279,7 +279,7 @@
 
 // Added test for checking duration "auto"
 test(t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t,  { fill: 'both' })
+  const anim = createScrollLinkedAnimationWithTiming(t,  { fill: 'both' })
   anim.play();
   anim.finish();
 
@@ -332,7 +332,7 @@
 
 for (const duration of gGoodDurationValuesForProgressBased) {
   test(t => {
-    const anim = createProgressBasedScrollLinkedAnimationWithTiming(t, 2000)
+    const anim = createScrollLinkedAnimationWithTiming(t, 2000)
     anim.play();
     anim.effect.updateTiming({ duration: duration.specified });
     if (typeof duration.specified === 'number') {
@@ -357,7 +357,7 @@
 for (const invalid of gBadDurationValuesForProgressBased) {
   test(t => {
     assert_throws_js(TypeError, () => {
-      const anim = createProgressBasedScrollLinkedAnimationWithTiming(t,  { duration: invalid })
+      const anim = createScrollLinkedAnimationWithTiming(t,  { duration: invalid })
       anim.play();
     });
   }, 'Throws when setting invalid duration: '
@@ -365,7 +365,7 @@
 }
 
 test(t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t,  { duration: 100000, fill: 'both' })
+  const anim = createScrollLinkedAnimationWithTiming(t,  { duration: 100000, fill: 'both' })
   anim.play();
   anim.finish();
   assert_equals(anim.effect.getComputedTiming().progress, 1,
@@ -382,7 +382,7 @@
 }, 'Allows setting the duration of an animation in progress');
 
 promise_test(t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t,  { duration: 100000, fill: 'both' })
+  const anim = createScrollLinkedAnimationWithTiming(t,  { duration: 100000, fill: 'both' })
   anim.play();
   return anim.ready.then(() => {
     const originalStartTime   = anim.startTime;
@@ -416,7 +416,7 @@
 // ------------------------------
 
 test(t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t, { duration: 2000 })
+  const anim = createScrollLinkedAnimationWithTiming(t, { duration: 2000 })
   anim.play();
 
   const directions = ['normal', 'reverse', 'alternate', 'alternate-reverse'];
@@ -428,7 +428,7 @@
 }, 'Allows setting the direction to each of the possible keywords');
 
 promise_test(async t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t, { duration: 10000, direction: 'normal' });
+  const anim = createScrollLinkedAnimationWithTiming(t, { duration: 10000, direction: 'normal' });
 
   const scroller = anim.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
@@ -448,7 +448,7 @@
    + ' \'reverse\'');
 
 test(t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t, { duration: 10000, direction: 'normal' });
+  const anim = createScrollLinkedAnimationWithTiming(t, { duration: 10000, direction: 'normal' });
   anim.play();
   assert_equals(anim.effect.getComputedTiming().progress, 0,
                 'progress before updating direction');
@@ -461,7 +461,7 @@
    + ' \'reverse\' while at start of active interval');
 
 test(t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t, { fill: 'backwards',
+  const anim = createScrollLinkedAnimationWithTiming(t, { fill: 'backwards',
                                       duration: 10000,
                                       delay: 10000,
                                       direction: 'normal' });
@@ -477,7 +477,7 @@
    + ' \'reverse\' while filling backwards');
 
 promise_test(async t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t, { iterations: 2,
+  const anim = createScrollLinkedAnimationWithTiming(t, { iterations: 2,
                                       duration: 10000,
                                       direction: 'normal' });
   const scroller = anim.timeline.scrollSource;
@@ -498,7 +498,7 @@
    + ' \'alternate\'');
 
 promise_test(async t => {
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t, { iterations: 2,
+  const anim = createScrollLinkedAnimationWithTiming(t, { iterations: 2,
                                       duration: 10000,
                                       direction: 'alternate' });
   const scroller = anim.timeline.scrollSource;
@@ -537,7 +537,7 @@
 
 for (const options of gEasingTests) {
   promise_test(async t => {
-    const anim = createProgressBasedScrollLinkedAnimationWithTiming(t, { duration: 100000,
+    const anim = createScrollLinkedAnimationWithTiming(t, { duration: 100000,
                                   fill: 'forwards' });
     anim.play();
     anim.effect.updateTiming({ easing: options.easing });
@@ -555,7 +555,7 @@
 
 for (const easing of gRoundtripEasings) {
   test(t => {
-    const anim = createProgressBasedScrollLinkedAnimationWithTiming(t);
+    const anim = createScrollLinkedAnimationWithTiming(t);
     anim.play();
     anim.effect.updateTiming({ easing: easing });
     assert_equals(anim.effect.getTiming().easing, easing);
@@ -568,7 +568,7 @@
 promise_test(async t => {
   const delay = 1000000;
 
-  const anim = createProgressBasedScrollLinkedAnimationWithTiming(t,
+  const anim = createScrollLinkedAnimationWithTiming(t,
     { duration: 1000000, fill: 'both', delay: delay, easing: 'steps(2, start)' });
 
   const scroller = anim.timeline.scrollSource;
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/element-based-offset-clamp.html b/third_party/blink/web_tests/external/wpt/scroll-animations/element-based-offset-clamp.html
index 57601a8..46dc08e 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/element-based-offset-clamp.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/element-based-offset-clamp.html
@@ -52,6 +52,12 @@
 <script>
   'use strict';
 
+  // TODO(crbug.com/1216655): Remove time range. Once time range is removed, all
+  // functions that include ...WithTimeRange() should be replaced with the same
+  // function but without that ending. For example:
+  //
+  // createScrollLinkedAnimationWithTimeRange() => createScrollLinkedAnimation()
+
   function createScrollerWithTarget(test, config) {
     const orientationClass = config.orientation;
     const positions = `
@@ -93,7 +99,7 @@
       // current time.
       await waitForNextFrame();
 
-      const animation = createScrollLinkedAnimation(t, timeline);
+      const animation = createScrollLinkedAnimationWithTimeRange(t, timeline);
       const timeRange = animation.timeline.timeRange;
 
       // Verify initial start and current times in Idle state.
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/element-based-offset.html b/third_party/blink/web_tests/external/wpt/scroll-animations/element-based-offset.html
index 1abb348..566e463 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/element-based-offset.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/element-based-offset.html
@@ -60,6 +60,12 @@
 <script>
   'use strict';
 
+  // TODO(crbug.com/1216655): Remove time range. Once time range is removed, all
+  // functions that include ...WithTimeRange() should be replaced with the same
+  // function but without that ending. For example:
+  //
+  // createScrollLinkedAnimationWithTimeRange() => createScrollLinkedAnimation()
+
   async function createScrollAnimationTest(description, config) {
     promise_test(async t => {
       const scroller = createScrollerWithStartAndEnd(t, config.orientation);
@@ -85,7 +91,7 @@
       // current time.
       await waitForNextFrame();
 
-      const animation = createScrollLinkedAnimation(t, timeline);
+      const animation = createScrollLinkedAnimationWithTimeRange(t, timeline);
       const scrollRange = end.offsetTop - start.offsetTop;
       const timeRange = animation.timeline.timeRange;
 
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/finish-animation.html b/third_party/blink/web_tests/external/wpt/scroll-animations/finish-animation.html
index 12665980..b7fd1e0 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/finish-animation.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/finish-animation.html
@@ -24,8 +24,15 @@
 <div id="log"></div>
 <script>
 'use strict';
+
+  // TODO(crbug.com/1216655): Remove time range. Once time range is removed, all
+  // functions that include ...WithTimeRange() should be replaced with the same
+  // function but without that ending. For example:
+  //
+  // createScrollLinkedAnimationWithTimeRange() => createScrollLinkedAnimation()
+
   promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
     // Wait for new animation frame which allows the timeline to compute new
     // current time.
     await waitForNextFrame();
@@ -39,32 +46,19 @@
 
   promise_test(async t => {
     const animation = createScrollLinkedAnimation(t);
-    animation.effect.updateTiming({ iterations : Infinity });
-    animation.play();
     // Wait for new animation frame which allows the timeline to compute new
     // current time.
     await waitForNextFrame();
-
-    assert_throws_dom('InvalidStateError', () => {
-      animation.finish();
-    });
-  }, 'Finishing an infinite animation throws');
-
-  promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
-    // Wait for new animation frame  which allows the timeline to compute new
-    // current time.
-    await waitForNextFrame();
     animation.play();
     animation.finish();
 
-    assert_times_equal(animation.currentTime, 1000,
+    assert_percent_css_unit_value_approx_equals(animation.currentTime, 100, 0.01,
       'After finishing, the currentTime should be set to the end of the'
       + ' active duration');
   }, 'Finishing an animation seeks to the end time');
 
   promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
     // Wait for new animation frame which allows the timeline to compute new
     // current time.
     await waitForNextFrame();
@@ -74,19 +68,21 @@
       animation.effect.getComputedTiming().endTime + 1;
     animation.finish();
 
-    assert_time_equals_literal(animation.currentTime, 1000,
+    assert_times_equal(animation.currentTime, 1000,
       'After finishing, the currentTime should be set back to the end of the'
       + ' active duration');
   }, 'Finishing an animation with a current time past the effect end jumps'
     + ' back to the end');
 
   promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
+    const scroller = animation.timeline.scrollSource;
+    const maxScroll = scroller.scrollHeight - scroller.clientHeight;
     // Wait for new animation frame which allows the timeline to compute new
     // current time.
     await waitForNextFrame();
     animation.play();
-    animation.currentTime = 1000;
+    scroller.scrollTop = maxScroll;
     await animation.finished;
 
     animation.playbackRate = -1;
@@ -98,7 +94,7 @@
   }, 'Finishing a reversed animation jumps to zero time');
 
   promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
     // Wait for new animation frame which allows the timeline to compute new
     // current time.
     await waitForNextFrame();
@@ -110,14 +106,14 @@
     animation.currentTime = -10000;
     animation.finish();
 
-    assert_equals(animation.currentTime, 0,
+    assert_times_equal(animation.currentTime, 0,
                   'After finishing a reversed animation the currentTime ' +
                   'should be set back to zero');
   }, 'Finishing a reversed animation with a current time less than zero'
     + ' makes it jump back to zero');
 
   promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
     // Wait for new animation frame which allows the timeline to compute new
     // current time.
     await waitForNextFrame();
@@ -154,7 +150,7 @@
     assert_equals(animation.playState, 'finished',
                   'The play state of a play-pending animation should become ' +
                   '"finished"');
-    assert_times_equal(animation.currentTime, 1000,
+    assert_percent_css_unit_value_approx_equals(animation.currentTime, 100, 0.1,
                       'The current time of a play-pending animation should ' +
                       'be set to the end of the active duration');
     assert_equals(animation.startTime, null,
@@ -243,10 +239,12 @@
     assert_equals(animation.playState, 'finished',
                   'The play state of a canceled animation should become ' +
                   '"finished"');
-    assert_times_equal(animation.startTime,
-                      animation.timeline.currentTime - 1000,
+    // Divide by 1000 to convert from milliseconds to seconds, which represent
+    // percentage values until changed internally.
+    assert_times_equal(animation.startTime / 1000,
+                      animation.timeline.currentTime.value - 100,
                       'The start time of a finished animation should be set');
-    assert_times_equal(animation.currentTime, 1000,
+    assert_percent_css_unit_value_approx_equals(animation.currentTime, 100, 0.1,
                       'Hold time should be set to end boundary of the animation');
 
   }, 'Finishing a canceled animation sets the current and start times');
@@ -266,13 +264,15 @@
     const finishEvent = await eventWatcher.wait_for('finish');
     assert_equals(animation.playState, 'finished',
       'Animation is finished.');
-    assert_equals(animation.currentTime, 1000,
+      assert_percent_css_unit_value_approx_equals(animation.currentTime, 100, 0.1,
       'The current time is the end of the active duration in finished state.');
-    assert_equals(animation.startTime, -750,
+    // Divide by 1000 to convert from milliseconds to seconds, which represent
+    // percentage values until changed internally.
+    assert_equals(animation.startTime / 1000, -75,
       'The start time is calculated to match the current time.');
-    assert_equals(finishEvent.currentTime, 1000,
+    assert_equals(finishEvent.currentTime / 1000, 100,
       'event.currentTime is the animation current time.');
-    assert_equals(finishEvent.timelineTime, 250,
+    assert_equals(finishEvent.timelineTime / 1000, 25,
       'event.timelineTime is timeline.currentTime');
   }, 'Finishing idle animation produces correct state and fires finish event.');
 
@@ -306,13 +306,15 @@
     const finishEvent = await eventWatcher.wait_for('finish');
     assert_equals(animation.playState, 'finished',
       'Animation is finished.');
-    assert_equals(animation.currentTime, 1000,
+      assert_percent_css_unit_value_approx_equals(animation.currentTime, 100, 0.1,
       'The current time is the end of active duration in finished state.');
-    assert_equals(animation.startTime, -750,
+    // Divide by 1000 to convert from milliseconds to seconds, which represent
+    // percentage values until changed internally.
+    assert_equals(animation.startTime / 1000, -75,
       'The start time is calculated to match animation current time.');
-    assert_equals(finishEvent.currentTime, 1000,
+    assert_equals(finishEvent.currentTime / 1000, 100,
       'event.currentTime is the animation current time.');
-    assert_equals(finishEvent.timelineTime, 250,
+    assert_equals(finishEvent.timelineTime / 1000, 25,
       'event.timelineTime is timeline.currentTime');
   }, 'Finishing running animation produces correct state and fires finish event.');
 
@@ -352,13 +354,15 @@
     assert_equals(animation.playState, 'finished',
                   'The play state of a paused animation should become ' +
                   '"finished"');
-    assert_times_equal(animation.startTime,
-                      animation.timeline.currentTime - 1000,
+    // Divide by 1000 to convert from milliseconds to seconds, which represent
+    // percentage values until changed internally.
+    assert_times_equal(animation.startTime / 1000,
+                      animation.timeline.currentTime.value - 100,
                       'The start time of a paused animation should be set');
   }, 'Finishing a paused animation resolves the start time');
 
   promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
     // Wait for new animation frame which allows the timeline to compute new
     // current time.
     await waitForNextFrame();
@@ -382,7 +386,7 @@
     + ' immediately and update the start time');
 
   promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
     // Wait for new animation frame which allows the timeline to compute new
     // current time.
     await waitForNextFrame();
@@ -436,7 +440,7 @@
     animation.finish();
     assert_false(animation.pending);
     assert_equals(animation.playbackRate, 2);
-    assert_times_equal(animation.currentTime, 1000);
+    assert_percent_css_unit_value_approx_equals(animation.currentTime, 100, 0.1);
   }, 'A pending playback rate should be applied immediately when an animation'
     + ' is finished');
 
@@ -454,40 +458,5 @@
       animation.finish();
     });
   }, 'An exception should be thrown if the effective playback rate is zero');
-
-  promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
-    animation.effect.updateTiming({ iterations: Infinity });
-    // Wait for new animation frame which allows the timeline to compute new
-    // current time.
-    await waitForNextFrame();
-    animation.play();
-    animation.currentTime = 500;
-    animation.playbackRate = -1;
-    await animation.ready;
-
-    animation.updatePlaybackRate(1);
-
-    assert_throws_dom('InvalidStateError', () => {
-      animation.finish();
-    });
-  }, 'An exception should be thrown when finishing if the effective playback rate'
-    + ' is positive and the target effect end is infinity');
-
-  promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
-    animation.effect.updateTiming({ iterations: Infinity });
-    // Wait for new animation frame which allows the timeline to compute new
-    // current time.
-    await waitForNextFrame();
-    animation.play();
-    await animation.ready;
-
-    animation.updatePlaybackRate(-1);
-
-    animation.finish();
-    // Should not have thrown
-  }, 'An exception is NOT thrown when finishing if the effective playback rate'
-    + ' is negative and the target effect end is infinity');
 </script>
 </body>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/pause-animation.html b/third_party/blink/web_tests/external/wpt/scroll-animations/pause-animation.html
index 9bddfed..0f67970 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/pause-animation.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/pause-animation.html
@@ -23,8 +23,15 @@
 <body>
 <script>
 'use strict';
+
+// TODO(crbug.com/1216655): Remove time range. Once time range is removed, all
+// functions that include ...WithTimeRange() should be replaced with the same
+// function but without that ending. For example:
+//
+// createScrollLinkedAnimationWithTimeRange() => createScrollLinkedAnimation()
+
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -44,7 +51,7 @@
 }, 'Pausing clears the start time');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -61,7 +68,7 @@
 }, 'Aborting a pause preserves the start time');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -78,7 +85,7 @@
    + ' animation is paused');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -103,7 +110,7 @@
   // This test does not cover a specific step in the algorithm but serves as a
   // high-level sanity check that pausing does, in fact, freeze the current
   // time.
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = animation.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
   // Wait for new animation frame which allows the timeline to compute new
@@ -127,7 +134,7 @@
 }, 'The animation\'s current time remains fixed after pausing');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -155,7 +162,7 @@
 }, 'Pausing a canceled animation sets the current time');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = animation.timeline.scrollSource;
   // Make the scroll timeline inactive.
   scroller.style.overflow = 'visible';
@@ -179,7 +186,7 @@
 }, 'Pause pending task doesn\'t run when the timeline is inactive.');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = animation.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
   scroller.scrollTop = 0.2 * maxScroll;
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/play-animation.html b/third_party/blink/web_tests/external/wpt/scroll-animations/play-animation.html
index fc1182d..65e8cee 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/play-animation.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/play-animation.html
@@ -24,8 +24,14 @@
 <script>
 'use strict';
 
+// TODO(crbug.com/1216655): Remove time range. Once time range is removed, all
+// functions that include ...WithTimeRange() should be replaced with the same
+// function but without that ending. For example:
+//
+// createScrollLinkedAnimationWithTimeRange() => createScrollLinkedAnimation()
+
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -37,7 +43,7 @@
 }, 'Playing a running animation leaves the current time unchanged');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -49,7 +55,7 @@
 }, 'Playing a finished animation seeks back to the start');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -62,7 +68,7 @@
 }, 'Playing a finished and reversed animation seeks to end');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -83,7 +89,7 @@
    + ' to the start');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -96,7 +102,7 @@
 }, 'Playing a finished animation clears the start time');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -109,7 +115,7 @@
    + ' pending');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -122,7 +128,7 @@
    + ' animation enters the running state');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -142,7 +148,7 @@
 }, 'Resuming an animation from paused calculates start time from hold time');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -169,7 +175,7 @@
 
 promise_test(async t => {
   // Seek animation beyond target end
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -189,7 +195,7 @@
 }, 'A pending playback rate is used when determining auto-rewind behavior');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -209,7 +215,7 @@
 }, 'Playing a canceled animation sets the start time');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/progress-based-scroll-animation.tentative.html b/third_party/blink/web_tests/external/wpt/scroll-animations/progress-based-scroll-animation.tentative.html
deleted file mode 100644
index 7f53368..0000000
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/progress-based-scroll-animation.tentative.html
+++ /dev/null
@@ -1,224 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>Test basic functionality of scroll linked animation.</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/web-animations/testcommon.js"></script>
-<script src="testcommon.js"></script>
-<style>
-  .scroller {
-    overflow: auto;
-    height: 100px;
-    width: 100px;
-    will-change: transform;
-  }
-  .contents {
-    height: 1000px;
-    width: 100%;
-  }
-</style>
-<div id="log"></div>
-<script>
-  'use strict';
-
-  // This test file is only temporary until we can remove timeline time_range at
-  // which point all scroll timelines will be progress based. See comment in
-  // testcommon.js for more details.
-
-  promise_test(async t => {
-    const animation = createProgressBasedScrollLinkedAnimation(t);
-    const scroller = animation.timeline.scrollSource;
-    const maxScroll = scroller.scrollHeight - scroller.clientHeight;
-
-    // Wait for new animation frame  which allows the timeline to compute new
-    // current time.
-    await waitForNextFrame();
-
-    // Verify initial start and current times in Idle state.
-    assert_equals(animation.currentTime, null,
-      "The current time is null in Idle state.");
-    assert_equals(animation.startTime, null,
-      "The start time is null in Idle state.");
-
-    animation.play();
-    assert_true(animation.pending, "Animation is in pending state.");
-    // Verify initial start and current times in Pending state.
-    assert_percent_css_unit_value_approx_equals(animation.currentTime, 0, 0.01,
-      "The current time is zero in Pending state.");
-    assert_equals(animation.startTime, 0,
-      "The start time is zero in Pending state.");
-
-    await animation.ready;
-    // Verify initial start and current times in Playing state.
-    assert_percent_css_unit_value_approx_equals(animation.currentTime, 0, 0.01,
-      "The current time is zero in Playing state.");
-    assert_equals(animation.startTime, 0,
-      "The start time is zero in Playing state.");
-
-    // Now do some scrolling and make sure that the Animation current time is
-    // correct.
-    scroller.scrollTop = 0.4 * maxScroll;
-    // Wait for new animation frame  which allows the timeline to compute new
-    // current time.
-    await waitForNextFrame();
-    assert_css_numberish_equals(animation.currentTime, animation.timeline.currentTime,
-      "The current time corresponds to the scroll position of the scroller.");
-    assert_times_equal(
-      animation.effect.getComputedTiming().progress,
-      // Division by 100 is temporary, it will be removed when progress returns
-      // a CSSNumericValue instead of a double 0-1
-      animation.timeline.currentTime.value / 100,
-      'Effect local time corresponds to the scroll position of the scroller.');
-}, 'Animation start and current times are correct for each animation state.');
-
-promise_test(async t => {
-    const animation = createProgressBasedScrollLinkedAnimation(t);
-    const scroller = animation.timeline.scrollSource;
-    const maxScroll = scroller.scrollHeight - scroller.clientHeight;
-
-    // Advance the scroller.
-    scroller.scrollTop = 0.4 * maxScroll;
-    // Wait for new animation frame  which allows the timeline to compute new
-    // current time.
-    await waitForNextFrame();
-
-    // Verify initial start and current times in Idle state.
-    assert_equals(animation.currentTime, null,
-      "The current time is null in Idle state.");
-    assert_equals(animation.startTime, null,
-      "The start time is null in Idle state.");
-    animation.play();
-    // Verify initial start and current times in Pending state.
-    assert_css_numberish_equals(animation.currentTime, animation.timeline.currentTime,
-      "The current time is a hold time in Pending state.");
-    assert_equals(animation.startTime, 0,
-      "The start time is zero in Pending state.");
-
-    await animation.ready;
-    // Verify initial start and current times in Playing state.
-    assert_css_numberish_equals(animation.currentTime, animation.timeline.currentTime,
-      "The current corresponds to the scroll position of the scroller.");
-    assert_equals(animation.startTime, 0,
-      "The start time is zero in Playing state.");
-}, 'Animation start and current times are correct for each animation state' +
-    ' when the animation starts playing with advanced scroller.');
-
-promise_test(async t => {
-    const timeline = createProgressBasedScrollTimeline(t);
-    const animation1 = createProgressBasedScrollLinkedAnimation(t, timeline);
-    const animation2 = createProgressBasedScrollLinkedAnimation(t, timeline);
-    const scroller = timeline.scrollSource;
-    const maxScroll = scroller.scrollHeight - scroller.clientHeight;
-
-    // Advance the scroller.
-    scroller.scrollTop = 0.4 * maxScroll;
-    // Wait for new animation frame  which allows the timeline to compute new
-    // current time.
-    await waitForNextFrame();
-
-    // Verify initial start and current times in Idle state.
-    assert_equals(animation1.currentTime, null,
-      "The current time is null in Idle state.");
-    assert_equals(animation1.startTime, null,
-      "The start time is null in Idle state.");
-    assert_equals(animation2.currentTime, null,
-      "The current time is null in Idle state.");
-    assert_equals(animation2.startTime, null,
-      "The start time is null in Idle state.");
-    animation1.play();
-    animation2.play();
-    // Verify initial start and current times in Pending state.
-    assert_css_numberish_equals(animation1.currentTime, timeline.currentTime,
-      "The current time corresponds to the scroll position of the scroller" +
-        " in Pending state.");
-    assert_equals(animation1.startTime, 0,
-      "The start time is zero in Pending state.");
-      assert_css_numberish_equals(animation2.currentTime, timeline.currentTime,
-      "The current time corresponds to the scroll position of the scroller" +
-        " in Pending state.");
-    assert_equals(animation2.startTime, 0,
-      "The start time is zero in Pending state.");
-
-    await animation1.ready;
-    await animation2.ready;
-    // Verify initial start and current times in Playing state.
-    assert_css_numberish_equals(animation1.currentTime, timeline.currentTime,
-      "The current corresponds to the scroll position of the scroller.");
-    assert_equals(animation1.startTime, 0,
-      "The start time is zero in Playing state.");
-      assert_css_numberish_equals(animation2.currentTime, timeline.currentTime,
-      "The current corresponds to the scroll position of the scroller.");
-    assert_equals(animation2.startTime, 0,
-      "The start time is zero in Playing state.");
-}, 'Animation start and current times are correct when multiple animations' +
-    ' are attached to the same timeline.');
-
-promise_test(async t => {
-    const animation = createProgressBasedScrollLinkedAnimation(t);
-    const scroller = animation.timeline.scrollSource;
-    const maxScroll = scroller.scrollHeight - scroller.clientHeight;
-
-    animation.play();
-    await animation.ready;
-    // Advance the scroller to max position.
-    scroller.scrollTop = maxScroll;
-
-    await animation.finished;
-
-    assert_equals(animation.playState, 'finished',
-      'Animation state is in finished state.');
-    assert_equals(animation.currentTime.value, 100,
-      'Animation current time is at 100% on reverse scrolling.');
-
-    // Scroll back.
-    scroller.scrollTop = 0.4 * maxScroll;
-
-    // Wait for new animation frame  which allows the timeline to compute new
-    // current time.
-    await waitForNextFrame();
-    // Verify animation state and current time on reverse scrolling.
-    assert_equals(animation.playState, 'running',
-      'Animation state is playing on reverse scrolling.');
-    assert_equals(animation.currentTime.value, 40 /* 40% */,
-      'Animation current time is updated on reverse scrolling.');
-}, 'Finished animation plays on reverse scrolling.');
-
-promise_test(async t => {
-    const animation = createProgressBasedScrollLinkedAnimation(t);
-    const scroller = animation.timeline.scrollSource;
-    const maxScroll = scroller.scrollHeight - scroller.clientHeight;
-
-    animation.play();
-    await animation.ready;
-
-    // Advance the scroller to max position.
-    scroller.scrollTop =  maxScroll;
-    await animation.finished;
-
-    var sent_finish_event = false;
-    animation.onfinish = function() {
-      sent_finish_event = true;
-    };
-
-    // Scroll back.
-    scroller.scrollTop = 0.4 * maxScroll;
-    // Wait for new animation frame  which allows the timeline to compute new
-    // current time.
-    await waitForNextFrame();
-    assert_false(sent_finish_event,
-                 "No animation finished event is sent on reverse scroll.");
-
-    scroller.scrollTop = maxScroll;
-    await animation.finished;
-
-    // Wait for next frame to allow the animation to send finish events. The
-    // finished promise fires before events are sent.
-    await waitForNextFrame();
-
-    assert_true(sent_finish_event,
-                 "Animation finished event is sent on reaching max scroll.");
-}, 'Sending animation finished events by finished animation on reverse ' +
-   'scrolling.');
-
-   //TODO: jortaylo: Add a test for changing from time based animation to progress based.
-</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/progress-based-scroll-timeline-phases.tentative.html b/third_party/blink/web_tests/external/wpt/scroll-animations/progress-based-scroll-timeline-phases.tentative.html
deleted file mode 100644
index 0c4bd22..0000000
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/progress-based-scroll-timeline-phases.tentative.html
+++ /dev/null
@@ -1,217 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>Test basic functionality of scroll timeline phases.</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/web-animations/testcommon.js"></script>
-<script src="testcommon.js"></script>
-<style>
-  .scroller {
-    overflow: auto;
-    height: 100px;
-    width: 100px;
-  }
-  .contents {
-    height: 1000px;
-    width: 100%;
-  }
-</style>
-<div id="log"></div>
-<script>
-  'use strict';
-
-  promise_test(async t => {
-    const timeline = createProgressBasedScrollTimeline(t);
-    assert_throws_js(TypeError, () => {
-      timeline.phase = "after";
-    });
-  }, 'Setting scroll timeline phase (which is readonly) throws TypeError.');
-
-  const test_cases = {
-    before_start: {
-      name: "before start",
-      scroll_percent: 0.1,
-      timeline_phase: "before"
-    },
-    at_start: {
-      name: "at start",
-      scroll_percent: 0.2,
-      timeline_phase: "active"
-    },
-    in_range: {
-      name: "in range",
-      scroll_percent: 0.5,
-      timeline_phase: "active"
-    },
-    at_end: {
-      name: "at end",
-      scroll_percent: 0.8,
-      timeline_phase: "after"
-    },
-    after_end: {
-      name: "after end",
-      scroll_percent: 0.9,
-      timeline_phase: "after"
-    }
-  }
-
-  for (const test_case_key in test_cases){
-    const test_case = test_cases[test_case_key];
-    promise_test(async t => {
-      const timeline = createProgressBasedScrollTimelineWithOffsets(t, CSS.percent(20), CSS.percent(80));
-      const scroller = timeline.scrollSource;
-      const maxScroll = scroller.scrollHeight - scroller.clientHeight;
-
-      scroller.scrollTop = test_case.scroll_percent * maxScroll;
-      // Wait for new animation frame which allows the timeline to compute new
-      // current time.
-      await waitForNextFrame();
-
-      assert_equals(
-        timeline.phase,
-        test_case.timeline_phase,
-        "timeline.phase"
-      );
-    }, "Timeline phase while scroll offset is " + test_case.name);
-  }
-
-  // TODO(crbug.com/1060384): Spec is unclear in this case, revisit this when
-  // desired results have been established.
-  // These test cases are worded strangely because they test an edge case
-  // where startScrollOffset is GREATER THAN endScrollOffset
-  const test_cases_start_offset_greater_than_end_offset = {
-    before_end: {
-      name: "before end",
-      scroll_percent: 0.1,
-      timeline_phase: "before"
-    },
-    at_end: {
-      name: "at end",
-      scroll_percent: 0.2,
-      timeline_phase: "before"
-    },
-    before_start: {
-      name: "before start",
-      scroll_percent: 0.5,
-      timeline_phase: "before"
-    },
-    at_start: {
-      name: "at start",
-      scroll_percent: 0.8,
-      timeline_phase: "after"
-    },
-    after_start: {
-      name: "after start",
-      scroll_percent: 0.9,
-      timeline_phase: "after"
-    }
-  }
-
-  for (const test_case_key in test_cases_start_offset_greater_than_end_offset){
-    const test_case =
-      test_cases_start_offset_greater_than_end_offset[test_case_key];
-    promise_test(async t => {
-      const timeline = createProgressBasedScrollTimelineWithOffsets(t, CSS.percent(80), CSS.percent(20));
-      const scroller = timeline.scrollSource;
-      const maxScroll = scroller.scrollHeight - scroller.clientHeight;
-
-      scroller.scrollTop = test_case.scroll_percent * maxScroll;
-      // Wait for new animation frame which allows the timeline to compute new
-      // current time.
-      await waitForNextFrame();
-
-      assert_equals(
-        timeline.phase,
-        test_case.timeline_phase,
-        "timeline.phase"
-      );
-    }, "Timeline phase while start offset is greater than end offset and" +
-    " scroll offset is " + test_case.name);
-  }
-
-  // TODO(crbug.com/1060384): Spec is unclear in this case, revisit this when
-  // desired results have been established.
-  // Test cases where startScrollOffset is EQUAL TO endScrollOffset
-  const test_cases_start_offset_equal_to_end_offset = {
-    before_end: {
-      name: "before start",
-      scroll_percent: 0.3,
-      timeline_phase: "before"
-    },
-    at_end: {
-      name: "at both",
-      scroll_percent: 0.5,
-      timeline_phase: "after"
-    },
-    before_start: {
-      name: "after end",
-      scroll_percent: 0.7,
-      timeline_phase: "after"
-    }
-  }
-
-  for (const test_case_key in test_cases_start_offset_equal_to_end_offset){
-    const test_case =
-      test_cases_start_offset_equal_to_end_offset[test_case_key];
-    promise_test(async t => {
-      const timeline = createProgressBasedScrollTimelineWithOffsets(t, CSS.percent(50), CSS.percent(50));
-      const scroller = timeline.scrollSource;
-      const maxScroll = scroller.scrollHeight - scroller.clientHeight;
-
-      scroller.scrollTop = test_case.scroll_percent * maxScroll;
-      // Wait for new animation frame which allows the timeline to compute new
-      // current time.
-      await waitForNextFrame();
-
-      assert_equals(
-        timeline.phase,
-        test_case.timeline_phase,
-        "timeline.phase"
-      );
-    }, "Timeline phase while start offset is equal to end offset and scroll" +
-    " offset is " + test_case.name);
-  }
-
-  promise_test(async t => {
-    const timeline = createProgressBasedScrollTimeline(t);
-    const scroller = timeline.scrollSource;
-    const maxScroll = scroller.scrollHeight - scroller.clientHeight;
-
-    scroller.scrollTop = maxScroll;
-
-    // Wait for new animation frame which allows the timeline to compute new
-    // current time.
-    await waitForNextFrame();
-
-    // When the endScrollOffset is equal to the maximum scroll offset, the
-    // endScrollOffset is treated as inclusive so the phase should remain
-    // active.
-    assert_equals(timeline.phase, "active");
-  }, 'Scroll timeline phase should be active when at scroll maximum and ' +
-    'endScrollOffset is equal to maximum scroll offset.');
-
-  promise_test(async t => {
-    const timeline = createProgressBasedScrollTimeline(t);
-    const scroller = timeline.scrollSource;
-    // Setting the scroller to display none should make the timeline inactive
-    scroller.style.display = "none";
-    scroller.scrollTop;
-    await waitForNextFrame();
-    assert_equals(timeline.phase, "inactive");
-
-    // Setting the scroller to display "block" should make the timeline active
-    scroller.style.display = "block";
-    scroller.scrollTop;
-    await waitForNextFrame();
-    assert_equals(timeline.phase, "active");
-
-    // Setting the scroller to display none should make the timeline inactive
-    scroller.style.display = "none";
-    scroller.scrollTop;
-    await waitForNextFrame();
-
-    assert_equals(timeline.phase, "inactive");
-  }, 'Scroll timeline starts inactive, can transition to active, and then' +
-  ' back to inactive.');
-
-</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/reverse-animation.html b/third_party/blink/web_tests/external/wpt/scroll-animations/reverse-animation.html
index 95c772e3..9c8fb0f 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/reverse-animation.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/reverse-animation.html
@@ -24,8 +24,14 @@
 <script>
 'use strict';
 
+// TODO(crbug.com/1216655): Remove time range. Once time range is removed, all
+// functions that include ...WithTimeRange() should be replaced with the same
+// function but without that ending. For example:
+//
+// createScrollLinkedAnimationWithTimeRange() => createScrollLinkedAnimation()
+
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -44,7 +50,7 @@
 }, 'Reversing an animation inverts the playback rate');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -58,7 +64,7 @@
 }, 'Reversing an animation maintains the same current time');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -73,7 +79,7 @@
 }, 'Reversing an animation does not cause it to leave the pending state');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -89,7 +95,7 @@
 }, 'Reversing an animation does not cause it to resolve the ready promise');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -104,7 +110,7 @@
    'effect end should make it play from the end');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -120,7 +126,7 @@
    'should make it play from the end');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -136,7 +142,7 @@
    'should make it play from the start');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -152,7 +158,7 @@
    'end should make it play from the start');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   animation.effect.updateTiming({ iterations: Infinity });
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
@@ -170,7 +176,7 @@
    'and the target effect end is positive infinity should throw an exception');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   animation.effect.updateTiming({ iterations: Infinity });
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
@@ -188,7 +194,7 @@
 }, 'When reversing throws an exception, the playback rate remains unchanged');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   animation.effect.updateTiming({ iterations: Infinity });
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
@@ -208,7 +214,7 @@
    'exception');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   animation.effect.updateTiming({ iterations: Infinity });
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
@@ -228,7 +234,7 @@
    'from the start');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -246,7 +252,7 @@
    'time and playback rate');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -262,7 +268,7 @@
 }, 'Reversing an idle animation from starts playing the animation');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = animation.timeline.scrollSource;
   // Make the scroll timeline inactive.
   scroller.style.overflow = 'visible';
@@ -276,7 +282,7 @@
    'InvalidStateError');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -294,7 +300,7 @@
 }, 'Reversing an animation plays a pausing animation');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -309,7 +315,7 @@
 }, 'Reversing should use the negative pending playback rate');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   animation.effect.updateTiming({ iterations: Infinity });
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/scroll-animation-effect-phases.tentative.html b/third_party/blink/web_tests/external/wpt/scroll-animations/scroll-animation-effect-phases.tentative.html
index 47e2717..4f38a10 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/scroll-animation-effect-phases.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/scroll-animation-effect-phases.tentative.html
@@ -21,11 +21,17 @@
 <script>
   'use strict';
 
+  // TODO(crbug.com/1216655): Remove time range. Once time range is removed, all
+  // functions that include ...WithTimeRange() should be replaced with the same
+  // function but without that ending. For example:
+  //
+  // createScrollLinkedAnimationWithTimeRange() => createScrollLinkedAnimation()
+
   // Test cases are included where effect delay causes the effect iteration to
   // overlap with the timeline start time and also the timeline end time.
   //                  Timeline
   //   BEFORE   +-----------------+     AFTER
-  //   time:    0                 timeRange
+  //   time:    0                 timeline.duration
   //   1)       +--------+
   //   2)            +-------+
   //   3)                      +------+
@@ -92,7 +98,7 @@
   function create_scroll_timeline_fill_test(delay, scroll_percentage, expected){
     return async t => {
       const target = createDiv(t);
-      const timeline = createScrollTimelineWithOffsets(t, CSS.percent(20), CSS.percent(80));
+      const timeline = createScrollTimelineWithOffsetsWithTimeRange(t, CSS.percent(20), CSS.percent(80));
       const effect = new KeyframeEffect(
         target,
         {
@@ -190,7 +196,7 @@
   promise_test(async t => {
     const animation = new Animation(
       createKeyframeEffectOpacity(t),
-      createScrollTimelineWithOffsets(t, CSS.percent(20), CSS.percent(80))
+      createScrollTimelineWithOffsetsWithTimeRange(t, CSS.percent(20), CSS.percent(80))
     );
 
     const scroller = animation.timeline.scrollSource;
@@ -218,7 +224,7 @@
   promise_test(async t => {
     const animation = new Animation(
       createKeyframeEffectOpacity(t),
-      createScrollTimelineWithOffsets(t, CSS.percent(20), CSS.percent(80))
+      createScrollTimelineWithOffsetsWithTimeRange(t, CSS.percent(20), CSS.percent(80))
     );
 
     const scroller = animation.timeline.scrollSource;
@@ -259,7 +265,7 @@
 promise_test(async t => {
   const animation = new Animation(
     createKeyframeEffectOpacity(t),
-    createScrollTimelineWithOffsets(t, CSS.percent(20), CSS.percent(80))
+    createScrollTimelineWithOffsetsWithTimeRange(t, CSS.percent(20), CSS.percent(80))
   );
   const scroller = animation.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
@@ -317,7 +323,7 @@
 promise_test(async t => {
   const animation = new Animation(
     createKeyframeEffectOpacity(t),
-    createScrollTimelineWithOffsets(t, CSS.percent(20), CSS.percent(80))
+    createScrollTimelineWithOffsetsWithTimeRange(t, CSS.percent(20), CSS.percent(80))
   );
   const scroller = animation.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/scroll-animation-inactive-timeline.html b/third_party/blink/web_tests/external/wpt/scroll-animations/scroll-animation-inactive-timeline.html
index 70b732ed..be1bc9e5 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/scroll-animation-inactive-timeline.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/scroll-animation-inactive-timeline.html
@@ -20,10 +20,16 @@
 </style>
 <div id="log"></div>
 <script>
-  'use strict';
+'use strict';
+
+// TODO(crbug.com/1216655): Remove time range. Once time range is removed, all
+// functions that include ...WithTimeRange() should be replaced with the same
+// function but without that ending. For example:
+//
+// createScrollLinkedAnimationWithTimeRange() => createScrollLinkedAnimation()
 
 promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
     const scroller = animation.timeline.scrollSource;
     // Make the scroll timeline inactive.
     scroller.style.overflow = 'visible';
@@ -46,7 +52,7 @@
 }, 'Play pending task doesn\'t run when the timeline is inactive.');
 
 promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
     const scroller = animation.timeline.scrollSource;
     // Make the scroll timeline inactive.
     scroller.style.overflow = 'visible';
@@ -70,7 +76,7 @@
    'activated after animation.play call.');
 
 promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
     const scroller = animation.timeline.scrollSource;
     const target = animation.effect.target;
     // Make the scroll timeline inactive.
@@ -105,7 +111,7 @@
    'activated after setting start time.');
 
 promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
     const scroller = animation.timeline.scrollSource;
     const maxScroll = scroller.scrollHeight - scroller.clientHeight;
     const target = animation.effect.target;
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/scroll-animation.html b/third_party/blink/web_tests/external/wpt/scroll-animations/scroll-animation.html
index ef36236..2b7bb55 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/scroll-animation.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/scroll-animation.html
@@ -37,30 +37,32 @@
     animation.play();
     assert_true(animation.pending, "Animation is in pending state.");
     // Verify initial start and current times in Pending state.
-    assert_equals(animation.currentTime, 0,
+    assert_percent_css_unit_value_approx_equals(animation.currentTime, 0, 0.01,
       "The current time is zero in Pending state.");
     assert_equals(animation.startTime, 0,
       "The start time is zero in Pending state.");
 
     await animation.ready;
     // Verify initial start and current times in Playing state.
-    assert_equals(animation.currentTime, 0,
+    assert_percent_css_unit_value_approx_equals(animation.currentTime, 0, 0.01,
       "The current time is zero in Playing state.");
     assert_equals(animation.startTime, 0,
       "The start time is zero in Playing state.");
 
     // Now do some scrolling and make sure that the Animation current time is
     // correct.
-    scroller.scrollTop = 0.2 * maxScroll;
+    scroller.scrollTop = 0.4 * maxScroll;
     // Wait for new animation frame  which allows the timeline to compute new
     // current time.
     await waitForNextFrame();
-    assert_equals(animation.currentTime, animation.timeline.currentTime,
+    assert_css_numberish_equals(animation.currentTime, animation.timeline.currentTime,
       "The current time corresponds to the scroll position of the scroller.");
     assert_times_equal(
-      animation.effect.getComputedTiming().localTime,
-      animation.timeline.currentTime,
-      'Effect local time corresponds to the scroll position of the scroller.');
+      animation.effect.getComputedTiming().progress,
+      // Division by 100 is temporary, it will be removed when progress returns
+      // a CSSNumericValue instead of a double 0-1
+      animation.timeline.currentTime.value / 100,
+      'Effect progress corresponds to the scroll position of the scroller.');
 }, 'Animation start and current times are correct for each animation state.');
 
 promise_test(async t => {
@@ -81,14 +83,14 @@
       "The start time is null in Idle state.");
     animation.play();
     // Verify initial start and current times in Pending state.
-    assert_equals(animation.currentTime, animation.timeline.currentTime,
+    assert_css_numberish_equals(animation.currentTime, animation.timeline.currentTime,
       "The current time is a hold time in Pending state.");
     assert_equals(animation.startTime, 0,
       "The start time is zero in Pending state.");
 
     await animation.ready;
     // Verify initial start and current times in Playing state.
-    assert_equals(animation.currentTime, animation.timeline.currentTime,
+    assert_css_numberish_equals(animation.currentTime, animation.timeline.currentTime,
       "The current corresponds to the scroll position of the scroller.");
     assert_equals(animation.startTime, 0,
       "The start time is zero in Playing state.");
@@ -103,7 +105,7 @@
     const maxScroll = scroller.scrollHeight - scroller.clientHeight;
 
     // Advance the scroller.
-    scroller.scrollTop = 0.2 * maxScroll;
+    scroller.scrollTop = 0.4 * maxScroll;
     // Wait for new animation frame  which allows the timeline to compute new
     // current time.
     await waitForNextFrame();
@@ -120,12 +122,12 @@
     animation1.play();
     animation2.play();
     // Verify initial start and current times in Pending state.
-    assert_equals(animation1.currentTime, timeline.currentTime,
+    assert_css_numberish_equals(animation1.currentTime, timeline.currentTime,
       "The current time corresponds to the scroll position of the scroller" +
         " in Pending state.");
     assert_equals(animation1.startTime, 0,
       "The start time is zero in Pending state.");
-    assert_equals(animation2.currentTime, timeline.currentTime,
+      assert_css_numberish_equals(animation2.currentTime, timeline.currentTime,
       "The current time corresponds to the scroll position of the scroller" +
         " in Pending state.");
     assert_equals(animation2.startTime, 0,
@@ -134,11 +136,11 @@
     await animation1.ready;
     await animation2.ready;
     // Verify initial start and current times in Playing state.
-    assert_equals(animation1.currentTime, timeline.currentTime,
+    assert_css_numberish_equals(animation1.currentTime, timeline.currentTime,
       "The current corresponds to the scroll position of the scroller.");
     assert_equals(animation1.startTime, 0,
       "The start time is zero in Playing state.");
-    assert_equals(animation2.currentTime, timeline.currentTime,
+      assert_css_numberish_equals(animation2.currentTime, timeline.currentTime,
       "The current corresponds to the scroll position of the scroller.");
     assert_equals(animation2.startTime, 0,
       "The start time is zero in Playing state.");
@@ -149,15 +151,19 @@
     const animation = createScrollLinkedAnimation(t);
     const scroller = animation.timeline.scrollSource;
     const maxScroll = scroller.scrollHeight - scroller.clientHeight;
-    const timeRange = animation.timeline.timeRange;
 
     animation.play();
     await animation.ready;
-
     // Advance the scroller to max position.
-    scroller.scrollTop =  maxScroll;
+    scroller.scrollTop = maxScroll;
+
     await animation.finished;
 
+    assert_equals(animation.playState, 'finished',
+      'Animation state is in finished state.');
+    assert_percent_css_unit_value_approx_equals(animation.currentTime, 100,
+      0.01, 'Animation current time is at 100% on reverse scrolling.');
+
     // Scroll back.
     scroller.scrollTop = 0.2 * maxScroll;
 
@@ -165,9 +171,9 @@
     // current time.
     await waitForNextFrame();
     // Verify animation state and current time on reverse scrolling.
-    assert_equals(animation.playState,  'running',
+    assert_equals(animation.playState, 'running',
       'Animation state is playing on reverse scrolling.');
-    assert_equals(animation.currentTime,  0.2 * timeRange,
+    assert_percent_css_unit_value_approx_equals(animation.currentTime, 20, 0.01,
       'Animation current time is updated on reverse scrolling.');
 }, 'Finished animation plays on reverse scrolling.');
 
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/scroll-timeline-invalidation.html b/third_party/blink/web_tests/external/wpt/scroll-animations/scroll-timeline-invalidation.html
index 45c148e..d5c8750 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/scroll-timeline-invalidation.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/scroll-timeline-invalidation.html
@@ -25,10 +25,12 @@
 
 promise_test(async t => {
   const animation = createScrollLinkedAnimation(t);
-  animation.effect.updateTiming({ duration: 350 });
+  const effect_duration = 350;
+  animation.effect.updateTiming({ duration: effect_duration });
   const scroller = animation.timeline.scrollSource;
-  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
+  let maxScroll = scroller.scrollHeight - scroller.clientHeight;
   scroller.scrollTop = 0.2 * maxScroll;
+  const initial_progress = (scroller.scrollTop / maxScroll) * 100;
   // Wait for new animation frame  which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -36,17 +38,27 @@
   animation.play();
   await animation.ready;
 
-  // Change scroller content size.
+  // Animation current time is at 20% because scroller was scrolled to 20%
+  // assert_equals(animation.currentTime.value, 20);
+  assert_equals(animation.currentTime.value, 20);
+  assert_equals(scroller.scrollTop, 180);
+  assert_equals(maxScroll, 900);
+
+  // Shrink scroller content size (from 1000 to 500).
+  // scroller.scrollTop maintains the same offset, which means shrinking the
+  // content has the effect of skipping the animation forward.
   scroller.firstChild.style.height = "500px";
+  maxScroll = scroller.scrollHeight - scroller.clientHeight;
 
-  await animation.finished;
-  const newTime = animation.effect.getTiming().duration;
-  assert_times_equal(animation.currentTime, newTime,
-    'Animation current time is updated after scroller invalidation.');
+  assert_equals(scroller.scrollTop, 180);
+  assert_equals(maxScroll, 400);
+  await waitForNextFrame();
 
-  assert_times_equal(
-    animation.effect.getComputedTiming().localTime, newTime,
-    'Effect local time is updated after scroller invalidation.');
+  const expected_progress = (scroller.scrollTop / maxScroll) * 100;
+  assert_true(expected_progress > initial_progress)
+  assert_equals(animation.currentTime.value, expected_progress); // 45%
+  assert_equals(animation.timeline.currentTime.value, expected_progress); // 45%
+  assert_equals(animation.effect.getComputedTiming().localTime.value, expected_progress); // 45%
 }, 'Animation current time and effect local time are updated after scroller ' +
    'content size changes.');
 
@@ -54,8 +66,10 @@
   const animation = createScrollLinkedAnimation(t);
   animation.effect.updateTiming({ duration: 350 });
   const scroller = animation.timeline.scrollSource;
-  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
-  scroller.scrollTop = 0.2 * maxScroll;
+  let maxScroll = scroller.scrollHeight - scroller.clientHeight;
+  const scrollOffset = 0.2 * maxScroll
+  scroller.scrollTop = scrollOffset;
+  const initial_progress = (scroller.scrollTop / maxScroll) * 100;
   // Wait for new animation frame  which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -63,17 +77,25 @@
   animation.play();
   await animation.ready;
 
+  // Animation current time is at 20% because scroller was scrolled to 20%
+  // assert_equals(animation.currentTime.value, 20);
+  assert_equals(animation.currentTime.value, 20);
+  assert_equals(scroller.scrollTop, scrollOffset);
+  assert_equals(maxScroll, 900);
+
   // Change scroller size.
   scroller.style.height = "500px";
+  maxScroll = scroller.scrollHeight - scroller.clientHeight;
 
-  await animation.finished;
-  const newTime = animation.effect.getTiming().duration;
-  assert_times_equal(animation.currentTime, newTime,
-    'Animation current time is updated after scroller invalidation.');
+  assert_equals(scroller.scrollTop, scrollOffset);
+  assert_equals(maxScroll, 500);
+  await waitForNextFrame();
 
-  assert_times_equal(
-    animation.effect.getComputedTiming().localTime, newTime,
-    'Effect local time is updated after scroller invalidation.');
+  const expected_progress = (scroller.scrollTop / maxScroll) * 100;
+  assert_true(expected_progress > initial_progress);
+  assert_equals(animation.currentTime.value, expected_progress); // 45%
+  assert_equals(animation.timeline.currentTime.value, expected_progress); // 45%
+  assert_equals(animation.effect.getComputedTiming().localTime.value, expected_progress); // 45%
 }, 'Animation current time and effect local time are updated after scroller ' +
    'size changes.');
 
@@ -95,10 +117,10 @@
   // Wait for new animation frame  which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
-  assert_times_equal(timeline.currentTime, 200,
+  assert_times_equal(timeline.currentTime.value, 20,
     'Timeline current time is updated after animation frame.');
   await waitForNextFrame();
-  assert_times_equal(timeline.currentTime, 163.636,
+  assert_times_equal(timeline.currentTime.value, 16.3636,
     'Timeline current time is updated after two animation frames and ' +
     'reflects single layout run.');
 }, 'If scroll animation resizes its scroll timeline scroller, ' +
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/setting-current-time.html b/third_party/blink/web_tests/external/wpt/scroll-animations/setting-current-time.html
index 91b558b..2a8ba4e 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/setting-current-time.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/setting-current-time.html
@@ -22,238 +22,245 @@
 <div id="log"></div>
 <script>
 'use strict';
-  promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
-    const scroller = animation.timeline.scrollSource;
-    const maxScroll = scroller.scrollHeight - scroller.clientHeight;
-    scroller.scrollTop = 0.25 * maxScroll;
-    // Wait for new animation frame  which allows the timeline to compute new
-    // current time.
-    await waitForNextFrame();
-    animation.play();
 
-    await animation.ready;
+// TODO(crbug.com/1216655): Remove time range. Once time range is removed, all
+// functions that include ...WithTimeRange() should be replaced with the same
+// function but without that ending. For example:
+//
+// createScrollLinkedAnimationWithTimeRange() => createScrollLinkedAnimation()
 
-    assert_throws_js(TypeError, () => {
-      animation.currentTime = null;
-    });
-  }, 'Setting animation current time to null throws TypeError.');
+promise_test(async t => {
+  const animation = createScrollLinkedAnimation(t);
+  const scroller = animation.timeline.scrollSource;
+  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
+  scroller.scrollTop = 0.25 * maxScroll;
+  // Wait for new animation frame  which allows the timeline to compute new
+  // current time.
+  await waitForNextFrame();
+  animation.play();
 
-  promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
-    const scroller = animation.timeline.scrollSource;
-    const maxScroll = scroller.scrollHeight - scroller.clientHeight;
-    scroller.scrollTop = 0.25 * maxScroll;
-    // Wait for new animation frame  which allows the timeline to compute new
-    // current time.
-    await waitForNextFrame();
+  await animation.ready;
 
-    animation.currentTime = 333;
+  assert_throws_js(TypeError, () => {
+    animation.currentTime = null;
+  });
+}, 'Setting animation current time to null throws TypeError.');
 
-    assert_times_equal(
-      animation.currentTime,
-      333,
-      "Animation current time should be equal to the set value."
-    );
-  }, 'Set animation current time to a valid value without playing.');
+promise_test(async t => {
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
+  const scroller = animation.timeline.scrollSource;
+  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
+  scroller.scrollTop = 0.25 * maxScroll;
+  // Wait for new animation frame  which allows the timeline to compute new
+  // current time.
+  await waitForNextFrame();
 
-  promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
-    const scroller = animation.timeline.scrollSource;
-    const maxScroll = scroller.scrollHeight - scroller.clientHeight;
-    scroller.scrollTop = 0.25 * maxScroll;
-    // Wait for new animation frame  which allows the timeline to compute new
-    // current time.
-    await waitForNextFrame();
-    animation.play();
+  animation.currentTime = 333;
 
-    await animation.ready;
-    animation.currentTime = 333;
+  assert_times_equal(
+    animation.currentTime,
+    333,
+    "Animation current time should be equal to the set value."
+  );
+}, 'Set animation current time to a valid value without playing.');
 
-    assert_times_equal(
-      animation.currentTime,
-      333,
-      "Animation current time should be equal to the set value."
-    );
-  }, 'Set animation current time to a valid value while playing.');
+promise_test(async t => {
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
+  const scroller = animation.timeline.scrollSource;
+  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
+  scroller.scrollTop = 0.25 * maxScroll;
+  // Wait for new animation frame  which allows the timeline to compute new
+  // current time.
+  await waitForNextFrame();
+  animation.play();
 
-  promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
-    const scroller = animation.timeline.scrollSource;
-    const maxScroll = scroller.scrollHeight - scroller.clientHeight;
-    const range = animation.timeline.timeRange;
-    scroller.scrollTop = 0.25 * maxScroll;
-    // Wait for new animation frame  which allows the timeline to compute new
-    // current time.
-    await waitForNextFrame();
-    animation.play();
+  await animation.ready;
+  animation.currentTime = 333;
 
-    await animation.ready;
-    const largerThanDuration = animation.effect.getTiming().duration * 2;
-    animation.currentTime = largerThanDuration;
+  assert_times_equal(
+    animation.currentTime,
+    333,
+    "Animation current time should be equal to the set value."
+  );
+}, 'Set animation current time to a valid value while playing.');
 
-    assert_greater_than_equal(largerThanDuration, range, "Make sure that the" +
-      " test value is after the end of the effect and the timeline");
-    assert_equals(animation.playState, "finished");
-    assert_times_equal(
-      animation.currentTime,
-      largerThanDuration,
-      "Animation current time should be equal to the set value."
-    );
-  }, 'Set animation current time to a value beyond effect end.');
+promise_test(async t => {
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
+  const scroller = animation.timeline.scrollSource;
+  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
+  const range = animation.timeline.timeRange;
+  scroller.scrollTop = 0.25 * maxScroll;
+  // Wait for new animation frame  which allows the timeline to compute new
+  // current time.
+  await waitForNextFrame();
+  animation.play();
 
-  promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
-    const scroller = animation.timeline.scrollSource;
-    const maxScroll = scroller.scrollHeight - scroller.clientHeight;
-    const range = animation.timeline.timeRange;
-    scroller.scrollTop = 0.25 * maxScroll;
-    // Wait for new animation frame  which allows the timeline to compute new
-    // current time.
-    await waitForNextFrame();
-    animation.play();
+  await animation.ready;
+  const largerThanDuration = animation.effect.getTiming().duration * 2;
+  animation.currentTime = largerThanDuration;
 
-    await animation.ready;
-    animation.currentTime = -100;
+  assert_greater_than_equal(largerThanDuration, range, "Make sure that the" +
+    " test value is after the end of the effect and the timeline");
+  assert_equals(animation.playState, "finished");
+  assert_times_equal(
+    animation.currentTime,
+    largerThanDuration,
+    "Animation current time should be equal to the set value."
+  );
+}, 'Set animation current time to a value beyond effect end.');
 
-    assert_equals(animation.playState, "running");
-    assert_times_equal(
-      animation.currentTime,
-      -100,
-      "Animation current time should be equal to the set value."
-    );
-  }, 'Set animation current time to a negative value.');
+promise_test(async t => {
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
+  const scroller = animation.timeline.scrollSource;
+  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
+  const range = animation.timeline.timeRange;
+  scroller.scrollTop = 0.25 * maxScroll;
+  // Wait for new animation frame  which allows the timeline to compute new
+  // current time.
+  await waitForNextFrame();
+  animation.play();
 
-  promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
-    const scroller = animation.timeline.scrollSource;
-    const maxScroll = scroller.scrollHeight - scroller.clientHeight;
-    scroller.scrollTop = 0.25 * maxScroll;
-    // Wait for new animation frame  which allows the timeline to compute new
-    // current time.
-    await waitForNextFrame();
-    animation.play();
+  await animation.ready;
+  animation.currentTime = -100;
 
-    animation.currentTime = 300;
+  assert_equals(animation.playState, "running");
+  assert_times_equal(
+    animation.currentTime,
+    -100,
+    "Animation current time should be equal to the set value."
+  );
+}, 'Set animation current time to a negative value.');
 
-    assert_equals(animation.playState, "running");
-    assert_true(animation.pending);
-    assert_time_equals_literal(animation.currentTime, 300);
-  }, "Setting current time while play pending overrides the current time");
+promise_test(async t => {
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
+  const scroller = animation.timeline.scrollSource;
+  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
+  scroller.scrollTop = 0.25 * maxScroll;
+  // Wait for new animation frame  which allows the timeline to compute new
+  // current time.
+  await waitForNextFrame();
+  animation.play();
 
-  promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
-    const scroller = animation.timeline.scrollSource;
-    const maxScroll = scroller.scrollHeight - scroller.clientHeight;
-    scroller.scrollTop = 0.25 * maxScroll;
-    // Wait for new animation frame  which allows the timeline to compute new
-    // current time.
-    await waitForNextFrame();
-    animation.play();
+  animation.currentTime = 300;
 
-    await animation.ready;
-    animation.currentTime = 333;
+  assert_equals(animation.playState, "running");
+  assert_true(animation.pending);
+  assert_time_equals_literal(animation.currentTime, 300);
+}, "Setting current time while play pending overrides the current time");
 
-    assert_times_equal(
-      animation.currentTime,
-      333,
-      "Animation current time should be equal to the set value."
-    );
+promise_test(async t => {
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
+  const scroller = animation.timeline.scrollSource;
+  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
+  scroller.scrollTop = 0.25 * maxScroll;
+  // Wait for new animation frame  which allows the timeline to compute new
+  // current time.
+  await waitForNextFrame();
+  animation.play();
 
-    // Cancel the animation and play it again, check that current time has reset
-    // to scroll offset based current time.
-    animation.cancel();
-    animation.play();
-    await animation.ready;
+  await animation.ready;
+  animation.currentTime = 333;
 
-    assert_times_equal(
-      animation.currentTime,
-      animation.timeline.currentTime,
-      "Animation current time should return to a value matching its" +
-      " timeline current time after animation is cancelled and played again."
-    );
-  }, 'Setting animation.currentTime then restarting the animation should' +
-    ' reset the current time.');
+  assert_times_equal(
+    animation.currentTime,
+    333,
+    "Animation current time should be equal to the set value."
+  );
 
-  promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
-    const scroller = animation.timeline.scrollSource;
-    const maxScroll = scroller.scrollHeight - scroller.clientHeight;
-    scroller.scrollTop = 0.25 * maxScroll;
-    // Wait for new animation frame  which allows the timeline to compute new
-    // current time.
-    await waitForNextFrame();
-    animation.play();
+  // Cancel the animation and play it again, check that current time has reset
+  // to scroll offset based current time.
+  animation.cancel();
+  animation.play();
+  await animation.ready;
 
-    await animation.ready;
-    const originalCurrentTime = animation.currentTime;
+  assert_times_equal(
+    animation.currentTime,
+    animation.timeline.currentTime,
+    "Animation current time should return to a value matching its" +
+    " timeline current time after animation is cancelled and played again."
+  );
+}, 'Setting animation.currentTime then restarting the animation should' +
+  ' reset the current time.');
 
-    // Set the current time to something other than where the scroll offset.
-    animation.currentTime = 500;
+promise_test(async t => {
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
+  const scroller = animation.timeline.scrollSource;
+  const maxScroll = scroller.scrollHeight - scroller.clientHeight;
+  scroller.scrollTop = 0.25 * maxScroll;
+  // Wait for new animation frame  which allows the timeline to compute new
+  // current time.
+  await waitForNextFrame();
+  animation.play();
 
-    // Setting current time is internally setting the start time to
-    // scrollTimeline.currentTime - newAnimationCurrentTime.
-    // Which results in current time of (timeline.currentTime - start_time).
-    // This behavior puts the animation in a strange "out of sync" state between
-    // the scroller and the animation effect, this is currently expected
-    // behavior.
+  await animation.ready;
+  const originalCurrentTime = animation.currentTime;
 
-    const expectedStartTime = originalCurrentTime - animation.currentTime;
-    assert_times_equal(
-      animation.startTime,
-      expectedStartTime,
-      "Animation current time should be updated when setting the current time" +
-      " to a time within the range of the animation.");
+  // Set the current time to something other than where the scroll offset.
+  animation.currentTime = 500;
 
-    scroller.scrollTop = 0.7 * maxScroll;
-    // Wait for new animation frame  which allows the timeline to compute new
-    // current time.
-    await waitForNextFrame();
+  // Setting current time is internally setting the start time to
+  // scrollTimeline.currentTime - newAnimationCurrentTime.
+  // Which results in current time of (timeline.currentTime - start_time).
+  // This behavior puts the animation in a strange "out of sync" state between
+  // the scroller and the animation effect, this is currently expected
+  // behavior.
 
-    assert_times_equal(
-      animation.startTime,
-      expectedStartTime,
-      "Animation start time should remain unchanged when the scroller changes" +
-      " position."
-    );
-    assert_times_equal(
-      animation.currentTime,
-      animation.timeline.currentTime - animation.startTime,
-      "Animation current time should return to a value equal to" +
-      " (timeline.currentTime - animation.startTime) after timeline scroll" +
-      " source has been scrolled."
-    );
-  }, 'Set Animation current time then scroll.');
+  const expectedStartTime = originalCurrentTime - animation.currentTime;
+  assert_times_equal(
+    animation.startTime,
+    expectedStartTime,
+    "Animation current time should be updated when setting the current time" +
+    " to a time within the range of the animation.");
 
-  promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
-    const scroller = animation.timeline.scrollSource;
+  scroller.scrollTop = 0.7 * maxScroll;
+  // Wait for new animation frame  which allows the timeline to compute new
+  // current time.
+  await waitForNextFrame();
 
-    // Wait for new animation frame which allows the timeline to compute new
-    // current time.
-    await waitForNextFrame();
-    animation.play();
-    await animation.ready;
+  assert_times_equal(
+    animation.startTime,
+    expectedStartTime,
+    "Animation start time should remain unchanged when the scroller changes" +
+    " position."
+  );
+  assert_times_equal(
+    animation.currentTime,
+    animation.timeline.currentTime - animation.startTime,
+    "Animation current time should return to a value equal to" +
+    " (timeline.currentTime - animation.startTime) after timeline scroll" +
+    " source has been scrolled."
+  );
+}, 'Set Animation current time then scroll.');
 
-    // Make the timeline inactive.
-    scroller.style.overflow = 'visible';
-    scroller.scrollTop;
-    await waitForNextFrame();
+promise_test(async t => {
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
+  const scroller = animation.timeline.scrollSource;
 
-    assert_equals(animation.currentTime, null,
-      'Current time is unresolved when the timeline is inactive.');
+  // Wait for new animation frame which allows the timeline to compute new
+  // current time.
+  await waitForNextFrame();
+  animation.play();
+  await animation.ready;
 
-    animation.currentTime = 300;
-    assert_equals(animation.currentTime, 300,
-      'Animation current time should be equal to the set value.');
-    assert_equals(animation.playState, 'paused',
-      'Animation play state is \'paused\' when current time is set and ' +
-      'timeline is inactive.');
+  // Make the timeline inactive.
+  scroller.style.overflow = 'visible';
+  scroller.scrollTop;
+  await waitForNextFrame();
+
+  assert_equals(animation.currentTime, null,
+    'Current time is unresolved when the timeline is inactive.');
+
+  animation.currentTime = 300;
+  assert_equals(animation.currentTime, 300,
+    'Animation current time should be equal to the set value.');
+  assert_equals(animation.playState, 'paused',
+    'Animation play state is \'paused\' when current time is set and ' +
+    'timeline is inactive.');
 }, 'Animation current time and play state are correct when current time is ' +
    'set while the timeline is inactive.');
 
 promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
     const scroller = animation.timeline.scrollSource;
 
     // Wait for new animation frame which allows the timeline to compute new
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/setting-playback-rate.html b/third_party/blink/web_tests/external/wpt/scroll-animations/setting-playback-rate.html
index e71d933..9119c523 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/setting-playback-rate.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/setting-playback-rate.html
@@ -20,9 +20,16 @@
 </style>
 <body>
 <script>
-'use strict';
+  'use strict';
+
+  // TODO(crbug.com/1216655): Remove time range. Once time range is removed, all
+  // functions that include ...WithTimeRange() should be replaced with the same
+  // function but without that ending. For example:
+  //
+  // createScrollLinkedAnimationWithTimeRange() => createScrollLinkedAnimation()
+
   promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
     const scroller = animation.timeline.scrollSource;
     // this forces a layout which results in an active timeline
     scroller.scrollTop = 0;
@@ -39,7 +46,7 @@
        'animation is in idle state.');
 
   promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
     const scroller = animation.timeline.scrollSource;
     // this forces a layout which results in an active timeline
     scroller.scrollTop = 0;
@@ -56,7 +63,7 @@
       'animation is in play-pending state.');
 
   promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
     const scroller = animation.timeline.scrollSource;
     const maxScroll = scroller.scrollHeight - scroller.clientHeight;
     const timeRange = animation.timeline.timeRange;
@@ -74,7 +81,7 @@
       'scroll-linked animation is in running state.');
 
   promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
     const scroller = animation.timeline.scrollSource;
     const maxScroll = scroller.scrollHeight - scroller.clientHeight;
     const timeRange = animation.timeline.timeRange;
@@ -95,7 +102,7 @@
       'scroll-linked animation is in play state.');
 
   promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
     const scroller = animation.timeline.scrollSource;
     const maxScroll = scroller.scrollHeight - scroller.clientHeight;
     const timeRange = animation.timeline.timeRange;
@@ -115,7 +122,7 @@
       'affects the rate of progress of the current time');
 
   promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
     const scroller = animation.timeline.scrollSource;
     const maxScroll = scroller.scrollHeight - scroller.clientHeight;
     animation.play();
@@ -137,7 +144,7 @@
     ' when scrolling');
 
     promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
     const scroller = animation.timeline.scrollSource;
     const maxScroll = scroller.scrollHeight - scroller.clientHeight;
     scroller.scrollTop = 0.25 * maxScroll;
@@ -155,7 +162,7 @@
     ' from scrollTimeline.');
 
   test(t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
     animation.play();
     animation.currentTime = 250;
     animation.playbackRate = 2;
@@ -167,7 +174,7 @@
     ' time.');
 
   promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
     const scroller = animation.timeline.scrollSource;
     const maxScroll = scroller.scrollHeight - scroller.clientHeight;
     scroller.scrollTop = 0.25 * maxScroll;
@@ -184,7 +191,7 @@
     ' from scrollTimeline.');
 
   promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
 
     /* Wait for animation frame is here for now to avoid a renderer crash
     caused by crbug.com/1042924. Once that is fixed, these can be removed */
@@ -200,7 +207,7 @@
   }, 'Setting the playback rate while playing preserves the set current time.');
 
   promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
     const scroller = animation.timeline.scrollSource;
     const maxScroll = scroller.scrollHeight - scroller.clientHeight;
     const range = animation.timeline.timeRange;
@@ -218,7 +225,7 @@
     ' time.');
 
   promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
     const scroller = animation.timeline.scrollSource;
     const maxScroll = scroller.scrollHeight - scroller.clientHeight;
     scroller.scrollTop = 0.5 * maxScroll;
@@ -253,7 +260,7 @@
     ' time during future scrolls');
 
   promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
     const scroller = animation.timeline.scrollSource;
     const maxScroll = scroller.scrollHeight - scroller.clientHeight;
     const range = animation.timeline.timeRange;
@@ -270,7 +277,7 @@
     ' time.');
 
   promise_test(async t => {
-    const animation = createScrollLinkedAnimation(t);
+    const animation = createScrollLinkedAnimationWithTimeRange(t);
     const scroller = animation.timeline.scrollSource;
     const maxScroll = scroller.scrollHeight - scroller.clientHeight;
     scroller.scrollTop = 0.2 * maxScroll;
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/setting-start-time.html b/third_party/blink/web_tests/external/wpt/scroll-animations/setting-start-time.html
index 2b208e7..a44cf043 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/setting-start-time.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/setting-start-time.html
@@ -24,8 +24,14 @@
 <script>
 'use strict';
 
+// TODO(crbug.com/1216655): Remove time range. Once time range is removed, all
+// functions that include ...WithTimeRange() should be replaced with the same
+// function but without that ending. For example:
+//
+// createScrollLinkedAnimationWithTimeRange() => createScrollLinkedAnimation()
+
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = animation.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
   scroller.scrollTop = 0.2 * maxScroll;
@@ -57,7 +63,7 @@
 }, 'Setting the start time clears the hold time');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = animation.timeline.scrollSource;
   // Make the scroll timeline inactive.
   scroller.style.overflow = 'visible';
@@ -91,7 +97,7 @@
 }, 'Setting the start time clears the hold time when the timeline is inactive');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = animation.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
   scroller.scrollTop = 0.2 * maxScroll;
@@ -121,7 +127,7 @@
 }, 'Setting an unresolved start time sets the hold time');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = animation.timeline.scrollSource;
   // Make the scroll timeline inactive.
   scroller.style.overflow = 'visible';
@@ -155,7 +161,7 @@
    'the timeline is inactive');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
 
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
@@ -187,7 +193,7 @@
 }, 'Setting the start time resolves a pending ready promise');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = animation.timeline.scrollSource;
   // Make the scroll timeline inactive.
   scroller.style.overflow = 'visible';
@@ -224,7 +230,7 @@
    'is inactive');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
 
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
@@ -246,7 +252,7 @@
    + ' paused');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = animation.timeline.scrollSource;
   // Make the scroll timeline inactive.
   scroller.style.overflow = 'visible';
@@ -272,7 +278,7 @@
    + ' idle when the timeline is inactive');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -301,7 +307,7 @@
 }, 'Setting the start time updates the finished state');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -319,7 +325,7 @@
 }, 'Setting the start time on a running animation updates the play state');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -338,7 +344,7 @@
 }, 'Setting the start time on a reverse running animation updates the play '
    + 'state');
    promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -362,7 +368,7 @@
 }, 'Setting the start time resolves a pending pause task');
 
 promise_test(async t => {
-  const anim = createScrollLinkedAnimation(t);
+  const anim = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -390,7 +396,7 @@
 }, 'Setting the start time of a play-pending animation applies a pending playback rate');
 
 promise_test(async t => {
-  const anim = createScrollLinkedAnimation(t);
+  const anim = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/setting-timeline.tentative.html b/third_party/blink/web_tests/external/wpt/scroll-animations/setting-timeline.tentative.html
index 3fd0c0cd..e2a3710 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/setting-timeline.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/setting-timeline.tentative.html
@@ -31,6 +31,12 @@
 <script>
 'use strict';
 
+// TODO(crbug.com/1216655): Remove time range. Once time range is removed, all
+// functions that include ...WithTimeRange() should be replaced with the same
+// function but without that ending. For example:
+//
+// createScrollLinkedAnimationWithTimeRange() => createScrollLinkedAnimation()
+
 function createAnimation(t) {
   const elem = createDiv(t);
   const animation = elem.animate({ opacity: [1, 0] }, 1000);
@@ -53,7 +59,7 @@
 }
 
 function assert_timeline_current_time(animation, timeline_current_time) {
-  assert_times_equal(animation.timeline.currentTime, timeline_current_time,
+  assert_times_equal(animation.timeline.currentTime.value, timeline_current_time,
                      'Timeline\'s currentTime aligns with the scroll ' +
                      'position even when paused');
 }
@@ -61,7 +67,7 @@
 function assert_scroll_synced_times(animation, timeline_current_time,
                                     animation_current_time) {
   assert_timeline_current_time(animation, timeline_current_time);
-  assert_times_equal(animation.currentTime, animation_current_time,
+  assert_times_equal(animation.currentTime.value, animation_current_time,
                      'Animation\'s currentTime aligns with the scroll ' +
                      'position');
 }
@@ -69,7 +75,7 @@
 function assert_paused_times(animation, timeline_current_time,
                              animation_current_time) {
   assert_timeline_current_time(animation, timeline_current_time);
-  assert_times_equal(animation.currentTime, animation_current_time,
+  assert_times_equal(animation.currentTime.value, animation_current_time,
                      'Animation\'s currentTime is fixed while paused');
 }
 
@@ -83,7 +89,7 @@
   await animation.ready;
 
   assert_equals(animation.playState, 'running');
-  assert_scroll_synced_times(animation, 100, 100);
+  assert_scroll_synced_times(animation, 10, 10);
 },  'Setting a scroll timeline on a play-pending animation synchronizes ' +
     'currentTime of the animation with the scroll position.');
 
@@ -98,17 +104,17 @@
   await animation.ready;
 
   assert_equals(animation.playState, 'paused');
-  assert_paused_times(animation, 100, 0);
+  assert_paused_times(animation, 10, 0);
 
   await updateScrollPosition(animation.timeline, 200);
 
   assert_equals(animation.playState, 'paused');
-  assert_paused_times(animation, 200, 0);
+  assert_paused_times(animation, 20, 0);
 
   animation.play();
   await animation.ready;
 
-  assert_scroll_synced_times(animation, 200, 200);
+  assert_scroll_synced_times(animation, 20, 20);
 }, 'Setting a scroll timeline on a pause-pending animation fixes the ' +
    'currentTime of the animation based on the scroll position once resumed');
 
@@ -122,7 +128,7 @@
   await animation.ready;
 
   assert_equals(animation.playState, 'running');
-  assert_scroll_synced_times(animation, 100, 900);
+  assert_scroll_synced_times(animation, 10, 90);
 },  'Setting a scroll timeline on a reversed play-pending animation ' +
     'synchronizes the currentTime of the animation with the scroll ' +
     'position.');
@@ -137,7 +143,7 @@
   animation.timeline = scrollTimeline;
   assert_false(animation.pending);
   assert_equals(animation.playState, 'running');
-  assert_scroll_synced_times(animation, 100, 100);
+  assert_scroll_synced_times(animation, 10, 10);
 },  'Setting a scroll timeline on a running animation synchronizes the ' +
     'currentTime of the animation with the scroll position.');
 
@@ -152,12 +158,12 @@
   animation.timeline = scrollTimeline;
   assert_false(animation.pending);
   assert_equals(animation.playState, 'paused');
-  assert_paused_times(animation, 100, 0);
+  assert_paused_times(animation, 10, 0);
 
   animation.play();
   await animation.ready;
 
-  assert_scroll_synced_times(animation, 100, 100);
+  assert_scroll_synced_times(animation, 10, 10);
 }, 'Setting a scroll timeline on a paused animation fixes the currentTime of ' +
    'the animation based on the scroll position when resumed');
 
@@ -173,19 +179,20 @@
   animation.timeline = scrollTimeline;
   assert_false(animation.pending);
   assert_equals(animation.playState, 'paused');
-  assert_paused_times(animation, 100, 1000);
+  assert_paused_times(animation, 10, 100);
 
   animation.play();
   await animation.ready;
 
-  assert_scroll_synced_times(animation, 100, 900);
+  assert_scroll_synced_times(animation, 10, 90);
 }, 'Setting a scroll timeline on a reversed paused animation ' +
    'fixes the currentTime of the animation based on the scroll ' +
    'position when resumed');
 
+
 promise_test(async t => {
   const animation = createAnimation(t);
-  const scrollTimeline = createScrollTimeline(t);
+  const scrollTimeline = createScrollTimelineWithTimeRange(t);
   animation.timeline = scrollTimeline;
   await animation.ready;
   await updateScrollPosition(scrollTimeline, 100);
@@ -197,7 +204,7 @@
 
 promise_test(async t => {
   const animation = createAnimation(t);
-  const scrollTimeline = createScrollTimeline(t);
+  const scrollTimeline = createScrollTimelineWithTimeRange(t);
   animation.timeline = scrollTimeline;
   await animation.ready;
   await updateScrollPosition(scrollTimeline, 100);
@@ -215,6 +222,26 @@
   const scrollTimeline = createScrollTimeline(t);
   animation.timeline = scrollTimeline;
   await animation.ready;
+
+  animation.reverse();
+  animation.pause();
+  await updateScrollPosition(scrollTimeline, 100);
+  assert_scroll_synced_times(animation, 10, 90);
+
+  await animation.ready;
+
+  animation.timeline = document.timeline;
+  assert_false(animation.pending);
+  assert_equals(animation.playState, 'paused');
+  assert_times_equal(animation.currentTime, 900);
+}, 'Transition from a scroll timeline to a document timeline on a reversed ' +
+   'paused animation maintains correct currentTime');
+
+promise_test(async t => {
+  const animation = createAnimation(t);
+  const scrollTimeline = createScrollTimeline(t);
+  animation.timeline = scrollTimeline;
+  await animation.ready;
   await updateScrollPosition(scrollTimeline, 100);
 
   assert_equals(animation.playState, 'running');
@@ -237,7 +264,7 @@
 
   animation.timeline = scrollTimeline;
   assert_equals(animation.playState, 'running');
-  assert_times_equal(animation.currentTime, 100);
+  assert_times_equal(animation.currentTime.value, 10);
 }, 'Switching from a null timeline to a scroll timeline on an animation with ' +
    'a resolved start time preserved the play state');
 
@@ -251,10 +278,10 @@
   const animation = createAnimation(t);
   animation.timeline = firstScrollTimeline;
   await animation.ready;
-  assert_times_equal(animation.currentTime, 100);
+  assert_times_equal(animation.currentTime.value, 10);
 
   animation.timeline = secondScrollTimeline;
-  assert_times_equal(animation.currentTime, 200);
+  assert_times_equal(animation.currentTime.value, 20);
 }, 'Switching from one scroll timeline to another updates currentTime');
 
 
@@ -266,18 +293,18 @@
   animation.timeline = scrollTimeline;
   await animation.ready;
   assert_equals(animation.playState, 'paused');
-  assert_times_equal(animation.currentTime, 0);
+  assert_times_equal(animation.currentTime.value, 0);
 
   const target = animation.effect.target;
   target.style.animationPlayState = 'running';
   await animation.ready;
 
-  assert_times_equal(animation.currentTime, 100);
+  assert_times_equal(animation.currentTime.value, 10);
 }, 'Switching from a document timeline to a scroll timeline updates ' +
    'currentTime when unpaused via CSS.');
 
 promise_test(async t => {
-  const scrollTimeline = createScrollTimeline(t);
+  const scrollTimeline = createScrollTimelineWithTimeRange(t);
   await updateScrollPosition(scrollTimeline, 100);
 
   const animation = createAnimation(t);
@@ -295,7 +322,7 @@
    'currentTime preserves the new value when unpaused.');
 
 promise_test(async t => {
-  const scrollTimeline = createScrollTimeline(t);
+  const scrollTimeline = createScrollTimelineWithTimeRange(t);
   await updateScrollPosition(scrollTimeline, 100);
 
   const animation = createAnimation(t);
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/testcommon.js b/third_party/blink/web_tests/external/wpt/scroll-animations/testcommon.js
index 286a51b..deda3af5 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/testcommon.js
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/testcommon.js
@@ -22,8 +22,7 @@
 
 function createScrollTimeline(test, options) {
   options = options || {
-    scrollSource: createScroller(test),
-    timeRange: 1000
+    scrollSource: createScroller(test)
   }
   return new ScrollTimeline(options);
 }
@@ -32,47 +31,17 @@
   return createScrollTimeline(test, {
     scrollSource: createScroller(test),
     orientation: "vertical",
-    scrollOffsets: [startOffset, endOffset],
-    timeRange: 1000
-  });
-}
-
-function createScrollLinkedAnimation(test, timeline) {
-  if (timeline === undefined)
-    timeline = createScrollTimeline(test);
-  const DURATION = 1000; // ms
-  const KEYFRAMES = { opacity: [0, 1] };
-  return new Animation(
-    new KeyframeEffect(createDiv(test), KEYFRAMES, DURATION), timeline);
-}
-// These tests are used for the updated "progress based" animations
-// which are only tested in a small number of files. In a later change
-// the above functions that are used in all scroll timeline tests will be
-// updated and these "progress based" duplicates can be removed. Needed work
-// tracked by crbug.com/1216655
-
-function createProgressBasedScrollTimeline(test, options) {
-  options = options || {
-    scrollSource: createScroller(test)
-  }
-  return new ScrollTimeline(options);
-}
-
-function createProgressBasedScrollTimelineWithOffsets(test, startOffset, endOffset) {
-  return createScrollTimeline(test, {
-    scrollSource: createScroller(test),
-    orientation: "vertical",
     scrollOffsets: [startOffset, endOffset]
   });
 }
 
-function createProgressBasedScrollLinkedAnimation(test, timeline) {
-  return createProgressBasedScrollLinkedAnimationWithTiming(test, /* duration in ms*/ 1000, timeline);
+function createScrollLinkedAnimation(test, timeline) {
+  return createScrollLinkedAnimationWithTiming(test, /* duration in ms*/ 1000, timeline);
 }
 
-function createProgressBasedScrollLinkedAnimationWithTiming(test, timing, timeline) {
+function createScrollLinkedAnimationWithTiming(test, timing, timeline) {
   if (timeline === undefined)
-    timeline = createProgressBasedScrollTimeline(test);
+    timeline = createScrollTimeline(test);
   if (timing === undefined)
     timing = 1000; // ms
   const KEYFRAMES = { opacity: [0, 1] };
@@ -102,4 +71,34 @@
   assert_true(expected instanceof CSSUnitValue, "'expected' must be of type CSSNumberish for \"" + name + "\"");
   assert_equals(actual.unit, expected.unit, "units do not match for  \"" + name + "\"");
   assert_equals(actual.value, expected.value, "values do not match for  \"" + name + "\"");
+}
+
+// These functions are used for the tests that have not yet been updated to be
+// compatible with progress based scroll animations. Once scroll timeline
+// "timeRange" is removed, these functions should also be removed.
+// Needed work tracked by crbug.com/1216655
+function createScrollTimelineWithTimeRange(test, options) {
+  options = options || {
+    scrollSource: createScroller(test),
+    timeRange: 1000
+  }
+  return new ScrollTimeline(options);
+}
+
+function createScrollTimelineWithOffsetsWithTimeRange(test, startOffset, endOffset) {
+  return createScrollTimelineWithTimeRange(test, {
+    scrollSource: createScroller(test),
+    orientation: "vertical",
+    scrollOffsets: [startOffset, endOffset],
+    timeRange: 1000
+  });
+}
+
+function createScrollLinkedAnimationWithTimeRange(test, timeline) {
+  if (timeline === undefined)
+    timeline = createScrollTimelineWithTimeRange(test);
+  const DURATION = 1000; // ms
+  const KEYFRAMES = { opacity: [0, 1] };
+  return new Animation(
+    new KeyframeEffect(createDiv(test), KEYFRAMES, DURATION), timeline);
 }
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/update-playback-rate.html b/third_party/blink/web_tests/external/wpt/scroll-animations/update-playback-rate.html
index 82cf6999..ba5a85c 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/update-playback-rate.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/update-playback-rate.html
@@ -24,8 +24,14 @@
 <script>
 'use strict';
 
+// TODO(crbug.com/1216655): Remove time range. Once time range is removed, all
+// functions that include ...WithTimeRange() should be replaced with the same
+// function but without that ending. For example:
+//
+// createScrollLinkedAnimationWithTimeRange() => createScrollLinkedAnimation()
+
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -48,7 +54,7 @@
 }, 'Updating the playback rate maintains the current time');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -61,7 +67,7 @@
 }, 'Updating the playback rate while running makes the animation pending');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -85,7 +91,7 @@
    + ' the current time');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -101,7 +107,7 @@
    + ' the current time');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -118,7 +124,7 @@
 }, 'If a pending playback rate is set multiple times, the latest wins');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -131,7 +137,7 @@
 }, 'In the idle state, the playback rate is applied immediately');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -144,7 +150,7 @@
 }, 'In the paused state, the playback rate is applied immediately');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -161,7 +167,7 @@
    + ' the current time');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/updating-the-finished-state.html b/third_party/blink/web_tests/external/wpt/scroll-animations/updating-the-finished-state.html
index 2e758db..fa947ba 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/updating-the-finished-state.html
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/updating-the-finished-state.html
@@ -23,6 +23,12 @@
 <script>
 'use strict';
 
+// TODO(crbug.com/1216655): Remove time range. Once time range is removed, all
+// functions that include ...WithTimeRange() should be replaced with the same
+// function but without that ending. For example:
+//
+// createScrollLinkedAnimationWithTimeRange() => createScrollLinkedAnimation()
+
 // --------------------------------------------------------------------
 //
 // TESTS FOR UPDATING THE HOLD TIME
@@ -34,7 +40,7 @@
 
 // Did seek = false
 promise_test(async t => {
-  const anim = createScrollLinkedAnimation(t);
+  const anim = createScrollLinkedAnimationWithTimeRange(t);
   // Set duration to half of scroll timeline timeRange.
   anim.effect.updateTiming({ duration: 500 });
   const scroller = anim.timeline.scrollSource;
@@ -58,7 +64,7 @@
 
 // Did seek = true
 promise_test(async t => {
-  const anim = createScrollLinkedAnimation(t);
+  const anim = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = anim.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
   // Wait for new animation frame which allows the timeline to compute new
@@ -78,7 +84,7 @@
 
 // Did seek = false
 promise_test(async t => {
-  const anim = createScrollLinkedAnimation(t);
+  const anim = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = anim.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
 
@@ -97,7 +103,7 @@
 
 // Did seek = true
 promise_test(async t => {
-  const anim = createScrollLinkedAnimation(t);
+  const anim = createScrollLinkedAnimationWithTimeRange(t);
   // Set duration to half of scroll timeline timeRange.
   anim.effect.updateTiming({ duration: 500 });
   const scroller = anim.timeline.scrollSource;
@@ -122,7 +128,7 @@
 
 // Did seek = false
 promise_test(async t => {
-  const anim = createScrollLinkedAnimation(t);
+  const anim = createScrollLinkedAnimationWithTimeRange(t);
   // Set duration to half of scroll timeline timeRange.
   anim.effect.updateTiming({ duration: 500 });
   const scroller = anim.timeline.scrollSource;
@@ -147,7 +153,7 @@
 
 // Did seek = true
 promise_test(async t => {
-  const anim = createScrollLinkedAnimation(t);
+  const anim = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = anim.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
 
@@ -169,7 +175,7 @@
 
 // Did seek = false
 promise_test(async t => {
-  const anim = createScrollLinkedAnimation(t);
+  const anim = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = anim.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
 
@@ -190,7 +196,7 @@
 
 // Did seek = true
 promise_test(async t => {
-  const anim = createScrollLinkedAnimation(t);
+  const anim = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = anim.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
 
@@ -217,7 +223,7 @@
 
 // Did seek = false; playback rate > 0
 promise_test(async t => {
-  const anim = createScrollLinkedAnimation(t);
+  const anim = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = anim.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
 
@@ -248,7 +254,7 @@
 
 // Did seek = true; playback rate > 0
 promise_test(async t => {
-  const anim = createScrollLinkedAnimation(t);
+  const anim = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = anim.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
 
@@ -290,7 +296,7 @@
 
 // Did seek = true; playback rate < 0
 promise_test(async t => {
-  const anim = createScrollLinkedAnimation(t);
+  const anim = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = anim.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
 
@@ -317,7 +323,7 @@
 
 // current time < 0
 promise_test(async t => {
-  const anim = createScrollLinkedAnimation(t);
+  const anim = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = anim.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
 
@@ -341,7 +347,7 @@
 
 // current time < target end
 promise_test(async t => {
-  const anim = createScrollLinkedAnimation(t);
+  const anim = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = anim.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
 
@@ -365,7 +371,7 @@
 
 // current time > target end
 promise_test(async t => {
-  const anim = createScrollLinkedAnimation(t);
+  const anim = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = anim.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
 
@@ -389,7 +395,7 @@
 // CASE 5: current time unresolved
 
 promise_test(async t => {
-  const anim = createScrollLinkedAnimation(t);
+  const anim = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -413,7 +419,7 @@
 // CASE 6: has a pending task
 
 promise_test(async t => {
-  const anim = createScrollLinkedAnimation(t);
+  const anim = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -436,7 +442,7 @@
 
 // Did seek = false
 promise_test(async t => {
-  const anim = createScrollLinkedAnimation(t);
+  const anim = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = anim.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
   // Wait for new animation frame which allows the timeline to compute new
@@ -461,7 +467,7 @@
 
 // Did seek = true
 promise_test(async t => {
-  const anim = createScrollLinkedAnimation(t);
+  const anim = createScrollLinkedAnimationWithTimeRange(t);
   // Wait for new animation frame which allows the timeline to compute new
   // current time.
   await waitForNextFrame();
@@ -491,7 +497,7 @@
 }
 
 promise_test(t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = animation.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
   animation.play();
@@ -508,7 +514,7 @@
    + ' and then seeks back again');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = animation.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
   animation.play();
@@ -519,7 +525,7 @@
 }, 'Finish notification steps run when the animation completes normally');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = animation.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
   animation.effect.target = null;
@@ -532,7 +538,7 @@
    + ' effect completes normally');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   animation.play();
   await animation.ready;
 
@@ -541,7 +547,7 @@
 }, 'Finish notification steps run when the animation seeks past finish');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   animation.play();
   await animation.ready;
 
@@ -556,7 +562,7 @@
    + ' even if we then seek away');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = animation.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
 
@@ -570,7 +576,7 @@
 }, 'Animation finished promise is replaced after seeking back to start');
 
 promise_test(async t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = animation.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
 
@@ -588,7 +594,7 @@
 }, 'Animation finished promise is replaced after replaying from start');
 
 async_test(t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = animation.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
 
@@ -609,7 +615,7 @@
 }, 'Animation finish event is fired again after seeking back to start');
 
 async_test(t => {
-  const animation = createScrollLinkedAnimation(t);
+  const animation = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = animation.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
 
@@ -629,7 +635,7 @@
 }, 'Animation finish event is fired again after replaying from start');
 
 async_test(t => {
-  const anim = createScrollLinkedAnimation(t);
+  const anim = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = anim.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
 
@@ -649,7 +655,7 @@
    + ' endDelay has not expired');
 
 async_test(t => {
-  const anim = createScrollLinkedAnimation(t);
+  const anim = createScrollLinkedAnimationWithTimeRange(t);
   const scroller = anim.timeline.scrollSource;
   const maxScroll = scroller.scrollHeight - scroller.clientHeight;
 
diff --git a/third_party/blink/web_tests/fast/block/float/4145535Crash-expected.txt b/third_party/blink/web_tests/fast/block/float/4145535-crash-expected.txt
similarity index 97%
rename from third_party/blink/web_tests/fast/block/float/4145535Crash-expected.txt
rename to third_party/blink/web_tests/fast/block/float/4145535-crash-expected.txt
index 8392a7b..9a3813e8 100644
--- a/third_party/blink/web_tests/fast/block/float/4145535Crash-expected.txt
+++ b/third_party/blink/web_tests/fast/block/float/4145535-crash-expected.txt
@@ -1 +1,2 @@
 CONSOLE MESSAGE: Blink Test Plugin: initializing
+
diff --git a/third_party/blink/web_tests/fast/block/float/4145535-crash.html b/third_party/blink/web_tests/fast/block/float/4145535-crash.html
new file mode 100644
index 0000000..d393605
--- /dev/null
+++ b/third_party/blink/web_tests/fast/block/float/4145535-crash.html
@@ -0,0 +1,7 @@
+<table
+CELLSPACING=8888888888>
+<EMBED UNITS="4" type="application/x-blink-test-plugin">
+<script>
+if (window.testRunner)
+    testRunner.dumpAsText();
+</script>
diff --git a/third_party/blink/web_tests/fast/block/float/4145535Crash-expected.png b/third_party/blink/web_tests/fast/block/float/4145535Crash-expected.png
deleted file mode 100644
index b5daa85..0000000
--- a/third_party/blink/web_tests/fast/block/float/4145535Crash-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/fast/block/float/4145535Crash.html b/third_party/blink/web_tests/fast/block/float/4145535Crash.html
deleted file mode 100644
index d1f0f99d..0000000
--- a/third_party/blink/web_tests/fast/block/float/4145535Crash.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<table
-CELLSPACING=8888888888>
-<EMBED UNITS="4" type="application/x-blink-test-plugin">
diff --git a/third_party/blink/web_tests/fast/canvas/fragmented-composited-canvas-crash.html b/third_party/blink/web_tests/fast/canvas/fragmented-composited-canvas-crash.html
new file mode 100644
index 0000000..0e02761
--- /dev/null
+++ b/third_party/blink/web_tests/fast/canvas/fragmented-composited-canvas-crash.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+Passes if it does not crash.
+<div style="columns: 3;">
+  <div style="width: 600px; height: 300px; position: relative;">
+    <canvas id="canvas" width="600" height="300" style="position: absolute; left: 0; top: 0;">
+    </canvas>
+  </div>
+</div>
+<script>
+async_test(t => {
+  const canvas = document.getElementById('canvas');
+  const ctx = canvas.getContext('2d');
+  ctx.fillStyle = 'green';
+  ctx.fillRect(0, 0, 100, 100);
+  t.done();
+});
+</script>
diff --git a/third_party/blink/web_tests/flag-specific/highdpi/fast/block/float/4145535Crash-expected.png b/third_party/blink/web_tests/flag-specific/highdpi/fast/block/float/4145535Crash-expected.png
deleted file mode 100644
index 0ad21d1d..0000000
--- a/third_party/blink/web_tests/flag-specific/highdpi/fast/block/float/4145535Crash-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/anonymous-iframe/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/virtual/anonymous-iframe/webexposed/global-interface-listing-expected.txt
index ce74792..1067156 100644
--- a/third_party/blink/web_tests/virtual/anonymous-iframe/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/virtual/anonymous-iframe/webexposed/global-interface-listing-expected.txt
@@ -1237,10 +1237,6 @@
     getter reason
     getter wasClean
     method constructor
-interface ColorSelectEvent : PointerEvent
-    attribute @@toStringTag
-    getter value
-    method constructor
 interface Comment : CharacterData
     attribute @@toStringTag
     method constructor
@@ -2579,16 +2575,10 @@
     method AddSearchProvider
     method IsSearchProviderInstalled
     method constructor
-interface EyeDropper : EventTarget
+interface EyeDropper
     attribute @@toStringTag
-    getter onclose
-    getter oncolorselect
-    getter opened
-    method close
     method constructor
     method open
-    setter onclose
-    setter oncolorselect
 interface FaceDetector
     attribute @@toStringTag
     method constructor
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index d3791d6..200666e5 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -1237,10 +1237,6 @@
     getter reason
     getter wasClean
     method constructor
-interface ColorSelectEvent : PointerEvent
-    attribute @@toStringTag
-    getter value
-    method constructor
 interface Comment : CharacterData
     attribute @@toStringTag
     method constructor
@@ -2579,16 +2575,10 @@
     method AddSearchProvider
     method IsSearchProviderInstalled
     method constructor
-interface EyeDropper : EventTarget
+interface EyeDropper
     attribute @@toStringTag
-    getter onclose
-    getter oncolorselect
-    getter opened
-    method close
     method constructor
     method open
-    setter onclose
-    setter oncolorselect
 interface FaceDetector
     attribute @@toStringTag
     method constructor
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium
index 6d1fa83..f8827cf5 100644
--- a/third_party/crashpad/README.chromium
+++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@
 Short Name: crashpad
 URL: https://crashpad.chromium.org/
 Version: unknown
-Revision: c4081b8e6ddf08b94dd61d8f1a5df421ab42a1cf
+Revision: b8a16857735ba8e6464696362625bf54938417d7
 License: Apache 2.0
 License File: crashpad/LICENSE
 Security Critical: yes
diff --git a/third_party/crashpad/crashpad/client/crashpad_client.h b/third_party/crashpad/crashpad/client/crashpad_client.h
index ec6c5e5..eea953d 100644
--- a/third_party/crashpad/crashpad/client/crashpad_client.h
+++ b/third_party/crashpad/crashpad/client/crashpad_client.h
@@ -462,7 +462,7 @@
   //! \param[in] database The path to a Crashpad database.
   //! \param[in] url The URL of an upload server.
   //! \param[in] annotations Process annotations to set in each crash report.
-  void StartCrashpadInProcessHandler(
+  static void StartCrashpadInProcessHandler(
       const base::FilePath& database,
       const std::string& url,
       const std::map<std::string, std::string>& annotations);
@@ -479,7 +479,24 @@
   //! \param[in] annotations Process annotations to set in each crash report.
   //!     Useful when adding crash annotations detected on the next run after a
   //!     crash but before upload.
-  void ProcessIntermediateDumps(
+  static void ProcessIntermediateDumps(
+      const std::map<std::string, std::string>& annotations = {});
+
+  //! \brief Requests that the handler convert a single intermediate dump at \a
+  //!     file generated by DumpWithoutCrashAndDeferProcessingAtPath into a
+  //!     minidump and trigger an upload if possible.
+  //!
+  //! A handler must have already been installed before calling this method.
+  //! This method should be called when an application is ready to start
+  //! processing previously created intermediate dumps. Processing will block,
+  //! so this should not be called on the main UI thread.
+  //!
+  //! \param[in] file The intermediate dump to process.
+  //! \param[in] annotations Process annotations to set in each crash report.
+  //!     Useful when adding crash annotations detected on the next run after a
+  //!     crash but before upload.
+  static void ProcessIntermediateDump(
+      const base::FilePath& file,
       const std::map<std::string, std::string>& annotations = {});
 
   //! \brief Requests that the handler begin in-process uploading of any
@@ -489,11 +506,11 @@
   //! on another thread. This method does not block.
   //!
   //! A handler must have already been installed before calling this method.
-  void StartProcesingPendingReports();
+  static void StartProcessingPendingReports();
 
   //! \brief Requests that the handler capture an intermediate dump even though
   //!     there hasn't been a crash. The intermediate dump will be converted
-  //!     to a mindump immediately. If StartProcesingPendingReports() has been
+  //!     to a mindump immediately. If StartProcessingPendingReports() has been
   //!     called, this will also trigger an upload.
   //!
   //! For internal use only. Clients should use CRASHPAD_SIMULATE_CRASH().
@@ -516,6 +533,23 @@
   //! \param[in] context A NativeCPUContext, generally captured by
   //!     CaptureContext() or similar.
   static void DumpWithoutCrashAndDeferProcessing(NativeCPUContext* context);
+
+  //! \brief Requests that the handler capture an intermediate dump and store it
+  //!     in path, even though there hasn't been a crash. The intermediate dump
+  //!     will not be converted to a mindump until ProcessIntermediateDump() is
+  //!     called.
+  //!
+  //! For internal use only. Clients should use
+  //! CRASHPAD_SIMULATE_CRASH_AND_DEFER_PROCESSING_AT_PATH().
+  //!
+  //! A handler must have already been installed before calling this method.
+  //!
+  //! \param[in] context A NativeCPUContext, generally captured by
+  //!     CaptureContext() or similar.
+  //! \param[in] path The path for writing the intermediate dump.
+  static void DumpWithoutCrashAndDeferProcessingAtPath(
+      NativeCPUContext* context,
+      const base::FilePath path);
 #endif
 
 #if defined(OS_APPLE) || DOXYGEN
diff --git a/third_party/crashpad/crashpad/client/crashpad_client_ios.cc b/third_party/crashpad/crashpad/client/crashpad_client_ios.cc
index 69e90d8c..a8ef224 100644
--- a/third_party/crashpad/crashpad/client/crashpad_client_ios.cc
+++ b/third_party/crashpad/crashpad/client/crashpad_client_ios.cc
@@ -55,6 +55,10 @@
   void ProcessIntermediateDumps(
       const std::map<std::string, std::string>& annotations = {}) {}
 
+  void ProcessIntermediateDump(
+      const base::FilePath& file,
+      const std::map<std::string, std::string>& annotations = {}) {}
+
   void DumpWithoutCrash(NativeCPUContext* context) {
     INITIALIZATION_STATE_DCHECK_VALID(initialized_);
     mach_exception_data_type_t code[2] = {};
@@ -220,7 +224,16 @@
 }
 
 // static
-void CrashpadClient::StartProcesingPendingReports() {
+void CrashpadClient::ProcessIntermediateDump(
+    const base::FilePath& file,
+    const std::map<std::string, std::string>& annotations) {
+  CrashHandler* crash_handler = CrashHandler::Get();
+  DCHECK(crash_handler);
+  crash_handler->ProcessIntermediateDump(file, annotations);
+}
+
+// static
+void CrashpadClient::StartProcessingPendingReports() {
   // TODO(justincohen): Start the CrashReportUploadThread.
 }
 
@@ -242,4 +255,14 @@
   crash_handler->DumpWithoutCrash(context);
 }
 
+// static
+void CrashpadClient::DumpWithoutCrashAndDeferProcessingAtPath(
+    NativeCPUContext* context,
+    const base::FilePath path) {
+  CrashHandler* crash_handler = CrashHandler::Get();
+  DCHECK(crash_handler);
+  // TODO(justincohen): Change to DumpWithoutCrashAtPath(context, path).
+  crash_handler->DumpWithoutCrash(context);
+}
+
 }  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/client/simulate_crash_ios.h b/third_party/crashpad/crashpad/client/simulate_crash_ios.h
index 87a94578..14e1e153 100644
--- a/third_party/crashpad/crashpad/client/simulate_crash_ios.h
+++ b/third_party/crashpad/crashpad/client/simulate_crash_ios.h
@@ -47,4 +47,12 @@
         &cpu_context);                                            \
   } while (false)
 
+#define CRASHPAD_SIMULATE_CRASH_AND_DEFER_PROCESSING_AT_PATH(path)      \
+  do {                                                                  \
+    crashpad::NativeCPUContext cpu_context;                             \
+    crashpad::CaptureContext(&cpu_context);                             \
+    crashpad::CrashpadClient::DumpWithoutCrashAndDeferProcessingAtPath( \
+        &cpu_context, path);                                            \
+  } while (false)
+
 #endif  // CRASHPAD_CLIENT_SIMULATE_CRASH_IOS_H_
diff --git a/third_party/crashpad/crashpad/doc/ios_overview_design.md b/third_party/crashpad/crashpad/doc/ios_overview_design.md
index 943d7a5d..1c4d6dd 100644
--- a/third_party/crashpad/crashpad/doc/ios_overview_design.md
+++ b/third_party/crashpad/crashpad/doc/ios_overview_design.md
@@ -96,7 +96,7 @@
 stability concerns. In this case, intermediate dumps are automatically
 converted to minidumps and immediately eligible for uploading.
 
-### `StartProcesingPendingReports`
+### `StartProcessingPendingReports`
 For similar reasons, applications may choose the correct time to begin uploading
 pending reports, such as when ideal network conditions exist. By default,
 clients start with uploading disabled. Applications should call this API when
diff --git a/third_party/crashpad/crashpad/handler/win/crashy_signal.cc b/third_party/crashpad/crashpad/handler/win/crashy_signal.cc
index 8caa625..e2deaca 100644
--- a/third_party/crashpad/crashpad/handler/win/crashy_signal.cc
+++ b/third_party/crashpad/crashpad/handler/win/crashy_signal.cc
@@ -39,7 +39,6 @@
 
 DWORD WINAPI BackgroundThread(void* arg) {
   abort();
-  return 0;
 }
 
 int CrashySignalMain(int argc, wchar_t* argv[]) {
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index 19c88a2..48a4dd28 100644
--- a/third_party/freetype/README.chromium
+++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@
 Name: FreeType
 URL: http://www.freetype.org/
-Version: VER-2-10-4-323
-Revision: 5d27b10f4c6c8e140bd48a001b98037ac0d54118
+Version: VER-2-10-4-326-g86b9c9347
+Revision: 86b9c9347f99174f4fea3e9deca5800e57a987f2
 CPEPrefix: cpe:/a:freetype:freetype:2.10.4
 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent
          JPEG Group) licenses"
diff --git a/third_party/sqlite/README.md b/third_party/sqlite/README.md
index cd205e2..fd30d35 100644
--- a/third_party/sqlite/README.md
+++ b/third_party/sqlite/README.md
@@ -1,28 +1,58 @@
-This is the top folder for Chromium's SQLite. The actual SQLite source is not
-in this repository, but instead cloned into the `src` directory from
-https://chromium.googlesource.com/chromium/deps/sqlite.
+# Chromium SQLite.
+This is the top folder for Chromium's [SQLite](https://www.sqlite.org/). The
+actual SQLite source is not in this repository, but instead cloned into the
+`src` directory from https://chromium.googlesource.com/chromium/deps/sqlite.
 
 The directory structure is as follows. Files common to all third_party projects
-(BUILD.GN, OWNERS, LICENSE) are omitted.
+(ex. BUILD.GN, OWNERS, LICENSE) are omitted.
 
 * `src/`     The Chromium fork of SQLite (cloned via top level DEPS file).
 * `scripts/` Scripts that generate the files in the amalgamations in src/.
 * `sqlite.h` The header used by the rest of Chromium to include SQLite. This
              forwards to src/amalgamation/sqlite3.h
-* `fuzz/`    Google OSS-Fuzz (ClusterFuzz) testing for Chromium's SQLite
-             build This directory contains:
+* `fuzz/`    Google OSS-Fuzz (ClusterFuzz) testing for Chromium's SQLite build.
 
-The SQLite amalgamation is committed to the SQLite Chromium repository (in
-`src`), but it is created by a script that lives in the Chromium repository.
-This is because the configuration variables for building and amalgamation
-generation are shared.
+## Amalgamations
 
-There are two amalgamations. The one in //third_party/sqlite/src/amalgamation
-is used by Chromium. A second, located at
-//third_party/sqlite/src/amalgamation_dev is used for some Chromium developer
-tools and is not distributed.
+[SQLite amalgamations](https://www.sqlite.org/amalgamation.html) are committed
+to the SQLite Chromium repository (in `src`), but are created by a script that
+lives in the Chromium repository. This is because the configuration variables
+for building and amalgamation generation are shared.
 
-# Upgrade to a new SQLite release.
+There are two amalgamations:
+* //third_party/sqlite/src/amalgamation is shipped, tested, and Fuzzed by
+  Chromium.
+* //third_party/sqlite/src/amalgamation_dev is not distributed or tested by
+  Chromium. It is used for some developer tools (either only for local
+  development, or only on trusted input).
+
+## [//third_party/sqlite/src](https://source.chromium.org/chromium/chromium/src/+/main:third_party/sqlite/src/) repository.
+
+CLs in this repository cannot be submitted through the commit queue (ex. CQ+2),
+because there is no commit queue / try bot support for this repository. Please
+use the "Submit" button (in Gerrit's 3-dot menu on the top right) to submit CLs
+in this repository instead.
+
+# Playbook
+
+## Upgrade to a new SQLite release.
+
+SQLite should be upgraded as soon as possible whenever a new version is
+available. This is because new versions often contain security and stability
+improvements, and frequent upgrades allow Chromium to have minimal cherry-pick
+diffs when requesting investigation for SQLite bugs discovered by Chromium
+Fuzzers. New versions may be viewed at https://www.sqlite.org/news.html, and
+bugs for these upgrades may look like [this example](https://crbug.com/1161048).
+
+Historically, Chromium fuzzers often find issues within 2 weeks after upgrading
+to new SQLite versions. Avoid upgrading SQLite within 1-2 weeks of a Chromium
+[branch point](https://chromiumdash.appspot.com/schedule) to allow fuzzers time
+to run. However, if the new SQLite release contains known security or stability
+fixes, upgrade once available and monitor fuzzers more closely.
+
+SQLite version upgrades tend to be extremely large changes
+([example](https://crrev.com/c/2601105)), for which the diffs are not possible
+to thoroughly review.
 
 **Note** SQLite tags all releases `version-<release number>`, e.g.
 `version-3.33.0`. The Chromium project prefixes all tags/branches with
@@ -30,12 +60,12 @@
 
 1. Create new release branch
 
-   Use the SQLite commit ID when creating a branch. For example
-   "562fd18b9dc27216191c0a6477bba9b175f7f0d2" corresponds to the
-   3.33.0 release. The commit is used, instead of the tag name, because
-   we do not mirror the SQLite tags along with the commits. The correct
-   commit ID can be found at
-   [sqlite/releases](https://github.com/sqlite/sqlite/releases).
+   Use the SQLite git commit hash for the release, found at
+   [sqlite/releases](https://github.com/sqlite/sqlite/releases), when creating
+   a new release branch. For example,
+   "[562fd18b9dc27216191c0a6477bba9b175f7f0d2](https://github.com/sqlite/sqlite/commit/562fd18b9dc27216191c0a6477bba9b175f7f0d2)"
+   corresponds to the 3.31.1 release. The commit is used instead of the tag
+   name because we do not mirror the SQLite tags along with the commits.
 
    Create the branch at
    [Gerrit/branches](https://chromium-review.googlesource.com/admin/repos/chromium/deps/sqlite,branches).
@@ -76,17 +106,25 @@
 
     Once review above has merged:
 
-    1. Roll the `chromium/src/DEPS` file to reference that new commit ID.
+    1. Roll the `chromium/src/DEPS` file to reference that new commit hash.
         ```sh
         roll-dep src/third_party/sqlite/src --roll-to <git hash of merged CL>
         ```
     2. Update the version in //third_party/sqlite/README.chromium. Append the
        commit created by roll-dep above.
 
-# Cherry-pick unreleased commit from SQLite.
+## Cherry-pick unreleased commit from SQLite.
 
 Sometimes **critical fixes** land in SQLite's master, but are not yet in a
-release. If these need to be brought into the current release branch do the
+release. This may occur when other SQLite embedders find critical security
+or stability issues that SQLite authors then fix, but are often detected by
+Chromium ClusterFuzz as well.
+
+If you're triaging a ClusterFuzz bug, an internal playbook on how to triage
+and fix ClusterFuzz bugs is available at
+[go/sqlite-clusterfuzz-bug-process](https://goto.google.com/sqlite-clusterfuzz-bug-process).
+
+If changes need to be brought into the current release branch, please do the
 following:
 
 1. Checkout the current release branch.
@@ -106,8 +144,8 @@
     the sqlite_cherry_picker.py script is preferred. This script automates a
     few tasks such as:
 
-    * Identifying the correct Git commit ID to use if given the
-      Fossil commit ID.
+    * Identifying the correct Git commit hash to use if given the
+      Fossil commit hash.
     * Automatically calculating Fossil manifest hashes.
     * Skipping conflicted binary files.
     * Generating the amalgamations.
@@ -115,25 +153,31 @@
     Cherry-pick the commit:
 
     ```sh
-    ../scripts/sqlite_cherry_picker.py <full git or fossil commit id>
+    ../scripts/sqlite_cherry_picker.py <full git or fossil commit hash>
     ```
 
     If there is a conflict that the script cannot resolve then, like
-    git-cherry-pick, the script will exit and leave you to resolve the
+    `git cherry-pick`, the script will exit and leave you to resolve the
     conflicts. Once resolved run the script a second time:
 
     ```sh
     ../scripts/sqlite_cherry_picker.py --continue
     ```
 
+    If you have access to the SQLite fossil commit hash, and would like to map
+    this to the corresponding git hash, you can use GitHub search. As SQLite's
+    git repository's commits include the fossil hash, you can search for the
+    fossil hash, using the following query with the fossil commit hash appended
+    ([example search](https://github.com/sqlite/sqlite/search?type=commits&q=8c432642572c8c4b7251f413def0725b3b8e9e7fe10230aa0aabe86b58e5902d)):
+    https://github.com/sqlite/sqlite/search?type=commits&q=
+
     If the cherry-picking script is unable to cherry-pick a commit, like in
-    https://crbug.com/1162100, manually apply the change from a sqlite or git,
-    in //third_party/sqlite/src's files modified in the sqlite tracker, like at
+    https://crbug.com/1162100, manually apply the change from a SQLite or git,
+    in //third_party/sqlite/src's files modified in the SQLite tracker, like at
     https://sqlite.org/src/info/a0bf931bd712037e. From there, run
     `../scripts/generate_amalgamation.py` to propagate these changes over to
-    the amalgamation files. The sqlite_cherry_picker should generally be
-    preferred though, as it updates hashes and makes tracking easier.
-
+    the amalgamation files. sqlite_cherry_picker.py should generally be
+    preferred, as it updates hashes and simplifies tracking.
 
 3. Run local tests.
 
@@ -142,6 +186,9 @@
 
 4. Upload cherry-picked change (with amalgamations) for review.
 
+  If the relevant bug is a security bug, make sure that the reviewers are cc'ed.
+  Otherwise, they may not know what/why they're reviewing.
+
     ```sh
     git cl upload
     ```
@@ -149,13 +196,13 @@
 5. Update the Chromium DEPS file.
 
     Once review above has merged, roll the `chromium/src/DEPS` file to
-    reference that new commit ID.
+    reference that new commit hash.
 
     ```sh
     roll-dep src/third_party/sqlite/src --roll-to <git hash of merged CL>
     ```
 
-# Running Tests
+## Running Tests
 
 Build all desktop targets:
 
@@ -168,36 +215,38 @@
 nm -B out/Default/libchromium_sqlite3.so | cut -c 18- | sort | grep '^T'
 ```
 
-## Running unit tests
+### Running unit tests
 
 ```sh
 out/Default/sql_unittests
 ```
 
-## Running web tests
+### Running web tests
 
 ```sh
 third_party/blink/tools/run_web_tests.py -t Default storage/websql/
 ```
 
-## Running SQLite's TCL test suite within the Chromium checkout.
+### Running SQLite's TCL test suite within the Chromium checkout.
 
 This is one of the [SQLite test suites](https://www.sqlite.org/testing.html).
 They take approximately 3 minutes to build and run on a fast workstation.
 
+**Note**: Tests currently fail both locally and on Chromium release branches.
+They fail on release branches because some tests rely on SQLite databases
+(binary files) which are committed to the source and are likely not merged down
+when cherry picked. It is safe to ignore these errors which should be
+reasonably easy to identify based on the cherry picked upstream changes. Until
+these tests are fixed, it is safe to ignore these tests when running SQLite test
+suites.
+
 ```sh
 cd //third_party/sqlite
 ./scripts/generate_amalgamation.py --testing
 make --directory=src test | tee /tmp/test.log
 ```
 
-**Note**: Tests may fail on Chromium release branches. This is because some
-tests rely on SQLite databases (binary files) which are committed to the
-source and are likely not merged down when cherry picked. It is safe to
-ignore these errors which should be reasonably easy to identify based on the
-cherry picked upstream changes.
-
-Show error'ed tests:
+Show tests with errors:
 
 ```sh
 egrep 'errors out of' /tmp/test.log
@@ -211,7 +260,7 @@
 
 Broken tests will also show lines ending in "..." instead of "... Ok".
 
-When done cleanup the SQLite repository:
+When done, clean up the SQLite repository:
 
 ```sh
 cd src
diff --git a/third_party/tcmalloc/README.chromium b/third_party/tcmalloc/README.chromium
index ec09d38..3a8e560 100644
--- a/third_party/tcmalloc/README.chromium
+++ b/third_party/tcmalloc/README.chromium
@@ -79,3 +79,4 @@
 - Enable ASLR support on both Linux and ChromeOS
 - Remove unused base::subtle::Acquire_Store/Release_Load (https://github.com/gperftools/gperftools/pull/1249)
 - Fix thread-safety annotations (https://github.com/gperftools/gperftools/pull/1251)
+- Fixed -Wimplicit-int-float-conversion.
diff --git a/third_party/tcmalloc/chromium/src/sampler.cc b/third_party/tcmalloc/chromium/src/sampler.cc
index 358b52c7..6337826 100644
--- a/third_party/tcmalloc/chromium/src/sampler.cc
+++ b/third_party/tcmalloc/chromium/src/sampler.cc
@@ -116,7 +116,8 @@
   // Very large values of interval overflow ssize_t. If we happen to
   // hit such improbable condition, we simply cheat and clamp interval
   // to largest supported value.
-  return static_cast<ssize_t>(std::min<double>(interval, MAX_SSIZE));
+  return static_cast<ssize_t>(
+      std::min(interval, static_cast<double>(MAX_SSIZE)));
 }
 
 bool Sampler::RecordAllocationSlow(size_t k) {
diff --git a/tools/json_schema_compiler/feature_compiler.py b/tools/json_schema_compiler/feature_compiler.py
index e462329..6a94be1 100644
--- a/tools/json_schema_compiler/feature_compiler.py
+++ b/tools/json_schema_compiler/feature_compiler.py
@@ -210,6 +210,8 @@
                 'theme': 'Manifest::TYPE_THEME',
                 'login_screen_extension':
                 'Manifest::TYPE_LOGIN_SCREEN_EXTENSION',
+                'chromeos_system_extension':
+                'Manifest::TYPE_CHROMEOS_SYSTEM_EXTENSION',
             },
             'allow_all': True
         },
diff --git a/tools/json_schema_compiler/test/features_generation_unittest.cc b/tools/json_schema_compiler/test/features_generation_unittest.cc
index efb552bc..80de7391 100644
--- a/tools/json_schema_compiler/test/features_generation_unittest.cc
+++ b/tools/json_schema_compiler/test/features_generation_unittest.cc
@@ -227,7 +227,8 @@
                                   Manifest::TYPE_PLATFORM_APP,
                                   Manifest::TYPE_SHARED_MODULE,
                                   Manifest::TYPE_THEME,
-                                  Manifest::TYPE_LOGIN_SCREEN_EXTENSION};
+                                  Manifest::TYPE_LOGIN_SCREEN_EXTENSION,
+                                  Manifest::TYPE_CHROMEOS_SYSTEM_EXTENSION};
     comparator.channel = version_info::Channel::BETA;
     comparator.CompareFeature(feature);
   }
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 57d09428a..095b49a 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -535,7 +535,7 @@
 
     'chromium.memory': {
       'Linux ASan LSan Builder': 'asan_lsan_release_trybot',
-      'Linux CFI': 'cfi_full_cfi_icall_cfi_diag_thin_lto_release_static_dcheck_always_on_goma',
+      'Linux CFI': 'cfi_full_cfi_icall_cfi_diag_goma_thin_lto_release_static_dcheck_always_on_goma',
       'Linux Chromium OS ASan LSan Builder': 'asan_lsan_chromeos_release_trybot',
       'Linux ChromiumOS MSan Builder': 'chromeos_msan_release_bot',
       'Linux MSan Builder': 'msan_release_bot',
@@ -1039,7 +1039,7 @@
       'linux-xenial-rel': 'gpu_tests_release_trybot_no_symbols_use_dummy_lastchange_code_coverage',
       'linux_chromium_archive_rel_ng': 'release_bot',
       'linux_chromium_asan_rel_ng': 'asan_lsan_release_trybot',
-      'linux_chromium_cfi_rel_ng': 'cfi_full_cfi_icall_cfi_diag_thin_lto_release_static_dcheck_always_on_goma',
+      'linux_chromium_cfi_rel_ng': 'cfi_full_cfi_icall_cfi_diag_goma_thin_lto_release_static_dcheck_always_on_goma',
       'linux_chromium_chromeos_asan_rel_ng': 'asan_lsan_chromeos_release_trybot',
       'linux_chromium_chromeos_msan_rel_ng': 'chromeos_msan_release_bot',
       'linux_chromium_clobber_deterministic': 'release_trybot',
@@ -1729,8 +1729,8 @@
       'cfi_full', 'cfi_icall', 'cfi_diag', 'cfi_recover', 'thin_lto', 'release', 'static', 'goma',
     ],
 
-    'cfi_full_cfi_icall_cfi_diag_thin_lto_release_static_dcheck_always_on_goma': [
-      'cfi_full', 'cfi_icall', 'cfi_diag', 'thin_lto', 'release', 'static', 'dcheck_always_on', 'goma',
+    'cfi_full_cfi_icall_cfi_diag_goma_thin_lto_release_static_dcheck_always_on_goma': [
+     'cfi_full', 'cfi_icall', 'cfi_diag', 'thin_lto', 'goma_thin_lto', 'release', 'static', 'dcheck_always_on', 'goma',
     ],
 
     'chromeos_amd64-generic': [
@@ -2468,11 +2468,11 @@
     ],
 
     'official_goma_android_arm32_pgo': [
-      'official', 'goma', 'android', 'arm', 'no_symbols', 'no_default_afdo', 'pgo_phase_1',
+      'official', 'goma', 'android', 'arm', 'minimal_symbols', 'no_default_afdo', 'pgo_phase_1',
     ],
 
     'official_goma_android_arm64_pgo': [
-      'official', 'goma', 'android', 'arm64', 'no_symbols', 'no_default_afdo', 'pgo_phase_1',
+      'official', 'goma', 'android', 'arm64', 'minimal_symbols', 'no_default_afdo', 'pgo_phase_1',
     ],
 
     'official_goma_mac': [
@@ -3592,6 +3592,10 @@
       'gn_args': 'use_thin_lto=true',
     },
 
+    'goma_thin_lto': {
+      'gn_args': 'use_goma_thin_lto=true',
+    },
+
     'thin_lto_opt': {
       'gn_args': 'use_thin_lto=true thin_lto_enable_optimizations=true',
     },
diff --git a/tools/mb/mb_config_expectations/chrome.pgo.json b/tools/mb/mb_config_expectations/chrome.pgo.json
index 1b9ae5ea..fd49a37 100644
--- a/tools/mb/mb_config_expectations/chrome.pgo.json
+++ b/tools/mb/mb_config_expectations/chrome.pgo.json
@@ -8,7 +8,7 @@
       "is_official_build": true,
       "proprietary_codecs": true,
       "strip_absolute_paths_from_debug_symbols": true,
-      "symbol_level": 0,
+      "symbol_level": 1,
       "target_cpu": "arm",
       "target_os": "android",
       "use_goma": true
@@ -23,7 +23,7 @@
       "is_official_build": true,
       "proprietary_codecs": true,
       "strip_absolute_paths_from_debug_symbols": true,
-      "symbol_level": 0,
+      "symbol_level": 1,
       "target_cpu": "arm64",
       "target_os": "android",
       "use_goma": true
diff --git a/tools/mb/mb_config_expectations/chromium.memory.json b/tools/mb/mb_config_expectations/chromium.memory.json
index 5f988715..925c4c7 100644
--- a/tools/mb/mb_config_expectations/chromium.memory.json
+++ b/tools/mb/mb_config_expectations/chromium.memory.json
@@ -21,6 +21,7 @@
       "use_cfi_diag": true,
       "use_cfi_icall": true,
       "use_goma": true,
+      "use_goma_thin_lto": true,
       "use_thin_lto": true
     }
   },
diff --git a/tools/mb/mb_config_expectations/tryserver.chrome.pgo.json b/tools/mb/mb_config_expectations/tryserver.chrome.pgo.json
index 1b9ae5ea..fd49a37 100644
--- a/tools/mb/mb_config_expectations/tryserver.chrome.pgo.json
+++ b/tools/mb/mb_config_expectations/tryserver.chrome.pgo.json
@@ -8,7 +8,7 @@
       "is_official_build": true,
       "proprietary_codecs": true,
       "strip_absolute_paths_from_debug_symbols": true,
-      "symbol_level": 0,
+      "symbol_level": 1,
       "target_cpu": "arm",
       "target_os": "android",
       "use_goma": true
@@ -23,7 +23,7 @@
       "is_official_build": true,
       "proprietary_codecs": true,
       "strip_absolute_paths_from_debug_symbols": true,
-      "symbol_level": 0,
+      "symbol_level": 1,
       "target_cpu": "arm64",
       "target_os": "android",
       "use_goma": true
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.linux.json b/tools/mb/mb_config_expectations/tryserver.chromium.linux.json
index c9eb7162..e37fe57 100644
--- a/tools/mb/mb_config_expectations/tryserver.chromium.linux.json
+++ b/tools/mb/mb_config_expectations/tryserver.chromium.linux.json
@@ -866,6 +866,7 @@
       "use_cfi_diag": true,
       "use_cfi_icall": true,
       "use_goma": true,
+      "use_goma_thin_lto": true,
       "use_thin_lto": true
     }
   },
diff --git a/tools/mb/rts_banned_suites.json b/tools/mb/rts_banned_suites.json
index a64b9a63..95ccb99 100644
--- a/tools/mb/rts_banned_suites.json
+++ b/tools/mb/rts_banned_suites.json
@@ -19,7 +19,8 @@
     "telemetry_gpu_integration_test_android_monochrome",
     "telemetry_gpu_integration_test_android_monochrome_bundle",
     "telemetry_gpu_integration_test_android_weblayer",
-    "telemetry_gpu_integration_test_android_webview"
+    "telemetry_gpu_integration_test_android_webview",
+    "monochrome_public_apk_checker"
   ],
   "fuchsia_x64_rts": [
     "blink_web_tests"
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 1e2cc50..c1d0370 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -8368,6 +8368,11 @@
   <int value="1" label="Anchor element has same host as document host"/>
 </enum>
 
+<enum name="BooleanAnnotated">
+  <int value="0" label="Not Annotated"/>
+  <int value="1" label="Annotated"/>
+</enum>
+
 <enum name="BooleanAttached">
   <int value="0" label="Detached"/>
   <int value="1" label="Attached"/>
@@ -25889,6 +25894,8 @@
   <int value="872" label="RestrictedManagedGuestSessionEnabled"/>
   <int value="873" label="ReportDeviceAudioStatus"/>
   <int value="874" label="DeviceHostnameUserConfigurable"/>
+  <int value="875" label="ReportDeviceNetworkConfiguration"/>
+  <int value="876" label="ReportDeviceNetworkStatus"/>
 </enum>
 
 <enum name="EnterprisePolicyDeviceIdValidity">
@@ -33404,9 +33411,9 @@
   <int value="3386" label="V8FontManager_Query_Method"/>
   <int value="3387" label="AudioContextBaseLatency"/>
   <int value="3388" label="V8Window_GetScreens_Method"/>
-  <int value="3389" label="V8Window_IsMultiScreen_Method"/>
-  <int value="3390" label="V8Window_Onscreenschange_AttributeGetter"/>
-  <int value="3391" label="V8Window_Onscreenschange_AttributeSetter"/>
+  <int value="3389" label="OBSOLETE_V8Window_IsMultiScreen_Method"/>
+  <int value="3390" label="OBSOLETE_V8Window_Onscreenschange_AttributeGetter"/>
+  <int value="3391" label="OBSOLETE_V8Window_Onscreenschange_AttributeSetter"/>
   <int value="3392" label="DOMWindowOpenPositioningFeaturesCrossScreen"/>
   <int value="3393" label="DOMWindowSetWindowRectCrossScreen"/>
   <int value="3394" label="FullscreenCrossScreen"/>
@@ -48769,6 +48776,7 @@
   <int value="-28295905" label="AutofillEnableAccountWalletStorage:enabled"/>
   <int value="-27287076" label="DesktopPWAsTabStripSettings:disabled"/>
   <int value="-27213807" label="GlobalMediaControls:enabled"/>
+  <int value="-25025176" label="PerformantSplitViewResizing:enabled"/>
   <int value="-24570936" label="DestroyProfileOnBrowserClose:disabled"/>
   <int value="-24217468" label="QuickAnswersTextAnnotator:enabled"/>
   <int value="-23804418"
@@ -49394,6 +49402,7 @@
   <int value="484581911" label="ServiceWorkerSubresourceFilter:disabled"/>
   <int value="484596410" label="EnterpriseRealtimeExtensionRequest:disabled"/>
   <int value="485957747" label="finch-seed-ignore-pending-download"/>
+  <int value="487605950" label="PerformantSplitViewResizing:disabled"/>
   <int value="487810392" label="EnablePalmOnToolTypePalm:enabled"/>
   <int value="491258649" label="UseFirstPartySet"/>
   <int value="491334698" label="ConditionalTabStripAndroid:enabled"/>
@@ -62119,8 +62128,10 @@
   <int value="0" label="Feature Disabled"/>
   <int value="1" label="Disallowed"/>
   <int value="2" label="First Contentful Paint"/>
-  <int value="3" label="Timeout"/>
+  <int value="3" label="FCP Timeout"/>
   <int value="4" label="Not Deferred"/>
+  <int value="5" label="Document Transition"/>
+  <int value="6" label="Document Transition Timeout"/>
 </enum>
 
 <enum name="PaintHoldingInputTiming">
@@ -62404,6 +62415,7 @@
   <int value="0" label="Password Settings"/>
   <int value="1" label="Safety Check"/>
   <int value="2" label="Password Breach Dialog"/>
+  <int value="3" label="PhishGuard Dialog"/>
 </enum>
 
 <enum name="PasswordCheckResolutionAction">
@@ -74936,6 +74948,9 @@
 </enum>
 
 <enum name="SigninReauthStates">
+  <obsolete>
+    Removed 2021-07.
+  </obsolete>
   <int value="0" label="Account mismatch"/>
   <int value="1" label="Reauth Shown"/>
 </enum>
diff --git a/tools/metrics/histograms/histograms_xml/bluetooth/histograms.xml b/tools/metrics/histograms/histograms_xml/bluetooth/histograms.xml
index 52cdb21..84e0ff13e 100644
--- a/tools/metrics/histograms/histograms_xml/bluetooth/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/bluetooth/histograms.xml
@@ -162,6 +162,17 @@
   </summary>
 </histogram>
 
+<histogram name="Bluetooth.ChromeOS.PoweredState" enum="BooleanEnabled"
+    expires_after="2022-07-01">
+  <owner>khorimoto@chromium.org</owner>
+  <owner>cros-connectivity@google.com</owner>
+  <summary>
+    Metric emitted when the user logs in on a device which supports Bluetooth as
+    well as when the Bluetooth adapter powered state changes (i.e., from off to
+    on or vice versa).
+  </summary>
+</histogram>
+
 <histogram
     name="Bluetooth.ChromeOS.UserInitiatedReconnectionAttempt.Result.FailureReason{BluetoothUISurfaces}"
     enum="BluetoothConnectionFailureReason" expires_after="2022-03-05">
diff --git a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
index a6366ad..621160a 100644
--- a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
+++ b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
@@ -3798,6 +3798,9 @@
 </histogram_suffixes>
 
 <histogram_suffixes name="CrosNotificationActions" separator=".">
+  <suffix name="CountOfNotificationShownInFirstMinutePerUser"
+      label="Count of notifications displayed in the first minute since login
+             for a user"/>
   <suffix name="NotificationAdded"
       label="A notification was created (regardless if it was shown or not)"/>
   <suffix name="Popup.ClickedActionButton"
diff --git a/tools/metrics/histograms/histograms_xml/optimization/histograms.xml b/tools/metrics/histograms/histograms_xml/optimization/histograms.xml
index 9bad8dff..fabf2358 100644
--- a/tools/metrics/histograms/histograms_xml/optimization/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/optimization/histograms.xml
@@ -447,7 +447,7 @@
 
 <histogram
     name="OptimizationGuide.PageContentAnnotationsService.ContentAnnotated"
-    units="BooleanAnnotated" expires_after="M94">
+    enum="BooleanAnnotated" expires_after="M94">
   <owner>sophiechang@chromium.org</owner>
   <owner>mcrouse@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/power/histograms.xml b/tools/metrics/histograms/histograms_xml/power/histograms.xml
index b471cef..bf0da9d2 100644
--- a/tools/metrics/histograms/histograms_xml/power/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/power/histograms.xml
@@ -28,8 +28,33 @@
 -->
 
   <variant name="" summary="Any scenario."/>
-  <variant name=".ZeroWindow"
-      summary="When chromium has no windows at all (ex: docked on macOS)"/>
+  <variant name=".AllTabsHidden" summary="Chrome had tabs, but none visible"/>
+  <variant name=".Audio"
+      summary="Chrome had at least 1 visible tab and was audible, but there
+               was no video playback or video capture"/>
+  <variant name=".EmbeddedVideo_NoNavigation"
+      summary="Chrome played a video in a visible tab, and there was no
+               navigation or video capture"/>
+  <variant name=".EmbeddedVideo_WithNavigation"
+      summary="Chrome played a video in a visible tab, there was a
+               navigation, but no video capture"/>
+  <variant name=".FullscreenVideo"
+      summary="Chrome played a video in fullscreen, and there was no video
+               capture"/>
+  <variant name=".Interaction"
+      summary="Chrome had at least 1 visible tab and received a user
+               interaction, but no navigation, audio, video playback or video
+               capture"/>
+  <variant name=".Navigation"
+      summary="Chrome had at least 1 visible tab and a navigation, but no
+               audio, video playback or video capture"/>
+  <variant name=".Passive"
+      summary="Chrome had at least 1 visible tab, but there was no user
+               interaction, navigation, audio, video playback or video
+               capture"/>
+  <variant name=".VideoCapture"
+      summary="Chrome had at least 1 visible tab and captured video"/>
+  <variant name=".ZeroWindow" summary="Chrome had no window"/>
 </variants>
 
 <histogram name="Power.ApproxCpuTimeSecondsPerCoreTypeAndFrequency"
diff --git a/tools/metrics/histograms/histograms_xml/signin/histograms.xml b/tools/metrics/histograms/histograms_xml/signin/histograms.xml
index 9dac3f02..d56af8d 100644
--- a/tools/metrics/histograms/histograms_xml/signin/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/signin/histograms.xml
@@ -881,6 +881,9 @@
 </histogram>
 
 <histogram name="Signin.Reauth" enum="SigninReauthStates" expires_after="M77">
+  <obsolete>
+    Removed 2021-07.
+  </obsolete>
   <owner>noms@chromium.org</owner>
   <summary>Tracks events related to the reauthentication Gaia page.</summary>
 </histogram>
diff --git a/tools/metrics/histograms/histograms_xml/simple/histograms.xml b/tools/metrics/histograms/histograms_xml/simple/histograms.xml
index 4e0cdc84..8195107 100644
--- a/tools/metrics/histograms/histograms_xml/simple/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/simple/histograms.xml
@@ -32,6 +32,9 @@
 
 <histogram base="true" name="SimpleCache.CheckCRCResult" enum="CheckCRCResult"
     expires_after="2021-07-01">
+  <obsolete>
+    Removed in July 2021.
+  </obsolete>
   <owner>morlovich@chromium.org</owner>
   <owner>wanderview@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/tab/histograms.xml b/tools/metrics/histograms/histograms_xml/tab/histograms.xml
index 524ac7e..5aa5b0f 100644
--- a/tools/metrics/histograms/histograms_xml/tab/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/tab/histograms.xml
@@ -1437,8 +1437,9 @@
   </summary>
 </histogram>
 
-<histogram name="Tabs.CountAtResume" units="tabs" expires_after="M92">
+<histogram name="Tabs.CountAtResume" units="tabs" expires_after="2021-12-12">
   <owner>marq@chromium.org</owner>
+  <owner>olivierrobin@chromium.org</owner>
   <summary>
     [iOS] The number of tabs open when the app comes out of the background.
   </summary>
diff --git a/tools/metrics/histograms/histograms_xml/translate/histograms.xml b/tools/metrics/histograms/histograms_xml/translate/histograms.xml
index a5a306d..6060cd9 100644
--- a/tools/metrics/histograms/histograms_xml/translate/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/translate/histograms.xml
@@ -1044,7 +1044,7 @@
 </histogram>
 
 <histogram name="Translate.TranslateTabIntentResult"
-    enum="TranslateTabIntentResult" expires_after="M91">
+    enum="TranslateTabIntentResult" expires_after="2022-06-12">
   <owner>jds@chromium.org</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 1d4d9ad..4e33ee9 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -11232,6 +11232,13 @@
       </history>
     </aggregation>
   </metric>
+  <metric name="InteractiveTiming.FirstScrollTimestamp">
+    <summary>
+      The duration between navigation start and the timestamp of the first
+      scroll per navigation. In ms. This is rounded down to the nearest
+      exponential bucket.
+    </summary>
+  </metric>
   <metric name="InteractiveTiming.LongestInputDelay">
     <obsolete>
       Deprecated on January 2019 in favor of
diff --git a/tools/perf/BUILD.gn b/tools/perf/BUILD.gn
index 344de9f..7f8fc6a 100644
--- a/tools/perf/BUILD.gn
+++ b/tools/perf/BUILD.gn
@@ -2,15 +2,15 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-group("perf") {
-  testonly = true
-  data_deps = [
-    ":perf_without_chrome",
-    "//tools/perf/chrome_telemetry_build:telemetry_chrome_test",
-  ]
-}
-
-if (is_android) {
+if (!is_android) {
+  group("perf") {
+    testonly = true
+    data_deps = [
+      ":perf_without_chrome",
+      "//tools/perf/chrome_telemetry_build:telemetry_chrome_test",
+    ]
+  }
+} else {
   template("perf_android_template") {
     forward_variables_from(invoker, [ "telemetry_target_suffix" ])
     group(target_name) {
diff --git a/tools/perf/benchmarks/v8_helper.py b/tools/perf/benchmarks/v8_helper.py
index ab16780a..be24190d 100644
--- a/tools/perf/benchmarks/v8_helper.py
+++ b/tools/perf/benchmarks/v8_helper.py
@@ -2,27 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-from devil.android import device_errors  # pylint: disable=import-error
-from devil.android import device_utils  # pylint: disable=import-error
 from telemetry.web_perf import timeline_based_measurement
 from telemetry.timeline import chrome_trace_config
 
 _JS_FLAGS_SWITCH = '--js-flags='
-LOW_END_DEVICE_MEMORY_KB = 1024 * 1024  # 1 GB
-
-
-def GetDeviceTotalMemory():
-  devices = device_utils.DeviceUtils.HealthyDevices()
-  if not devices:
-    return None
-  try:
-    mem_info = devices[0].ReadFile('/proc/meminfo')
-  except device_errors.AdbShellCommandFailedError:
-    return None
-  for line in mem_info.splitlines():
-    if line.startswith('MemTotal:'):
-      return int(line.split()[1])
-
 
 def AppendJSFlags(options, js_flags):
   existing_js_flags = ''
@@ -75,13 +58,7 @@
   memory_dump_config.AddTrigger('light', 1000)
   options.config.chrome_trace_config.SetMemoryDumpConfig(memory_dump_config)
 
-  # On low-end devices there's not enough memory to hold 400Mb buffer (See
-  # crbug.com/1218139).
-  device_memory = GetDeviceTotalMemory()
-  if device_memory and device_memory < LOW_END_DEVICE_MEMORY_KB:
-    options.config.chrome_trace_config.SetTraceBufferSizeInKb(200 * 1024)
-  else:
-    options.config.chrome_trace_config.SetTraceBufferSizeInKb(400 * 1024)
+  options.config.chrome_trace_config.SetTraceBufferSizeInKb(400 * 1024)
 
   metrics = [
       'blinkGcMetric',
diff --git a/tools/perf/chrome_telemetry_build/BUILD.gn b/tools/perf/chrome_telemetry_build/BUILD.gn
index 902b24d..6fdf9ba 100644
--- a/tools/perf/chrome_telemetry_build/BUILD.gn
+++ b/tools/perf/chrome_telemetry_build/BUILD.gn
@@ -36,25 +36,7 @@
   ]
   data = []
 
-  if (is_android) {
-    # TODO(crbug.com/1213269): Remove these APK dependencies and fully switch to
-    # the separate Android targets below once all Android uses of the old target
-    # have been cleaned up.
-    data_deps += [
-      ":telemetry_weblayer_apks",
-      "//android_webview:system_webview_apk",
-      "//android_webview/test:webview_instrumentation_apk",
-      "//android_webview/tools/system_webview_shell:system_webview_shell_apk",
-      "//chrome/android:chrome_public_apk",
-      "//chrome/android:monochrome_public_apk",
-      "//chrome/android:monochrome_public_bundle",
-      "//chrome/android/webapk/shell_apk:maps_go_webapk",
-    ]
-
-    if (enable_chrome_android_internal) {
-      data_deps += [ "//clank:telemetry_clank_test" ]
-    }
-  } else if (!is_fuchsia) {
+  if (!is_fuchsia && !is_android) {
     data_deps += [ "//chrome" ]
   }
 
diff --git a/tools/perf/contrib/vr_benchmarks/BUILD.gn b/tools/perf/contrib/vr_benchmarks/BUILD.gn
index 9521351..06b53cf 100644
--- a/tools/perf/contrib/vr_benchmarks/BUILD.gn
+++ b/tools/perf/contrib/vr_benchmarks/BUILD.gn
@@ -50,15 +50,15 @@
   }
 }
 
-group("vr_perf_tests") {
-  testonly = true
-  data_deps = [
-    ":vr_perf_tests_base",
-    "//tools/perf:perf",
-  ]
-}
-
-if (is_android) {
+if (!is_android) {
+  group("vr_perf_tests") {
+    testonly = true
+    data_deps = [
+      ":vr_perf_tests_base",
+      "//tools/perf:perf",
+    ]
+  }
+} else {
   template("vr_perf_tests_android_template") {
     forward_variables_from(invoker, [ "telemetry_target_suffix" ])
     group(target_name) {
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index d9a486844..aa4a98fa 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,12 +5,12 @@
             "remote_path": "perfetto_binaries/trace_processor_shell/win/bbc615953ec6e431f158546c282b4f8b857937b8/trace_processor_shell.exe"
         },
         "mac": {
-            "hash": "a62641d093e3c5b3831792002c1115e1091873f4",
-            "remote_path": "perfetto_binaries/trace_processor_shell/mac/97facadd961825cf2b6eb12398e0908a102d0c4a/trace_processor_shell"
+            "hash": "95672997dc2f93b5cac365d6ad3dacbf97f49176",
+            "remote_path": "perfetto_binaries/trace_processor_shell/mac/bbc615953ec6e431f158546c282b4f8b857937b8/trace_processor_shell"
         },
         "linux": {
-            "hash": "c195fdc1f83e98b2ed5b6ce67a1e5b1f1bcc0082",
-            "remote_path": "perfetto_binaries/trace_processor_shell/linux/97facadd961825cf2b6eb12398e0908a102d0c4a/trace_processor_shell"
+            "hash": "3fe7fcf25c3135f13ef06bc8e59827e368dcacf1",
+            "remote_path": "perfetto_binaries/trace_processor_shell/linux/bbc615953ec6e431f158546c282b4f8b857937b8/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/typescript/ts_library.gni b/tools/typescript/ts_library.gni
index e29fb803..84fc32c 100644
--- a/tools/typescript/ts_library.gni
+++ b/tools/typescript/ts_library.gni
@@ -17,10 +17,7 @@
                            ])
 
     inputs = [ "//tools/typescript/tsconfig_base.json" ]
-    outputs = [
-      "$target_gen_dir/tsconfig.json",
-      "$target_gen_dir/tsconfig.tsbuildinfo",
-    ]
+    outputs = [ "$target_gen_dir/tsconfig.json" ]
 
     assert(defined(in_files) || defined(invoker.definitions))
 
@@ -39,6 +36,10 @@
       composite = invoker.composite
     }
 
+    if (composite) {
+      outputs += [ "$target_gen_dir/tsconfig.tsbuildinfo" ]
+    }
+
     if (defined(in_files)) {
       outputs += [ "$target_gen_dir/tsconfig.manifest" ]
       foreach(_source, in_files) {
diff --git a/tools/typescript/ts_library.py b/tools/typescript/ts_library.py
index f4069cf..a05d279 100644
--- a/tools/typescript/ts_library.py
+++ b/tools/typescript/ts_library.py
@@ -51,13 +51,13 @@
       else os.path.relpath(TSCONFIG_BASE_PATH, args.gen_dir)
 
   tsconfig['compilerOptions'] = collections.OrderedDict()
-  tsconfig['compilerOptions']['tsBuildInfoFile'] = 'tsconfig.tsbuildinfo'
   tsconfig['compilerOptions']['rootDir'] = root_dir
   tsconfig['compilerOptions']['outDir'] = out_dir
 
   if args.composite:
     tsconfig['compilerOptions']['composite'] = True
     tsconfig['compilerOptions']['declaration'] = True
+    tsconfig['compilerOptions']['tsBuildInfoFile'] = 'tsconfig.tsbuildinfo'
 
   tsconfig['files'] = []
   if args.in_files is not None:
diff --git a/tools/typescript/ts_library_test.py b/tools/typescript/ts_library_test.py
index c564c4b..65dc09fd 100755
--- a/tools/typescript/ts_library_test.py
+++ b/tools/typescript/ts_library_test.py
@@ -98,13 +98,16 @@
         'bar.js',
         'tsconfig.json',
         'tsconfig.manifest',
-        'tsconfig.tsbuildinfo',
     ]
     for f in files:
       self.assertTrue(os.path.exists(os.path.join(gen_dir, f)), f)
 
-    dts_file = 'bar.d.ts'
-    self.assertFalse(os.path.exists(os.path.join(gen_dir, dts_file)), dts_file)
+    non_existing_files = [
+        'bar.d.ts',
+        'tsconfig.tsbuildinfo',
+    ]
+    for f in non_existing_files:
+      self.assertFalse(os.path.exists(os.path.join(gen_dir, f)), f)
 
   # Builds project3, which includes only definition files.
   def _build_project3(self):
diff --git a/tools/typescript/tsconfig_base.json b/tools/typescript/tsconfig_base.json
index cba0a73..17bb7cb 100644
--- a/tools/typescript/tsconfig_base.json
+++ b/tools/typescript/tsconfig_base.json
@@ -6,8 +6,6 @@
     "noEmitOnError": true,
     "pretty": true,
 
-    "incremental": true,
-
     "forceConsistentCasingInFileNames": true,
     "noFallthroughCasesInSwitch": true,
     "noImplicitReturns": true,
diff --git a/ui/base/class_property.h b/ui/base/class_property.h
index a4be5fb..f7b2f55 100644
--- a/ui/base/class_property.h
+++ b/ui/base/class_property.h
@@ -9,6 +9,7 @@
 
 #include <map>
 #include <set>
+#include <type_traits>
 
 #include "base/component_export.h"
 #include "base/time/time.h"
@@ -95,7 +96,7 @@
   // freed when they are overwritten or cleared).  NOTE: This should NOT be
   // for passing a raw pointer for owned properties. Prefer the std::unique_ptr
   // version below.
-  template<typename T>
+  template <typename T>
   void SetProperty(const ClassProperty<T>* property, T value);
 
   // Sets the |value| of the given class |property|, which must be an owned
@@ -197,9 +198,10 @@
 
 class COMPONENT_EXPORT(UI_BASE) PropertyHelper {
  public:
-  template<typename T>
+  template <typename T>
   static void Set(::ui::PropertyHandler* handler,
-                  const ::ui::ClassProperty<T>* property, T value) {
+                  const ::ui::ClassProperty<T>* property,
+                  T value) {
     int64_t old = handler->SetPropertyInternal(
         property, property->name,
         value == property->default_value ? nullptr : property->deallocator,
@@ -218,10 +220,10 @@
         property, ClassPropertyCaster<T>::ToInt64(property->default_value),
         property->cascading && allow_cascade));
   }
-  template<typename T>
+  template <typename T>
   static void Clear(::ui::PropertyHandler* handler,
                     const ::ui::ClassProperty<T>* property) {
-    handler->SetProperty(property, property->default_value);
+    Set(handler, property, property->default_value);
   }
 };
 
@@ -293,6 +295,11 @@
   template <>                                                                \
   EXPORT void PropertyHandler::SetProperty(const ClassProperty<T>* property, \
                                            T value) {                        \
+    /* TODO(kylixrd, pbos): Once all the call-sites are fixed to only use */ \
+    /* the unique_ptr version for owned properties, add the following */     \
+    /* DCHECK to guard against passing raw pointers for owned properties. */ \
+    /* DCHECK(!std::is_pointer<T>::value || */                               \
+    /*        (std::is_pointer<T>::value && !property->deallocator)); */     \
     subtle::PropertyHelper::Set<T>(this, property, value);                   \
   }                                                                          \
   template <>                                                                \
diff --git a/ui/base/class_property_unittest.cc b/ui/base/class_property_unittest.cc
index ffa0dbc..9950076 100644
--- a/ui/base/class_property_unittest.cc
+++ b/ui/base/class_property_unittest.cc
@@ -309,11 +309,11 @@
   EXPECT_EQ(4, h.num_events());
 
   // Verify that setting a heap-allocated value also ticks the event counter.
-  h.SetProperty(kAssignableKey, new AssignableTestProperty{4});
+  h.SetProperty(kAssignableKey, std::make_unique<AssignableTestProperty>(4));
   EXPECT_EQ(5, h.num_events());
 
   // Verify that overwriting a heap-allocated value ticks the event counter.
-  h.SetProperty(kAssignableKey, new AssignableTestProperty{5});
+  h.SetProperty(kAssignableKey, std::make_unique<AssignableTestProperty>(5));
   EXPECT_EQ(6, h.num_events());
 }
 
@@ -333,5 +333,18 @@
   EXPECT_EQ(&h, value->handler());
 }
 
+// TODO(kylixrd, pbos): Once all the call-sites are fixed to only use the
+// unique_ptr version for owned properties, enable the following test to ensure
+// that passing raw pointers for owned properties will, in fact, DCHECK.
+TEST(PropertyTest, DISABLED_CheckedOwnedProperties) {
+  PropertyHandler h;
+
+  EXPECT_EQ(nullptr, h.GetProperty(kOwnedKey));
+  // The following SetProperty call should DCHECK if it's enabled. NOTE: This
+  // will leak the TestProperty!
+  EXPECT_DEATH_IF_SUPPORTED(h.SetProperty(kOwnedKey, new TestProperty()), "");
+  EXPECT_EQ(nullptr, h.GetProperty(kOwnedKey));
+}
+
 } // namespace test
 } // namespace ui
diff --git a/ui/base/clipboard/OWNERS b/ui/base/clipboard/OWNERS
index b9f041b..7287c885 100644
--- a/ui/base/clipboard/OWNERS
+++ b/ui/base/clipboard/OWNERS
@@ -1,5 +1,5 @@
+asully@chromium.org
 dcheng@chromium.org
-huangdarwin@chromium.org
 
 per-file clipboard_*android*=gangwu@chromium.org
 per-file clipboard_*ozone*=msisov@igalia.com
diff --git a/ui/base/dragdrop/OWNERS b/ui/base/dragdrop/OWNERS
index 7baa107..859c2c6 100644
--- a/ui/base/dragdrop/OWNERS
+++ b/ui/base/dragdrop/OWNERS
@@ -1,5 +1 @@
-# Primary:
-huangdarwin@chromium.org
-
-# Secondary:
 dcheng@chromium.org
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h
index 3c226fe..dfb0c89 100644
--- a/ui/compositor/compositor.h
+++ b/ui/compositor/compositor.h
@@ -25,6 +25,7 @@
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_host_client.h"
 #include "cc/trees/layer_tree_host_single_thread_client.h"
+#include "cc/trees/paint_holding_reason.h"
 #include "components/viz/common/frame_sinks/begin_frame_args.h"
 #include "components/viz/common/surfaces/frame_sink_id.h"
 #include "components/viz/common/surfaces/subtree_capture_id.h"
@@ -321,7 +322,7 @@
   void WillBeginMainFrame() override {}
   void DidBeginMainFrame() override {}
   void OnDeferMainFrameUpdatesChanged(bool) override {}
-  void OnDeferCommitsChanged(bool) override {}
+  void OnDeferCommitsChanged(bool, cc::PaintHoldingReason) override {}
   void WillUpdateLayers() override {}
   void DidUpdateLayers() override;
   void BeginMainFrame(const viz::BeginFrameArgs& args) override;
diff --git a/ui/events/chromecast/scroller_unittest.cc b/ui/events/chromecast/scroller_unittest.cc
index d955f318..1ffbd21 100644
--- a/ui/events/chromecast/scroller_unittest.cc
+++ b/ui/events/chromecast/scroller_unittest.cc
@@ -103,15 +103,9 @@
   base::TimeTicks start_time = base::TimeTicks::Now();
 
   // Start a fling and verify initialized values.
-  scroller.Fling(kDefaultStartX,
-                 kDefaultStartY,
-                 kDefaultVelocityX,
-                 kDefaultVelocityY,
-                 INT_MIN,
-                 INT_MAX,
-                 INT_MIN,
-                 INT_MAX,
-                 start_time);
+  scroller.Fling(kDefaultStartX, kDefaultStartY, kDefaultVelocityX,
+                 kDefaultVelocityY, INT_MIN, static_cast<float>(INT_MAX),
+                 INT_MIN, static_cast<float>(INT_MAX), start_time);
 
   EXPECT_EQ(kDefaultStartX, scroller.GetStartX());
   EXPECT_EQ(kDefaultStartY, scroller.GetStartY());
diff --git a/ui/views/widget/widget_interactive_uitest.cc b/ui/views/widget/widget_interactive_uitest.cc
index 1d4cc67..7c91221 100644
--- a/ui/views/widget/widget_interactive_uitest.cc
+++ b/ui/views/widget/widget_interactive_uitest.cc
@@ -533,7 +533,13 @@
 }
 
 // Test z-order of child widgets relative to their parent.
-TEST_F(WidgetTestInteractive, ChildStackedRelativeToParent) {
+// TODO(crbug.com/1227009): Disabled on Mac due to flake
+#if defined(OS_MAC)
+#define MAYBE_ChildStackedRelativeToParent DISABLED_ChildStackedRelativeToParent
+#else
+#define MAYBE_ChildStackedRelativeToParent ChildStackedRelativeToParent
+#endif
+TEST_F(WidgetTestInteractive, MAYBE_ChildStackedRelativeToParent) {
   WidgetAutoclosePtr parent(CreateTopLevelPlatformWidget());
   Widget* child = CreateChildPlatformWidget(parent->GetNativeView());